summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java4
-rw-r--r--core/api/current.txt72
-rw-r--r--core/java/android/app/Activity.java6
-rw-r--r--core/java/android/app/AppCompatTaskInfo.java29
-rw-r--r--core/java/android/app/Notification.java69
-rw-r--r--core/java/android/app/NotificationManager.java10
-rw-r--r--core/java/android/app/SystemServiceRegistry.java9
-rw-r--r--core/java/android/app/jank/AppJankStats.java126
-rw-r--r--core/java/android/app/jank/FrameOverrunHistogram.java107
-rw-r--r--core/java/android/app/jank/JankDataProcessor.java9
-rw-r--r--core/java/android/app/jank/RelativeFrameTimeHistogram.java129
-rw-r--r--core/java/android/hardware/contexthub/HubServiceInfo.java4
-rw-r--r--core/java/android/hardware/display/DisplayTopology.java33
-rw-r--r--core/java/android/hardware/location/ContextHubManager.java14
-rw-r--r--core/java/android/provider/Settings.java16
-rw-r--r--core/java/android/service/settings/preferences/GetValueRequest.java1
-rw-r--r--core/java/android/service/settings/preferences/GetValueResult.java1
-rw-r--r--core/java/android/service/settings/preferences/MetadataRequest.java1
-rw-r--r--core/java/android/service/settings/preferences/MetadataResult.java1
-rw-r--r--core/java/android/service/settings/preferences/SetValueRequest.java1
-rw-r--r--core/java/android/service/settings/preferences/SetValueResult.java1
-rw-r--r--core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java20
-rw-r--r--core/java/android/service/settings/preferences/SettingsPreferenceValue.java1
-rw-r--r--core/java/android/tracing/flags.aconfig8
-rw-r--r--core/java/android/view/Surface.java9
-rw-r--r--core/java/android/view/View.java4
-rw-r--r--core/java/android/view/ViewRootImpl.java6
-rw-r--r--core/java/android/view/contentcapture/flags/content_capture_flags.aconfig2
-rw-r--r--core/java/android/window/WindowTokenClientController.java3
-rw-r--r--core/java/android/window/flags/large_screen_experiences_app_compat.aconfig7
-rw-r--r--core/java/android/window/flags/windowing_sdk.aconfig10
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java44
-rw-r--r--core/jni/Android.bp13
-rw-r--r--core/jni/platform/darwin/libandroid_runtime_export.exp38
-rw-r--r--core/jni/platform/linux/libandroid_runtime_export.txt43
-rw-r--r--core/res/res/values-watch/config.xml3
-rw-r--r--core/tests/coretests/src/android/app/NotificationTest.java208
-rw-r--r--core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt86
-rw-r--r--core/tests/coretests/src/android/view/ViewRootImplTest.java12
-rw-r--r--core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java162
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt28
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java16
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt33
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java20
-rw-r--r--media/java/android/media/MediaRoute2ProviderService.java66
-rw-r--r--packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java47
-rw-r--r--packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java47
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java37
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupRestoreKeys.java61
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java28
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java41
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java4
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupRestoreKeysTest.java58
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/UpgradeControllerTest.java175
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt13
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt7
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt10
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt26
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt56
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java1
-rw-r--r--packages/SystemUI/res/drawable/audio_bars_idle.xml56
-rw-r--r--packages/SystemUI/res/layout/volume_dialog.xml2
-rw-r--r--packages/SystemUI/res/raw/audio_bars_in.json1
-rw-r--r--packages/SystemUI/res/raw/audio_bars_out.json1
-rw-r--r--packages/SystemUI/res/raw/audio_bars_playing.json1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt225
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/lottie/LottieTaskExt.kt49
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/NotificationScrimClip.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt197
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java7
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt1
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java3
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java1
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java4
-rw-r--r--services/core/java/com/android/server/display/DisplayTopologyCoordinator.java17
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2Provider.java25
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java21
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java40
-rw-r--r--services/core/java/com/android/server/media/SystemMediaRoute2Provider.java15
-rw-r--r--services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java110
-rw-r--r--services/core/java/com/android/server/power/Notifier.java27
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java5
-rw-r--r--services/core/java/com/android/server/wm/AppCompatUtils.java7
-rw-r--r--services/core/java/com/android/server/wm/AsyncRotationController.java8
-rw-r--r--services/core/java/com/android/server/wm/FadeAnimationController.java26
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java3
-rw-r--r--services/java/com/android/server/SystemServer.java7
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt41
-rw-r--r--services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java27
-rw-r--r--tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java3
-rw-r--r--tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java3
-rw-r--r--tests/AppJankTest/src/android/app/jank/tests/JankUtils.java18
-rw-r--r--tests/AppJankTest/src/android/app/jank/tests/TestWidget.java8
-rw-r--r--tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java2
-rw-r--r--tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java3
119 files changed, 2411 insertions, 981 deletions
diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
index c77528021201..ed669beae1ce 100644
--- a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
@@ -63,12 +63,14 @@ public class ZipFilePerfTest {
@Test
@Parameters(method = "getData")
- public void timeZipFileOpenClose(int numEntries) throws Exception {
+ public void timeZipFileOpen(int numEntries) throws Exception {
setUp(numEntries);
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
ZipFile zf = new ZipFile(mFile);
+ state.pauseTiming();
zf.close();
+ state.resumeTiming();
}
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 1b494c51a1f4..7c56a5811abb 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9190,37 +9190,37 @@ package android.app.blob {
package android.app.jank {
@FlaggedApi("android.app.jank.detailed_app_jank_metrics_api") public final class AppJankStats {
- ctor public AppJankStats(int, @NonNull String, @Nullable String, @Nullable String, long, long, @NonNull android.app.jank.FrameOverrunHistogram);
- method @NonNull public android.app.jank.FrameOverrunHistogram getFrameOverrunHistogram();
+ ctor public AppJankStats(int, @NonNull String, @Nullable String, @Nullable String, long, long, @NonNull android.app.jank.RelativeFrameTimeHistogram);
method public long getJankyFrameCount();
+ method @NonNull public android.app.jank.RelativeFrameTimeHistogram getRelativeFrameTimeHistogram();
method public long getTotalFrameCount();
method public int getUid();
method @NonNull public String getWidgetCategory();
method @NonNull public String getWidgetId();
method @NonNull public String getWidgetState();
- field public static final String ANIMATING = "animating";
- field public static final String ANIMATION = "animation";
- field public static final String DRAGGING = "dragging";
- field public static final String FLINGING = "flinging";
- field public static final String KEYBOARD = "keyboard";
- field public static final String MEDIA = "media";
- field public static final String NAVIGATION = "navigation";
- field public static final String NONE = "none";
- field public static final String OTHER = "other";
- field public static final String PLAYBACK = "playback";
- field public static final String PREDICTIVE_BACK = "predictive_back";
- field public static final String SCROLL = "scroll";
- field public static final String SCROLLING = "scrolling";
- field public static final String SWIPING = "swiping";
- field public static final String TAPPING = "tapping";
- field public static final String WIDGET_CATEGORY_UNSPECIFIED = "widget_category_unspecified";
- field public static final String WIDGET_STATE_UNSPECIFIED = "widget_state_unspecified";
- field public static final String ZOOMING = "zooming";
- }
-
- @FlaggedApi("android.app.jank.detailed_app_jank_metrics_api") public class FrameOverrunHistogram {
- ctor public FrameOverrunHistogram();
- method public void addFrameOverrunMillis(int);
+ field public static final String WIDGET_CATEGORY_ANIMATION = "animation";
+ field public static final String WIDGET_CATEGORY_KEYBOARD = "keyboard";
+ field public static final String WIDGET_CATEGORY_MEDIA = "media";
+ field public static final String WIDGET_CATEGORY_NAVIGATION = "navigation";
+ field public static final String WIDGET_CATEGORY_OTHER = "other";
+ field public static final String WIDGET_CATEGORY_SCROLL = "scroll";
+ field public static final String WIDGET_CATEGORY_UNSPECIFIED = "unspecified";
+ field public static final String WIDGET_STATE_ANIMATING = "animating";
+ field public static final String WIDGET_STATE_DRAGGING = "dragging";
+ field public static final String WIDGET_STATE_FLINGING = "flinging";
+ field public static final String WIDGET_STATE_NONE = "none";
+ field public static final String WIDGET_STATE_PLAYBACK = "playback";
+ field public static final String WIDGET_STATE_PREDICTIVE_BACK = "predictive_back";
+ field public static final String WIDGET_STATE_SCROLLING = "scrolling";
+ field public static final String WIDGET_STATE_SWIPING = "swiping";
+ field public static final String WIDGET_STATE_TAPPING = "tapping";
+ field public static final String WIDGET_STATE_UNSPECIFIED = "unspecified";
+ field public static final String WIDGET_STATE_ZOOMING = "zooming";
+ }
+
+ @FlaggedApi("android.app.jank.detailed_app_jank_metrics_api") public class RelativeFrameTimeHistogram {
+ ctor public RelativeFrameTimeHistogram();
+ method public void addRelativeFrameTimeMillis(int);
method @NonNull public int[] getBucketCounters();
method @NonNull public int[] getBucketEndpointsMillis();
}
@@ -42521,7 +42521,7 @@ package android.service.settings.preferences {
field @NonNull public static final android.os.Parcelable.Creator<android.service.settings.preferences.GetValueRequest> CREATOR;
}
- public static final class GetValueRequest.Builder {
+ @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class GetValueRequest.Builder {
ctor public GetValueRequest.Builder(@NonNull String, @NonNull String);
method @NonNull public android.service.settings.preferences.GetValueRequest build();
}
@@ -42542,7 +42542,7 @@ package android.service.settings.preferences {
field public static final int RESULT_UNSUPPORTED = 1; // 0x1
}
- public static final class GetValueResult.Builder {
+ @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class GetValueResult.Builder {
ctor public GetValueResult.Builder(int);
method @NonNull public android.service.settings.preferences.GetValueResult build();
method @NonNull public android.service.settings.preferences.GetValueResult.Builder setMetadata(@Nullable android.service.settings.preferences.SettingsPreferenceMetadata);
@@ -42555,7 +42555,7 @@ package android.service.settings.preferences {
field @NonNull public static final android.os.Parcelable.Creator<android.service.settings.preferences.MetadataRequest> CREATOR;
}
- public static final class MetadataRequest.Builder {
+ @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class MetadataRequest.Builder {
ctor public MetadataRequest.Builder();
method @NonNull public android.service.settings.preferences.MetadataRequest build();
}
@@ -42571,7 +42571,7 @@ package android.service.settings.preferences {
field public static final int RESULT_UNSUPPORTED = 1; // 0x1
}
- public static final class MetadataResult.Builder {
+ @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class MetadataResult.Builder {
ctor public MetadataResult.Builder(int);
method @NonNull public android.service.settings.preferences.MetadataResult build();
method @NonNull public android.service.settings.preferences.MetadataResult.Builder setMetadataList(@NonNull java.util.List<android.service.settings.preferences.SettingsPreferenceMetadata>);
@@ -42586,7 +42586,7 @@ package android.service.settings.preferences {
field @NonNull public static final android.os.Parcelable.Creator<android.service.settings.preferences.SetValueRequest> CREATOR;
}
- public static final class SetValueRequest.Builder {
+ @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class SetValueRequest.Builder {
ctor public SetValueRequest.Builder(@NonNull String, @NonNull String, @NonNull android.service.settings.preferences.SettingsPreferenceValue);
method @NonNull public android.service.settings.preferences.SetValueRequest build();
}
@@ -42608,14 +42608,13 @@ package android.service.settings.preferences {
field public static final int RESULT_UNSUPPORTED = 1; // 0x1
}
- public static final class SetValueResult.Builder {
+ @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class SetValueResult.Builder {
ctor public SetValueResult.Builder(int);
method @NonNull public android.service.settings.preferences.SetValueResult build();
}
@FlaggedApi("com.android.settingslib.flags.settings_catalyst") public final class SettingsPreferenceMetadata implements android.os.Parcelable {
method public int describeContents();
- method @NonNull public java.util.List<java.lang.String> getBreadcrumbs();
method @NonNull public android.os.Bundle getExtras();
method @NonNull public String getKey();
method @Nullable public android.content.Intent getLaunchIntent();
@@ -42631,17 +42630,16 @@ package android.service.settings.preferences {
method public boolean isWritable();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.service.settings.preferences.SettingsPreferenceMetadata> CREATOR;
+ field public static final int DEEPLINK_ONLY = 2; // 0x2
field public static final int EXPECT_POST_CONFIRMATION = 1; // 0x1
- field public static final int EXPECT_PRE_CONFIRMATION = 2; // 0x2
field public static final int NO_DIRECT_ACCESS = 3; // 0x3
field public static final int NO_SENSITIVITY = 0; // 0x0
}
- public static final class SettingsPreferenceMetadata.Builder {
+ @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class SettingsPreferenceMetadata.Builder {
ctor public SettingsPreferenceMetadata.Builder(@NonNull String, @NonNull String);
method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata build();
method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setAvailable(boolean);
- method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setBreadcrumbs(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setEnabled(boolean);
method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setExtras(@NonNull android.os.Bundle);
method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setLaunchIntent(@Nullable android.content.Intent);
@@ -42688,7 +42686,7 @@ package android.service.settings.preferences {
field public static final int TYPE_STRING = 3; // 0x3
}
- public static final class SettingsPreferenceValue.Builder {
+ @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class SettingsPreferenceValue.Builder {
ctor public SettingsPreferenceValue.Builder(int);
method @NonNull public android.service.settings.preferences.SettingsPreferenceValue build();
method @NonNull public android.service.settings.preferences.SettingsPreferenceValue.Builder setBooleanValue(boolean);
@@ -53484,9 +53482,9 @@ package android.view {
field public static final int CHANGE_FRAME_RATE_ALWAYS = 1; // 0x1
field public static final int CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0; // 0x0
field @NonNull public static final android.os.Parcelable.Creator<android.view.Surface> CREATOR;
+ field @FlaggedApi("com.android.graphics.surfaceflinger.flags.arr_setframerate_gte_enum") public static final int FRAME_RATE_COMPATIBILITY_AT_LEAST = 2; // 0x2
field public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; // 0x0
field public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; // 0x1
- field @FlaggedApi("com.android.graphics.surfaceflinger.flags.arr_setframerate_gte_enum") public static final int FRAME_RATE_COMPATIBILITY_GTE = 2; // 0x2
field public static final int ROTATION_0 = 0; // 0x0
field public static final int ROTATION_180 = 2; // 0x2
field public static final int ROTATION_270 = 3; // 0x3
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index fee8cdb1ce51..c3ef104075f2 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5834,7 +5834,11 @@ public class Activity extends ContextThemeWrapper
final int size = permissions.length;
int[] results = new int[size];
for (int i = 0; i < size; i++) {
- results[i] = deviceContext.getPermissionRequestState(permissions[i]);
+ if (permissions[i] == null) {
+ results[i] = Context.PERMISSION_REQUEST_STATE_UNREQUESTABLE;
+ } else {
+ results[i] = deviceContext.getPermissionRequestState(permissions[i]);
+ }
}
return results;
}
diff --git a/core/java/android/app/AppCompatTaskInfo.java b/core/java/android/app/AppCompatTaskInfo.java
index 61b56877589b..599f1a8be233 100644
--- a/core/java/android/app/AppCompatTaskInfo.java
+++ b/core/java/android/app/AppCompatTaskInfo.java
@@ -27,6 +27,7 @@ import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
/**
* Stores App Compat information about a particular Task.
@@ -58,16 +59,11 @@ public class AppCompatTaskInfo implements Parcelable {
public int topActivityLetterboxHeight = PROPERTY_VALUE_UNSET;
/**
- * Contains the current app height of the letterboxed activity if available or
- * {@link TaskInfo#PROPERTY_VALUE_UNSET} otherwise.
+ * Contains the app bounds of the top activity or size compat mode
+ * bounds when in size compat mode. If null, contains bounds.
*/
- public int topActivityLetterboxAppHeight = PROPERTY_VALUE_UNSET;
-
- /**
- * Contains the current app width of the letterboxed activity if available or
- * {@link TaskInfo#PROPERTY_VALUE_UNSET} otherwise.
- */
- public int topActivityLetterboxAppWidth = PROPERTY_VALUE_UNSET;
+ @NonNull
+ public final Rect topActivityAppBounds = new Rect();
/**
* Contains the top activity bounds when the activity is letterboxed.
@@ -350,8 +346,7 @@ public class AppCompatTaskInfo implements Parcelable {
&& topActivityLetterboxVerticalPosition == that.topActivityLetterboxVerticalPosition
&& topActivityLetterboxWidth == that.topActivityLetterboxWidth
&& topActivityLetterboxHeight == that.topActivityLetterboxHeight
- && topActivityLetterboxAppWidth == that.topActivityLetterboxAppWidth
- && topActivityLetterboxAppHeight == that.topActivityLetterboxAppHeight
+ && topActivityAppBounds.equals(that.topActivityAppBounds)
&& topActivityLetterboxHorizontalPosition
== that.topActivityLetterboxHorizontalPosition
&& cameraCompatTaskInfo.equalsForTaskOrganizer(that.cameraCompatTaskInfo);
@@ -371,8 +366,7 @@ public class AppCompatTaskInfo implements Parcelable {
== that.topActivityLetterboxHorizontalPosition
&& topActivityLetterboxWidth == that.topActivityLetterboxWidth
&& topActivityLetterboxHeight == that.topActivityLetterboxHeight
- && topActivityLetterboxAppWidth == that.topActivityLetterboxAppWidth
- && topActivityLetterboxAppHeight == that.topActivityLetterboxAppHeight
+ && topActivityAppBounds.equals(that.topActivityAppBounds)
&& cameraCompatTaskInfo.equalsForCompatUi(that.cameraCompatTaskInfo);
}
@@ -385,8 +379,7 @@ public class AppCompatTaskInfo implements Parcelable {
topActivityLetterboxHorizontalPosition = source.readInt();
topActivityLetterboxWidth = source.readInt();
topActivityLetterboxHeight = source.readInt();
- topActivityLetterboxAppWidth = source.readInt();
- topActivityLetterboxAppHeight = source.readInt();
+ topActivityAppBounds.set(Objects.requireNonNull(source.readTypedObject(Rect.CREATOR)));
topActivityLetterboxBounds = source.readTypedObject(Rect.CREATOR);
cameraCompatTaskInfo = source.readTypedObject(CameraCompatTaskInfo.CREATOR);
}
@@ -401,8 +394,7 @@ public class AppCompatTaskInfo implements Parcelable {
dest.writeInt(topActivityLetterboxHorizontalPosition);
dest.writeInt(topActivityLetterboxWidth);
dest.writeInt(topActivityLetterboxHeight);
- dest.writeInt(topActivityLetterboxAppWidth);
- dest.writeInt(topActivityLetterboxAppHeight);
+ dest.writeTypedObject(topActivityAppBounds, flags);
dest.writeTypedObject(topActivityLetterboxBounds, flags);
dest.writeTypedObject(cameraCompatTaskInfo, flags);
}
@@ -421,8 +413,7 @@ public class AppCompatTaskInfo implements Parcelable {
+ topActivityLetterboxHorizontalPosition
+ " topActivityLetterboxWidth=" + topActivityLetterboxWidth
+ " topActivityLetterboxHeight=" + topActivityLetterboxHeight
- + " topActivityLetterboxAppWidth=" + topActivityLetterboxAppWidth
- + " topActivityLetterboxAppHeight=" + topActivityLetterboxAppHeight
+ + " topActivityAppBounds=" + topActivityAppBounds
+ " isUserFullscreenOverrideEnabled=" + isUserFullscreenOverrideEnabled()
+ " isSystemFullscreenOverrideEnabled=" + isSystemFullscreenOverrideEnabled()
+ " hasMinAspectRatioOverride=" + hasMinAspectRatioOverride()
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 17638ee76dba..eeb1ebb69b03 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -11208,8 +11208,8 @@ public class Notification implements Parcelable
private static final String KEY_SEGMENT_LENGTH = "length";
private static final String KEY_POINT_POSITION = "position";
- private static final int MAX_PROGRESS_SEGMENT_LIMIT = 15;
- private static final int MAX_PROGRESS_STOP_LIMIT = 5;
+ private static final int MAX_PROGRESS_SEGMENT_LIMIT = 10;
+ private static final int MAX_PROGRESS_POINT_LIMIT = 4;
private static final int DEFAULT_PROGRESS_MAX = 100;
private List<Segment> mProgressSegments = new ArrayList<>();
@@ -11286,7 +11286,9 @@ public class Notification implements Parcelable
mProgressSegments = new ArrayList<>();
}
mProgressSegments.clear();
- mProgressSegments.addAll(progressSegments);
+ for (Segment segment : progressSegments) {
+ addProgressSegment(segment);
+ }
return this;
}
@@ -11302,7 +11304,11 @@ public class Notification implements Parcelable
if (mProgressSegments == null) {
mProgressSegments = new ArrayList<>();
}
- mProgressSegments.add(segment);
+ if (segment.getLength() > 0) {
+ mProgressSegments.add(segment);
+ } else {
+ Log.w(TAG, "Dropped the segment. The length is not a positive integer.");
+ }
return this;
}
@@ -11327,7 +11333,14 @@ public class Notification implements Parcelable
* @see Point
*/
public @NonNull ProgressStyle setProgressPoints(@NonNull List<Point> points) {
- mProgressPoints = new ArrayList<>(points);
+ if (mProgressPoints == null) {
+ mProgressPoints = new ArrayList<>();
+ }
+ mProgressPoints.clear();
+
+ for (Point point: points) {
+ addProgressPoint(point);
+ }
return this;
}
@@ -11348,7 +11361,17 @@ public class Notification implements Parcelable
if (mProgressPoints == null) {
mProgressPoints = new ArrayList<>();
}
- mProgressPoints.add(point);
+ if (point.getPosition() >= 0) {
+ mProgressPoints.add(point);
+
+ if (mProgressPoints.size() > MAX_PROGRESS_POINT_LIMIT) {
+ Log.w(TAG, "Progress points limit is reached. First"
+ + MAX_PROGRESS_POINT_LIMIT + " points will be rendered.");
+ }
+
+ } else {
+ Log.w(TAG, "Dropped the point. The position is a negative integer.");
+ }
return this;
}
@@ -11384,8 +11407,7 @@ public class Notification implements Parcelable
} else {
int progressMax = 0;
int validSegmentCount = 0;
- for (int i = 0; i < progressSegment.size()
- && validSegmentCount < MAX_PROGRESS_SEGMENT_LIMIT; i++) {
+ for (int i = 0; i < progressSegment.size(); i++) {
int segmentLength = progressSegment.get(i).getLength();
if (segmentLength > 0) {
try {
@@ -11832,6 +11854,30 @@ public class Notification implements Parcelable
totalLength = DEFAULT_PROGRESS_MAX;
segments.add(sanitizeSegment(new Segment(totalLength), backgroundColor,
defaultProgressColor));
+ } else if (segments.size() > MAX_PROGRESS_SEGMENT_LIMIT) {
+ // If segment limit is exceeded. All segments will be replaced
+ // with a single segment
+ boolean allSameColor = true;
+ int firstSegmentColor = segments.get(0).getColor();
+
+ for (int i = 1; i < segments.size(); i++) {
+ if (segments.get(i).getColor() != firstSegmentColor) {
+ allSameColor = false;
+ break;
+ }
+ }
+
+ // This single segment length has same max as total.
+ final Segment singleSegment = new Segment(totalLength);
+ // Single segment color: if all segments have the same color,
+ // use that color. Otherwise, use 0 / default.
+ singleSegment.setColor(allSameColor ? firstSegmentColor
+ : Notification.COLOR_DEFAULT);
+
+ segments.clear();
+ segments.add(sanitizeSegment(singleSegment,
+ backgroundColor,
+ defaultProgressColor));
}
// Ensure point color contrasts.
@@ -11840,6 +11886,9 @@ public class Notification implements Parcelable
final int position = point.getPosition();
if (position < 0 || position > totalLength) continue;
points.add(sanitizePoint(point, backgroundColor, defaultProgressColor));
+ if (points.size() == MAX_PROGRESS_POINT_LIMIT) {
+ break;
+ }
}
model = new NotificationProgressModel(segments, points,
@@ -11868,8 +11917,10 @@ public class Notification implements Parcelable
* has the same hue as the original color, but is lightened or darkened depending on
* whether the background is dark or light.
*
+ * @hide
*/
- private int sanitizeProgressColor(@ColorInt int color,
+ @VisibleForTesting
+ public static int sanitizeProgressColor(@ColorInt int color,
@ColorInt int bg,
@ColorInt int defaultColor) {
return Builder.ensureColorContrast(
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 8ed66eb7e6c0..e9b889a2f1aa 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -55,6 +55,7 @@ import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
@@ -677,9 +678,14 @@ public class NotificationManager {
}
/** {@hide} */
- @UnsupportedAppUsage
- public NotificationManager(Context context, InstantSource clock)
+ public NotificationManager(Context context)
{
+ this(context, SystemClock.elapsedRealtimeClock());
+ }
+
+ /** {@hide} */
+ @UnsupportedAppUsage
+ public NotificationManager(Context context, InstantSource clock) {
mContext = context;
mClock = clock;
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 920b19cd8f78..0bbe9434293a 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -17,7 +17,7 @@
package android.app;
import static android.app.appfunctions.flags.Flags.enableAppFunctionManager;
-import static android.provider.flags.Flags.stageFlagsForBuild;
+import static android.provider.flags.Flags.newStoragePublicApi;
import static android.server.Flags.removeGameManagerServiceFromWear;
import android.accounts.AccountManager;
@@ -289,7 +289,6 @@ import com.android.internal.os.IDropBoxManagerService;
import com.android.internal.policy.PhoneLayoutInflater;
import com.android.internal.util.Preconditions;
-import java.time.InstantSource;
import java.util.Map;
import java.util.Objects;
@@ -625,8 +624,8 @@ public final class SystemServiceRegistry {
com.android.internal.R.style.Theme_Dialog,
com.android.internal.R.style.Theme_Holo_Dialog,
com.android.internal.R.style.Theme_DeviceDefault_Dialog,
- com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)),
- InstantSource.system());
+ com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog))
+ );
}});
registerService(Context.PEOPLE_SERVICE, PeopleManager.class,
@@ -1841,7 +1840,7 @@ public final class SystemServiceRegistry {
VirtualizationFrameworkInitializer.registerServiceWrappers();
ConnectivityFrameworkInitializerBaklava.registerServiceWrappers();
- if (stageFlagsForBuild()) {
+ if (newStoragePublicApi()) {
ConfigInfrastructureFrameworkInitializer.registerServiceWrappers();
}
diff --git a/core/java/android/app/jank/AppJankStats.java b/core/java/android/app/jank/AppJankStats.java
index eea1d2ba5b9e..6ef6a44ddfbb 100644
--- a/core/java/android/app/jank/AppJankStats.java
+++ b/core/java/android/app/jank/AppJankStats.java
@@ -41,7 +41,8 @@ public final class AppJankStats {
// The id that has been set for the widget.
private String mWidgetId;
- // A general category that the widget applies to.
+ // A general category the widget falls into based on the functions it performs or helps
+ // facilitate.
private String mWidgetCategory;
// The states that the UI elements can report
@@ -53,78 +54,78 @@ public final class AppJankStats {
// Total number of frames determined to be janky during the reported state.
private long mJankyFrames;
- // Histogram of frame duration overruns encoded in predetermined buckets.
- private FrameOverrunHistogram mFrameOverrunHistogram;
+ // Histogram of relative frame times encoded in predetermined buckets.
+ private RelativeFrameTimeHistogram mRelativeFrameTimeHistogram;
/** Used to indicate no widget category has been set. */
- public static final String WIDGET_CATEGORY_UNSPECIFIED =
- "widget_category_unspecified";
+ public static final String WIDGET_CATEGORY_UNSPECIFIED = "unspecified";
/** UI elements that facilitate scrolling. */
- public static final String SCROLL = "scroll";
+ public static final String WIDGET_CATEGORY_SCROLL = "scroll";
/** UI elements that facilitate playing animations. */
- public static final String ANIMATION = "animation";
+ public static final String WIDGET_CATEGORY_ANIMATION = "animation";
/** UI elements that facilitate media playback. */
- public static final String MEDIA = "media";
+ public static final String WIDGET_CATEGORY_MEDIA = "media";
/** UI elements that facilitate in-app navigation. */
- public static final String NAVIGATION = "navigation";
+ public static final String WIDGET_CATEGORY_NAVIGATION = "navigation";
/** UI elements that facilitate displaying, hiding or interacting with keyboard. */
- public static final String KEYBOARD = "keyboard";
-
- /** UI elements that facilitate predictive back gesture navigation. */
- public static final String PREDICTIVE_BACK = "predictive_back";
+ public static final String WIDGET_CATEGORY_KEYBOARD = "keyboard";
/** UI elements that don't fall in one or any of the other categories. */
- public static final String OTHER = "other";
+ public static final String WIDGET_CATEGORY_OTHER = "other";
/** Used to indicate no widget state has been set. */
- public static final String WIDGET_STATE_UNSPECIFIED = "widget_state_unspecified";
+ public static final String WIDGET_STATE_UNSPECIFIED = "unspecified";
/** Used to indicate the UI element currently has no state and is idle. */
- public static final String NONE = "none";
+ public static final String WIDGET_STATE_NONE = "none";
/** Used to indicate the UI element is currently scrolling. */
- public static final String SCROLLING = "scrolling";
+ public static final String WIDGET_STATE_SCROLLING = "scrolling";
/** Used to indicate the UI element is currently being flung. */
- public static final String FLINGING = "flinging";
+ public static final String WIDGET_STATE_FLINGING = "flinging";
/** Used to indicate the UI element is currently being swiped. */
- public static final String SWIPING = "swiping";
+ public static final String WIDGET_STATE_SWIPING = "swiping";
/** Used to indicate the UI element is currently being dragged. */
- public static final String DRAGGING = "dragging";
+ public static final String WIDGET_STATE_DRAGGING = "dragging";
/** Used to indicate the UI element is currently zooming. */
- public static final String ZOOMING = "zooming";
+ public static final String WIDGET_STATE_ZOOMING = "zooming";
/** Used to indicate the UI element is currently animating. */
- public static final String ANIMATING = "animating";
+ public static final String WIDGET_STATE_ANIMATING = "animating";
/** Used to indicate the UI element is currently playing media. */
- public static final String PLAYBACK = "playback";
+ public static final String WIDGET_STATE_PLAYBACK = "playback";
/** Used to indicate the UI element is currently being tapped on, for example on a keyboard. */
- public static final String TAPPING = "tapping";
+ public static final String WIDGET_STATE_TAPPING = "tapping";
+
+ /** Used to indicate predictive back navigation is currently being used */
+ public static final String WIDGET_STATE_PREDICTIVE_BACK = "predictive_back";
/**
+ * Provide an organized way to group widgets that have similar purposes or perform related
+ * functions.
* @hide
*/
- @StringDef(value = {
+ @StringDef(prefix = {"WIDGET_CATEGORY_"}, value = {
WIDGET_CATEGORY_UNSPECIFIED,
- SCROLL,
- ANIMATION,
- MEDIA,
- NAVIGATION,
- KEYBOARD,
- PREDICTIVE_BACK,
- OTHER
+ WIDGET_CATEGORY_SCROLL,
+ WIDGET_CATEGORY_ANIMATION,
+ WIDGET_CATEGORY_MEDIA,
+ WIDGET_CATEGORY_NAVIGATION,
+ WIDGET_CATEGORY_KEYBOARD,
+ WIDGET_CATEGORY_OTHER
})
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@Retention(RetentionPolicy.SOURCE)
@@ -133,17 +134,18 @@ public final class AppJankStats {
/**
* @hide
*/
- @StringDef(value = {
+ @StringDef(prefix = {"WIDGET_STATE_"}, value = {
WIDGET_STATE_UNSPECIFIED,
- NONE,
- SCROLLING,
- FLINGING,
- SWIPING,
- DRAGGING,
- ZOOMING,
- ANIMATING,
- PLAYBACK,
- TAPPING,
+ WIDGET_STATE_NONE,
+ WIDGET_STATE_SCROLLING,
+ WIDGET_STATE_FLINGING,
+ WIDGET_STATE_SWIPING,
+ WIDGET_STATE_DRAGGING,
+ WIDGET_STATE_ZOOMING,
+ WIDGET_STATE_ANIMATING,
+ WIDGET_STATE_PLAYBACK,
+ WIDGET_STATE_TAPPING,
+ WIDGET_STATE_PREDICTIVE_BACK
})
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@Retention(RetentionPolicy.SOURCE)
@@ -156,31 +158,33 @@ public final class AppJankStats {
*
* @param appUid the Uid of the App that is collecting jank stats.
* @param widgetId the widget id that frames will be associated to.
- * @param widgetCategory a general functionality category that the widget falls into. Must be
- * one of the following: SCROLL, ANIMATION, MEDIA, NAVIGATION, KEYBOARD,
- * PREDICTIVE_BACK, OTHER or will be set to WIDGET_CATEGORY_UNSPECIFIED
- * if no value is passed.
- * @param widgetState the state the widget was in while frames were counted. Must be one of
- * the following: NONE, SCROLLING, FLINGING, SWIPING, DRAGGING, ZOOMING,
- * ANIMATING, PLAYBACK, TAPPING or will be set to WIDGET_STATE_UNSPECIFIED
- * if no value is passed.
+ * @param widgetCategory a category used to organize widgets in a structured way that indicates
+ * they serve a similar purpose or perform related functions. Must be
+ * prefixed with WIDGET_CATEGORY_ and have a suffix of one of the
+ * following:SCROLL, ANIMATION, MEDIA, NAVIGATION, KEYBOARD, OTHER or
+ * will be set to UNSPECIFIED if no value is passed.
+ * @param widgetState the state the widget was in while frames were counted. Must be prefixed
+ * with WIDGET_STATE_ and have a suffix of one of the following:
+ * NONE, SCROLLING, FLINGING, SWIPING, DRAGGING, ZOOMING, ANIMATING,
+ * PLAYBACK, TAPPING, PREDICTIVE_BACK or will be set to
+ * WIDGET_STATE_UNSPECIFIED if no value is passed.
* @param totalFrames the total number of frames that were counted for this stat.
* @param jankyFrames the total number of janky frames that were counted for this stat.
- * @param frameOverrunHistogram the histogram with predefined buckets. See
- * {@link #getFrameOverrunHistogram()} for details.
+ * @param relativeFrameTimeHistogram the histogram with predefined buckets. See
+ * {@link #getRelativeFrameTimeHistogram()} for details.
*
*/
public AppJankStats(int appUid, @NonNull String widgetId,
@Nullable @WidgetCategory String widgetCategory,
@Nullable @WidgetState String widgetState, long totalFrames, long jankyFrames,
- @NonNull FrameOverrunHistogram frameOverrunHistogram) {
+ @NonNull RelativeFrameTimeHistogram relativeFrameTimeHistogram) {
mUid = appUid;
mWidgetId = widgetId;
mWidgetCategory = widgetCategory != null ? widgetCategory : WIDGET_CATEGORY_UNSPECIFIED;
mWidgetState = widgetState != null ? widgetState : WIDGET_STATE_UNSPECIFIED;
mTotalFrames = totalFrames;
mJankyFrames = jankyFrames;
- mFrameOverrunHistogram = frameOverrunHistogram;
+ mRelativeFrameTimeHistogram = relativeFrameTimeHistogram;
}
/**
@@ -203,7 +207,7 @@ public final class AppJankStats {
/**
* Returns the category that the widget's functionality generally falls into, or
- * widget_category_unspecified {@link #WIDGET_CATEGORY_UNSPECIFIED} if no value was passed in.
+ * {@link #WIDGET_CATEGORY_UNSPECIFIED} if no value was passed in.
*
* @return the category that the widget's functionality generally falls into, this value cannot
* be null.
@@ -213,7 +217,7 @@ public final class AppJankStats {
}
/**
- * Returns the widget's state that was reported for this stat, or widget_state_unspecified
+ * Returns the widget's state that was reported for this stat, or
* {@link #WIDGET_STATE_UNSPECIFIED} if no value was passed in.
*
* @return the widget's state that was reported for this stat. This value cannot be null.
@@ -241,13 +245,13 @@ public final class AppJankStats {
}
/**
- * Returns a Histogram containing frame overrun times in millis grouped into predefined buckets.
- * See {@link FrameOverrunHistogram} for more information.
+ * Returns a Histogram containing relative frame times in millis grouped into predefined
+ * buckets. See {@link RelativeFrameTimeHistogram} for more information.
*
- * @return Histogram containing frame overrun times in predefined buckets. This value cannot
+ * @return Histogram containing relative frame times in predefined buckets. This value cannot
* be null.
*/
- public @NonNull FrameOverrunHistogram getFrameOverrunHistogram() {
- return mFrameOverrunHistogram;
+ public @NonNull RelativeFrameTimeHistogram getRelativeFrameTimeHistogram() {
+ return mRelativeFrameTimeHistogram;
}
}
diff --git a/core/java/android/app/jank/FrameOverrunHistogram.java b/core/java/android/app/jank/FrameOverrunHistogram.java
deleted file mode 100644
index 3ad6531a46bf..000000000000
--- a/core/java/android/app/jank/FrameOverrunHistogram.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.jank;
-
-import android.annotation.FlaggedApi;
-import android.annotation.NonNull;
-
-import java.util.Arrays;
-
-/**
- * This class is intended to be used when reporting {@link AppJankStats} back to the system. It's
- * intended to be used by library widgets to help facilitate the reporting of frame overrun times
- * by adding those times into predefined buckets.
- */
-@FlaggedApi(Flags.FLAG_DETAILED_APP_JANK_METRICS_API)
-public class FrameOverrunHistogram {
- private static int[] sBucketEndpoints = new int[]{
- Integer.MIN_VALUE, -200, -150, -100, -90, -80, -70, -60, -50, -40, -30, -25, -20, -18,
- -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 25, 30, 40,
- 50, 60, 70, 80, 90, 100, 150, 200, 300, 400, 500, 600, 700, 800, 900, 1000
- };
- private int[] mBucketCounts;
-
- /**
- * Create a new instance of FrameOverrunHistogram.
- */
- public FrameOverrunHistogram() {
- mBucketCounts = new int[sBucketEndpoints.length];
- }
-
- /**
- * Increases the count by one for the bucket representing the frame overrun duration.
- *
- * @param frameOverrunMillis frame overrun duration in millis, frame overrun is the difference
- * between a frames deadline and when it was rendered.
- */
- public void addFrameOverrunMillis(int frameOverrunMillis) {
- int countsIndex = getIndexForCountsFromOverrunTime(frameOverrunMillis);
- mBucketCounts[countsIndex]++;
- }
-
- /**
- * Returns the counts for the all the frame overrun buckets.
- *
- * @return an array of integers representing the counts of frame overrun times. This value
- * cannot be null.
- */
- public @NonNull int[] getBucketCounters() {
- return Arrays.copyOf(mBucketCounts, mBucketCounts.length);
- }
-
- /**
- * Returns the predefined endpoints for the histogram.
- *
- * @return array of integers representing the endpoints for the predefined histogram count
- * buckets. This value cannot be null.
- */
- public @NonNull int[] getBucketEndpointsMillis() {
- return Arrays.copyOf(sBucketEndpoints, sBucketEndpoints.length);
- }
-
- // This takes the overrun time and returns what bucket it belongs to in the counters array.
- private int getIndexForCountsFromOverrunTime(int overrunTime) {
- if (overrunTime < 20) {
- if (overrunTime >= -20) {
- return (overrunTime + 20) / 2 + 12;
- }
- if (overrunTime >= -30) {
- return (overrunTime + 30) / 5 + 10;
- }
- if (overrunTime >= -100) {
- return (overrunTime + 100) / 10 + 3;
- }
- if (overrunTime >= -200) {
- return (overrunTime + 200) / 50 + 1;
- }
- return 0;
- }
- if (overrunTime < 30) {
- return (overrunTime - 20) / 5 + 32;
- }
- if (overrunTime < 100) {
- return (overrunTime - 30) / 10 + 34;
- }
- if (overrunTime < 200) {
- return (overrunTime - 50) / 100 + 41;
- }
- if (overrunTime < 1000) {
- return (overrunTime - 200) / 100 + 43;
- }
- return sBucketEndpoints.length - 1;
- }
-}
diff --git a/core/java/android/app/jank/JankDataProcessor.java b/core/java/android/app/jank/JankDataProcessor.java
index c9472598b352..b4c293eeb695 100644
--- a/core/java/android/app/jank/JankDataProcessor.java
+++ b/core/java/android/app/jank/JankDataProcessor.java
@@ -111,7 +111,7 @@ public class JankDataProcessor {
pendingStat.mTotalFrames += jankStat.getTotalFrameCount();
mergeOverrunHistograms(pendingStat.mFrameOverrunBuckets,
- jankStat.getFrameOverrunHistogram().getBucketCounters());
+ jankStat.getRelativeFrameTimeHistogram().getBucketCounters());
}
private void mergeNewStat(String stateKey, String activityName, AppJankStats jankStats) {
@@ -136,7 +136,7 @@ public class JankDataProcessor {
pendingStat.mJankyFrames = jankStats.getJankyFrameCount();
mergeOverrunHistograms(pendingStat.mFrameOverrunBuckets,
- jankStats.getFrameOverrunHistogram().getBucketCounters());
+ jankStats.getRelativeFrameTimeHistogram().getBucketCounters());
mPendingJankStats.put(stateKey, pendingStat);
}
@@ -271,7 +271,8 @@ public class JankDataProcessor {
private static final int[] sFrameOverrunHistogramBounds = {
Integer.MIN_VALUE, -200, -150, -100, -90, -80, -70, -60, -50, -40, -30, -25, -20,
-18, -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 25,
- 30, 40, 50, 60, 70, 80, 90, 100, 150, 200, 300, 400, 500, 600, 700, 800, 900, 1000
+ 30, 40, 50, 60, 70, 80, 90, 100, 150, 200, 300, 400, 500, 600, 700, 800, 900, 1000,
+ Integer.MAX_VALUE
};
private final int[] mFrameOverrunBuckets = new int[sFrameOverrunHistogramBounds.length];
@@ -414,7 +415,7 @@ public class JankDataProcessor {
if (overrunTime < 200) {
return (overrunTime - 50) / 100 + 41;
}
- if (overrunTime < 1000) {
+ if (overrunTime <= 1000) {
return (overrunTime - 200) / 100 + 43;
}
return sFrameOverrunHistogramBounds.length - 1;
diff --git a/core/java/android/app/jank/RelativeFrameTimeHistogram.java b/core/java/android/app/jank/RelativeFrameTimeHistogram.java
new file mode 100644
index 000000000000..666f90f89f45
--- /dev/null
+++ b/core/java/android/app/jank/RelativeFrameTimeHistogram.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.jank;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+
+import java.util.Arrays;
+
+/**
+ * A histogram of frame times relative to their deadline.
+ *
+ * This class aids in reporting {@link AppJankStats} to the system and is designed for use by
+ * library widgets. It facilitates the recording of frame times in relation to the frame deadline.
+ * The class records the distribution of time remaining until a frame is considered janky or how
+ * janky the frame was.
+ * <p>
+ * A frame's relative frame time value indicates whether it was delivered early, on time, or late.
+ * A negative relative frame time value indicates the frame was delivered early, a value of zero
+ * indicates the frame was delivered on time and a positive value indicates the frame was delivered
+ * late. The values of the endpoints indicate how early or late a frame was delivered.
+ * <p>
+ * The relative frame times are recorded as a histogram: values are
+ * {@link #addRelativeFrameTimeMillis added} to a bucket by increasing the bucket's counter. The
+ * count of frames with a relative frame time between
+ * {@link #getBucketEndpointsMillis bucket endpoints} {@code i} and {@code i+1} can be obtained
+ * through index {@code i} of {@link #getBucketCounters}.
+ *
+ */
+@FlaggedApi(Flags.FLAG_DETAILED_APP_JANK_METRICS_API)
+public class RelativeFrameTimeHistogram {
+ private static int[] sBucketEndpoints = new int[]{
+ Integer.MIN_VALUE, -200, -150, -100, -90, -80, -70, -60, -50, -40, -30, -25, -20, -18,
+ -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 25, 30, 40,
+ 50, 60, 70, 80, 90, 100, 150, 200, 300, 400, 500, 600, 700, 800, 900, 1000,
+ Integer.MAX_VALUE
+ };
+ //
+ private int[] mBucketCounts;
+
+ /**
+ * Create a new instance of RelativeFrameTimeHistogram.
+ */
+ public RelativeFrameTimeHistogram() {
+ mBucketCounts = new int[sBucketEndpoints.length - 1];
+ }
+
+ /**
+ * Increases the count by one for the bucket representing the relative frame time.
+ *
+ * @param frameTimeMillis relative frame time in millis, relative frame time is the difference
+ * between a frames deadline and when it was rendered.
+ */
+ public void addRelativeFrameTimeMillis(int frameTimeMillis) {
+ int countsIndex = getRelativeFrameTimeBucketIndex(frameTimeMillis);
+ mBucketCounts[countsIndex]++;
+ }
+
+ /**
+ * Returns the counts for the all the relative frame time buckets.
+ *
+ * @return an array of integers representing the counts of relative frame times. This value
+ * cannot be null.
+ */
+ public @NonNull int[] getBucketCounters() {
+ return Arrays.copyOf(mBucketCounts, mBucketCounts.length);
+ }
+
+ /**
+ * Returns the relative frame time endpoints for the histogram.
+ * <p>
+ * Index {@code i} of {@link #getBucketCounters} contains the count of frames that had a
+ * relative frame time between {@code endpoints[i]} (inclusive) and {@code endpoints[i+1]}
+ * (exclusive).
+ *
+ * @return array of integers representing the endpoints for the predefined histogram count
+ * buckets. This value cannot be null.
+ */
+ public @NonNull int[] getBucketEndpointsMillis() {
+ return Arrays.copyOf(sBucketEndpoints, sBucketEndpoints.length);
+ }
+
+ // This takes the relative frame time and returns what bucket it belongs to in the counters
+ // array.
+ private int getRelativeFrameTimeBucketIndex(int relativeFrameTime) {
+ if (relativeFrameTime < 20) {
+ if (relativeFrameTime >= -20) {
+ return (relativeFrameTime + 20) / 2 + 12;
+ }
+ if (relativeFrameTime >= -30) {
+ return (relativeFrameTime + 30) / 5 + 10;
+ }
+ if (relativeFrameTime >= -100) {
+ return (relativeFrameTime + 100) / 10 + 3;
+ }
+ if (relativeFrameTime >= -200) {
+ return (relativeFrameTime + 200) / 50 + 1;
+ }
+ return 0;
+ }
+ if (relativeFrameTime < 30) {
+ return (relativeFrameTime - 20) / 5 + 32;
+ }
+ if (relativeFrameTime < 100) {
+ return (relativeFrameTime - 30) / 10 + 34;
+ }
+ if (relativeFrameTime < 200) {
+ return (relativeFrameTime - 50) / 100 + 41;
+ }
+ if (relativeFrameTime < 1000) {
+ return (relativeFrameTime - 200) / 100 + 43;
+ }
+ return mBucketCounts.length - 1;
+ }
+}
diff --git a/core/java/android/hardware/contexthub/HubServiceInfo.java b/core/java/android/hardware/contexthub/HubServiceInfo.java
index 2f33e8f8872b..651be3b17c33 100644
--- a/core/java/android/hardware/contexthub/HubServiceInfo.java
+++ b/core/java/android/hardware/contexthub/HubServiceInfo.java
@@ -112,6 +112,7 @@ public final class HubServiceInfo implements Parcelable {
* <p>The value can be one of {@link HubServiceInfo#FORMAT_CUSTOM}, {@link
* HubServiceInfo#FORMAT_AIDL} or {@link HubServiceInfo#FORMAT_PW_RPC_PROTOBUF}.
*/
+ @ServiceFormat
public int getFormat() {
return mFormat;
}
@@ -178,7 +179,8 @@ public final class HubServiceInfo implements Parcelable {
* <li>Pigweed RPC with Protobuf: com.example.proto.ExampleService
* </ol>
*
- * @param serviceDescriptor The service descriptor.
+ * @param serviceDescriptor The service descriptor for the interface, provided by the
+ * vendor.
* @param format One of {@link HubServiceInfo#FORMAT_CUSTOM}, {@link
* HubServiceInfo#FORMAT_AIDL} or {@link HubServiceInfo#FORMAT_PW_RPC_PROTOBUF}.
* @param majorVersion Breaking changes should be a major version bump.
diff --git a/core/java/android/hardware/display/DisplayTopology.java b/core/java/android/hardware/display/DisplayTopology.java
index 211aefffa34c..ba5dfc094afb 100644
--- a/core/java/android/hardware/display/DisplayTopology.java
+++ b/core/java/android/hardware/display/DisplayTopology.java
@@ -129,14 +129,38 @@ public final class DisplayTopology implements Parcelable {
}
/**
+ * Update the size of a display and normalize the topology.
+ * @param displayId The logical display ID
+ * @param width The new width
+ * @param height The new height
+ * @return True if the topology has changed.
+ */
+ public boolean updateDisplay(int displayId, float width, float height) {
+ TreeNode display = findDisplay(displayId, mRoot);
+ if (display == null) {
+ return false;
+ }
+ if (floatEquals(display.mWidth, width) && floatEquals(display.mHeight, height)) {
+ return false;
+ }
+ display.mWidth = width;
+ display.mHeight = height;
+ normalize();
+ Slog.i(TAG, "Display with ID " + displayId + " updated, new width: " + width
+ + ", new height: " + height);
+ return true;
+ }
+
+ /**
* Remove a display from the topology.
* The default topology is created from the remaining displays, as if they were reconnected
* one by one.
* @param displayId The logical display ID
+ * @return True if the display was present in the topology and removed.
*/
- public void removeDisplay(int displayId) {
+ public boolean removeDisplay(int displayId) {
if (findDisplay(displayId, mRoot) == null) {
- return;
+ return false;
}
Queue<TreeNode> queue = new ArrayDeque<>();
queue.add(mRoot);
@@ -159,6 +183,7 @@ public final class DisplayTopology implements Parcelable {
} else {
Slog.i(TAG, "Display with ID " + displayId + " removed");
}
+ return true;
}
/**
@@ -685,12 +710,12 @@ public final class DisplayTopology implements Parcelable {
/**
* The width of the display in density-independent pixels (dp).
*/
- private final float mWidth;
+ private float mWidth;
/**
* The height of the display in density-independent pixels (dp).
*/
- private final float mHeight;
+ private float mHeight;
/**
* The position of this display relative to its parent.
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 0633233e4ac7..0cd320981c93 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -718,7 +718,19 @@ public final class ContextHubManager {
/**
* Find a list of endpoints that provides a specific service.
*
- * @param serviceDescriptor Statically generated ID for an endpoint.
+ * <p>Service descriptor should uniquely identify the interface (scoped to type). Convention of
+ * the descriptor depend on interface type.
+ *
+ * <p>Examples:
+ *
+ * <ol>
+ * <li>AOSP-defined AIDL: android.hardware.something.IFoo/default
+ * <li>Vendor-defined AIDL: com.example.something.IBar/default
+ * <li>Pigweed RPC with Protobuf: com.example.proto.ExampleService
+ * </ol>
+ *
+ * @param serviceDescriptor The service descriptor for a service provided by the hub. The value
+ * cannot be null or empty.
* @return A list of {@link HubDiscoveryInfo} objects that represents the result of discovery.
* @throws IllegalArgumentException if the serviceDescriptor is empty/null.
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c3a49305af87..6898fcef23ab 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1296,6 +1296,22 @@ public final class Settings {
public static final String ACTION_LOCKSCREEN_SETTINGS = "android.settings.LOCK_SCREEN_SETTINGS";
/**
+ * Activity Action: Show settings of notifications on lockscreen.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_LOCKSCREEN_NOTIFICATIONS_SETTINGS =
+ "android.settings.LOCK_SCREEN_NOTIFICATIONS_SETTINGS";
+
+ /**
* Activity Action: Show settings to allow pairing bluetooth devices.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
diff --git a/core/java/android/service/settings/preferences/GetValueRequest.java b/core/java/android/service/settings/preferences/GetValueRequest.java
index 4f82800d1855..db5c57c49595 100644
--- a/core/java/android/service/settings/preferences/GetValueRequest.java
+++ b/core/java/android/service/settings/preferences/GetValueRequest.java
@@ -108,6 +108,7 @@ public final class GetValueRequest implements Parcelable {
/**
* Builder to construct {@link GetValueRequest}.
*/
+ @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST)
public static final class Builder {
private final String mScreenKey;
private final String mPreferenceKey;
diff --git a/core/java/android/service/settings/preferences/GetValueResult.java b/core/java/android/service/settings/preferences/GetValueResult.java
index 369dea77cc85..791131588034 100644
--- a/core/java/android/service/settings/preferences/GetValueResult.java
+++ b/core/java/android/service/settings/preferences/GetValueResult.java
@@ -170,6 +170,7 @@ public final class GetValueResult implements Parcelable {
/**
* Builder to construct {@link GetValueResult}.
*/
+ @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST)
public static final class Builder {
@ResultCode
private final int mResultCode;
diff --git a/core/java/android/service/settings/preferences/MetadataRequest.java b/core/java/android/service/settings/preferences/MetadataRequest.java
index ffecc6bec5b2..e0417152eedc 100644
--- a/core/java/android/service/settings/preferences/MetadataRequest.java
+++ b/core/java/android/service/settings/preferences/MetadataRequest.java
@@ -65,6 +65,7 @@ public final class MetadataRequest implements Parcelable {
/**
* Builder to construct {@link MetadataRequest}.
*/
+ @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST)
public static final class Builder {
/** Constructs an immutable {@link MetadataRequest} object. */
@NonNull
diff --git a/core/java/android/service/settings/preferences/MetadataResult.java b/core/java/android/service/settings/preferences/MetadataResult.java
index 6a65dcc9c757..e62fa8f38c93 100644
--- a/core/java/android/service/settings/preferences/MetadataResult.java
+++ b/core/java/android/service/settings/preferences/MetadataResult.java
@@ -131,6 +131,7 @@ public final class MetadataResult implements Parcelable {
/**
* Builder to construct {@link MetadataResult}.
*/
+ @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST)
public static final class Builder {
@ResultCode
private final int mResultCode;
diff --git a/core/java/android/service/settings/preferences/SetValueRequest.java b/core/java/android/service/settings/preferences/SetValueRequest.java
index f7600aecdfaf..77581d9deffe 100644
--- a/core/java/android/service/settings/preferences/SetValueRequest.java
+++ b/core/java/android/service/settings/preferences/SetValueRequest.java
@@ -123,6 +123,7 @@ public final class SetValueRequest implements Parcelable {
/**
* Builder to construct {@link SetValueRequest}.
*/
+ @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST)
public static final class Builder {
private final String mScreenKey;
private final String mPreferenceKey;
diff --git a/core/java/android/service/settings/preferences/SetValueResult.java b/core/java/android/service/settings/preferences/SetValueResult.java
index cb1776abd3bc..513f7a7d5bcc 100644
--- a/core/java/android/service/settings/preferences/SetValueResult.java
+++ b/core/java/android/service/settings/preferences/SetValueResult.java
@@ -156,6 +156,7 @@ public final class SetValueResult implements Parcelable {
/**
* Builder to construct {@link SetValueResult}.
*/
+ @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST)
public static final class Builder {
@ResultCode
private final int mResultCode;
diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java b/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java
index ea7d4a675713..30631f2fd71d 100644
--- a/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java
+++ b/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java
@@ -102,6 +102,7 @@ public final class SettingsPreferenceMetadata implements Parcelable {
/**
* Returns the breadcrumbs (navigation context) of Preference.
* <p>May be empty.
+ * @hide restrict to platform; may be opened wider in the future
*/
@NonNull
public List<String> getBreadcrumbs() {
@@ -189,33 +190,32 @@ public final class SettingsPreferenceMetadata implements Parcelable {
@IntDef(value = {
NO_SENSITIVITY,
EXPECT_POST_CONFIRMATION,
- EXPECT_PRE_CONFIRMATION,
+ DEEPLINK_ONLY,
NO_DIRECT_ACCESS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface WriteSensitivity {}
/**
- * Indicates preference is not sensitive.
+ * Indicates preference is not write-sensitive.
* <p>Its value is writable without explicit consent, assuming all necessary permissions are
* granted.
*/
public static final int NO_SENSITIVITY = 0;
/**
- * Indicates preference is mildly sensitive.
+ * Indicates preference is mildly write-sensitive.
* <p>In addition to necessary permissions, after writing its value the user should be
* given the option to revert back.
*/
public static final int EXPECT_POST_CONFIRMATION = 1;
/**
- * Indicates preference is sensitive.
- * <p>In addition to necessary permissions, the user should be prompted for confirmation prior
- * to making a change. Otherwise it is suggested to provide a deeplink to the Preference's page
- * instead, accessible via {@link #getLaunchIntent}.
+ * Indicates preference is write-sensitive.
+ * <p>This preference cannot be changed through this API; instead a deeplink to the Preference's
+ * page should be used instead, accessible via {@link #getLaunchIntent}.
*/
- public static final int EXPECT_PRE_CONFIRMATION = 2;
+ public static final int DEEPLINK_ONLY = 2;
/**
- * Indicates preference is highly sensitivity and carries significant user-risk.
+ * Indicates preference is highly write-sensitivity and carries significant user-risk.
* <p>This Preference cannot be changed through this API and no direct deeplink is available.
* Other Metadata is still available.
*/
@@ -303,6 +303,7 @@ public final class SettingsPreferenceMetadata implements Parcelable {
/**
* Builder to construct {@link SettingsPreferenceMetadata}.
*/
+ @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST)
public static final class Builder {
private final String mScreenKey;
private final String mKey;
@@ -355,6 +356,7 @@ public final class SettingsPreferenceMetadata implements Parcelable {
/**
* Sets the preference breadcrumbs (navigation context).
+ * @hide
*/
@NonNull
public Builder setBreadcrumbs(@NonNull List<String> breadcrumbs) {
diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceValue.java b/core/java/android/service/settings/preferences/SettingsPreferenceValue.java
index 08826ca9776b..eea93b321e47 100644
--- a/core/java/android/service/settings/preferences/SettingsPreferenceValue.java
+++ b/core/java/android/service/settings/preferences/SettingsPreferenceValue.java
@@ -170,6 +170,7 @@ public final class SettingsPreferenceValue implements Parcelable {
/**
* Builder to construct {@link SettingsPreferenceValue}.
*/
+ @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST)
public static final class Builder {
@Type
private final int mType;
diff --git a/core/java/android/tracing/flags.aconfig b/core/java/android/tracing/flags.aconfig
index fb1bd1703ce6..6116d599baa0 100644
--- a/core/java/android/tracing/flags.aconfig
+++ b/core/java/android/tracing/flags.aconfig
@@ -70,3 +70,11 @@ flag {
is_fixed_read_only: true
bug: "352538294"
}
+
+flag {
+ name: "system_server_large_perfetto_shmem_buffer"
+ namespace: "windowing_tools"
+ description: "Large perfetto shmem buffer"
+ is_fixed_read_only: true
+ bug: "382369925"
+}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 6e6e87bb9403..4fc1cfc0ca82 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -206,7 +206,8 @@ public class Surface implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"FRAME_RATE_COMPATIBILITY_"},
value = {FRAME_RATE_COMPATIBILITY_DEFAULT, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
- FRAME_RATE_COMPATIBILITY_GTE})
+ FRAME_RATE_COMPATIBILITY_AT_LEAST, FRAME_RATE_COMPATIBILITY_EXACT,
+ FRAME_RATE_COMPATIBILITY_MIN})
public @interface FrameRateCompatibility {}
// From native_window.h. Keep these in sync.
@@ -219,7 +220,7 @@ public class Surface implements Parcelable {
* In Android version {@link Build.VERSION_CODES#BAKLAVA} and above, use
* {@link FRAME_RATE_COMPATIBILITY_DEFAULT} for game content.
* For other cases, see {@link FRAME_RATE_COMPATIBILITY_FIXED_SOURCE} and
- * {@link FRAME_RATE_COMPATIBILITY_GTE}.
+ * {@link FRAME_RATE_COMPATIBILITY_AT_LEAST}.
*/
public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0;
@@ -234,7 +235,7 @@ public class Surface implements Parcelable {
public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1;
/**
- * The surface requests a frame rate that is greater than or equal to the specified frame rate.
+ * The surface requests a frame rate that is at least the specified frame rate.
* This value should be used for UIs, animations, scrolling and fling, and anything that is not
* a game or video.
*
@@ -242,7 +243,7 @@ public class Surface implements Parcelable {
* {@link FRAME_RATE_COMPATIBILITY_DEFAULT}.
*/
@FlaggedApi(com.android.graphics.surfaceflinger.flags.Flags.FLAG_ARR_SETFRAMERATE_GTE_ENUM)
- public static final int FRAME_RATE_COMPATIBILITY_GTE = 2;
+ public static final int FRAME_RATE_COMPATIBILITY_AT_LEAST = 2;
/**
* This surface belongs to an app on the High Refresh Rate Deny list, and needs the display
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d13f0e21bf80..8f8bfe2865a9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -27,7 +27,7 @@ import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE;
import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
-import static android.view.Surface.FRAME_RATE_COMPATIBILITY_GTE;
+import static android.view.Surface.FRAME_RATE_COMPATIBILITY_AT_LEAST;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
import static android.view.accessibility.Flags.FLAG_DEPRECATE_ACCESSIBILITY_ANNOUNCEMENT_APIS;
@@ -34251,7 +34251,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
compatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
frameRateToSet = frameRate;
} else {
- compatibility = FRAME_RATE_COMPATIBILITY_GTE;
+ compatibility = FRAME_RATE_COMPATIBILITY_AT_LEAST;
frameRateToSet = velocityFrameRate;
}
viewRootImpl.votePreferredFrameRate(frameRateToSet, compatibility);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ec1650947aec..16cdb64f62cc 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -38,7 +38,7 @@ import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE;
import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
-import static android.view.Surface.FRAME_RATE_COMPATIBILITY_GTE;
+import static android.view.Surface.FRAME_RATE_COMPATIBILITY_AT_LEAST;
import static android.view.View.FRAME_RATE_CATEGORY_REASON_BOOST;
import static android.view.View.FRAME_RATE_CATEGORY_REASON_CONFLICTED;
import static android.view.View.FRAME_RATE_CATEGORY_REASON_INTERMITTENT;
@@ -13272,7 +13272,7 @@ public final class ViewRootImpl implements ViewParent,
* We set category to HIGH if the maximum frame rate is greater than 60.
* Otherwise, we set category to NORMAL.
*
- * Use FRAME_RATE_COMPATIBILITY_GTE for velocity and FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
+ * Use FRAME_RATE_COMPATIBILITY_AT_LEAST for velocity and FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
* for TextureView video play and user requested frame rate.
*
* @param frameRate the preferred frame rate of a View
@@ -13283,7 +13283,7 @@ public final class ViewRootImpl implements ViewParent,
if (frameRate <= 0) {
return;
}
- if (frameRateCompatibility == FRAME_RATE_COMPATIBILITY_GTE && !mIsPressedGesture) {
+ if (frameRateCompatibility == FRAME_RATE_COMPATIBILITY_AT_LEAST && !mIsPressedGesture) {
mIsTouchBoosting = false;
mIsFrameRateBoosting = false;
if (!sToolkitFrameRateVelocityMappingReadOnlyFlagValue) {
diff --git a/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig b/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig
index 20d193ea2351..f709ed7f57cd 100644
--- a/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig
+++ b/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig
@@ -12,5 +12,5 @@ flag {
name: "ccapi_baklava_enabled"
namespace: "machine_learning"
description: "Feature flag for baklava content capture API"
- bug: "309411951"
+ bug: "380381249"
}
diff --git a/core/java/android/window/WindowTokenClientController.java b/core/java/android/window/WindowTokenClientController.java
index 11019324acd8..fcd7dfbb1769 100644
--- a/core/java/android/window/WindowTokenClientController.java
+++ b/core/java/android/window/WindowTokenClientController.java
@@ -148,6 +148,9 @@ public class WindowTokenClientController {
info = wms.attachWindowContextToDisplayContent(mAppThread, client, displayId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } catch (Exception e) {
+ Log.e(TAG, "Failed attachToDisplayContent", e);
+ return false;
}
if (info == null) {
return false;
diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
index 801698caff0e..0d04961569e6 100644
--- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
+++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
@@ -58,13 +58,6 @@ flag {
}
flag {
- name: "user_min_aspect_ratio_app_default"
- namespace: "large_screen_experiences_app_compat"
- description: "Whether the API PackageManager.USER_MIN_ASPECT_RATIO_APP_DEFAULT is available"
- bug: "310816437"
-}
-
-flag {
name: "allow_hide_scm_button"
namespace: "large_screen_experiences_app_compat"
description: "Whether we should allow hiding the size compat restart button"
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index ae846441723a..c97d3ec787b3 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -148,3 +148,13 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ namespace: "windowing_sdk"
+ name: "condense_configuration_change_for_simple_mode"
+ description: "Condense configuration change for simple mode"
+ bug: "356738240"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 9bd52372e6c4..39ddea614ee4 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -25,6 +25,8 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED
import static android.security.Flags.reportPrimaryAuthAttempts;
import static android.security.Flags.shouldTrustManagerListenForPrimaryAuth;
+import static com.android.internal.widget.flags.Flags.hideLastCharWithPhysicalInput;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -42,6 +44,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.hardware.input.InputManagerGlobal;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
@@ -59,6 +62,7 @@ import android.util.Log;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
+import android.view.InputDevice;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
@@ -1097,12 +1101,20 @@ public class LockPatternUtils {
return type == CREDENTIAL_TYPE_PATTERN;
}
+ private boolean hasActivePointerDeviceAttached() {
+ return !getEnabledNonTouchInputDevices(InputDevice.SOURCE_CLASS_POINTER).isEmpty();
+ }
+
/**
* @return Whether the visible pattern is enabled.
*/
@UnsupportedAppUsage
public boolean isVisiblePatternEnabled(int userId) {
- return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, true, userId);
+ boolean defaultValue = true;
+ if (hideLastCharWithPhysicalInput()) {
+ defaultValue = !hasActivePointerDeviceAttached();
+ }
+ return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, defaultValue, userId);
}
/**
@@ -1116,11 +1128,39 @@ public class LockPatternUtils {
return getString(Settings.Secure.LOCK_PATTERN_VISIBLE, userId) != null;
}
+ private List<InputDevice> getEnabledNonTouchInputDevices(int source) {
+ final InputManagerGlobal inputManager = InputManagerGlobal.getInstance();
+ final int[] inputIds = inputManager.getInputDeviceIds();
+ List<InputDevice> matchingDevices = new ArrayList<InputDevice>();
+ for (final int deviceId : inputIds) {
+ final InputDevice inputDevice = inputManager.getInputDevice(deviceId);
+ if (!inputDevice.isEnabled()) continue;
+ if (inputDevice.supportsSource(InputDevice.SOURCE_TOUCHSCREEN)) continue;
+ if (inputDevice.isVirtual()) continue;
+ if (!inputDevice.supportsSource(source)) continue;
+ matchingDevices.add(inputDevice);
+ }
+ return matchingDevices;
+ }
+
+ private boolean hasPhysicalKeyboardActive() {
+ final List<InputDevice> keyboards =
+ getEnabledNonTouchInputDevices(InputDevice.SOURCE_KEYBOARD);
+ for (final InputDevice keyboard : keyboards) {
+ if (keyboard.isFullKeyboard()) return true;
+ }
+ return false;
+ }
+
/**
* @return Whether enhanced pin privacy is enabled.
*/
public boolean isPinEnhancedPrivacyEnabled(int userId) {
- return getBoolean(LOCK_PIN_ENHANCED_PRIVACY, false, userId);
+ boolean defaultValue = false;
+ if (hideLastCharWithPhysicalInput()) {
+ defaultValue = hasPhysicalKeyboardActive();
+ }
+ return getBoolean(LOCK_PIN_ENHANCED_PRIVACY, defaultValue, userId);
}
/**
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 027113a75f6b..5acdf32a9f84 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -482,11 +482,22 @@ cc_library_shared_for_libandroid_runtime {
"libbinder",
"libhidlbase", // libhwbinder is in here
],
+ version_script: "platform/linux/libandroid_runtime_export.txt",
+ },
+ darwin: {
+ host_ldlibs: [
+ "-framework AppKit",
+ ],
+ dist: {
+ targets: ["layoutlib_jni"],
+ dir: "layoutlib_native/darwin",
+ },
+ exported_symbols_list: "platform/darwin/libandroid_runtime_export.exp",
},
linux_glibc_x86_64: {
ldflags: ["-static-libgcc"],
dist: {
- targets: ["layoutlib"],
+ targets: ["layoutlib_jni"],
dir: "layoutlib_native/linux",
tag: "stripped_all",
},
diff --git a/core/jni/platform/darwin/libandroid_runtime_export.exp b/core/jni/platform/darwin/libandroid_runtime_export.exp
new file mode 100644
index 000000000000..00a7585719ea
--- /dev/null
+++ b/core/jni/platform/darwin/libandroid_runtime_export.exp
@@ -0,0 +1,38 @@
+#
+# 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.
+#
+
+# symbols needed for the JNI operations
+_JNI_OnLoad
+_ANativeWindow*
+
+# symbols needed to link with layoutlib_jni
+___android_log*
+__ZNK7android7RefBase*
+__ZN7android4base9SetLogger*
+__ZN7android4base10SetAborter*
+__ZN7android4base11GetProperty*
+__ZN7android4Rect*
+__ZN7android5Fence*
+__ZN7android7RefBase*
+__ZN7android7String*
+__ZN7android10VectorImpl*
+__ZN7android11BufferQueue*
+__ZN7android14AndroidRuntime*
+__ZN7android14sp_report_raceEv*
+__ZN7android15KeyCharacterMap*
+__ZN7android15InputDeviceInfo*
+__ZN7android31android_view_InputDevice_create*
+__ZN7android53android_view_Surface_createFromIGraphicBufferProducer*
diff --git a/core/jni/platform/linux/libandroid_runtime_export.txt b/core/jni/platform/linux/libandroid_runtime_export.txt
new file mode 100644
index 000000000000..19e3478d5d38
--- /dev/null
+++ b/core/jni/platform/linux/libandroid_runtime_export.txt
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+{
+ global:
+ # symbols needed for the JNI operations
+ JNI_OnLoad;
+ ANativeWindow*;
+
+ # symbols needed to link with layoutlib_jni
+ __android_log*;
+ _ZNK7android7RefBase*;
+ _ZN7android4base9SetLogger*;
+ _ZN7android4base10SetAborter*;
+ _ZN7android4base11GetProperty*;
+ _ZN7android4Rect*;
+ _ZN7android5Fence*;
+ _ZN7android7RefBase*;
+ _ZN7android7String*;
+ _ZN7android10VectorImpl*;
+ _ZN7android11BufferQueue*;
+ _ZN7android14AndroidRuntime*;
+ _ZN7android14sp_report_raceEv*;
+ _ZN7android15KeyCharacterMap*;
+ _ZN7android15InputDeviceInfo*;
+ _ZN7android31android_view_InputDevice_create*;
+ _ZN7android53android_view_Surface_createFromIGraphicBufferProducer*;
+ local:
+ *;
+};
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index e28b6462bad7..e6295ea06177 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -100,4 +100,7 @@
<!-- Whether to enable scaling and fading animation to scrollviews while scrolling.
P.S this is a change only intended for wear devices. -->
<bool name="config_enableViewGroupScalingFading">true</bool>
+
+ <!-- Allow the gesture to double tap the power button to trigger a target action. -->
+ <bool name="config_doubleTapPowerGestureEnabled">false</bool>
</resources>
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 9effeec23890..ca6ad6fae46e 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -105,6 +105,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.R;
import com.android.internal.util.ContrastColorUtil;
+import com.android.internal.widget.NotificationProgressModel;
import junit.framework.Assert;
@@ -2414,7 +2415,7 @@ public class NotificationTest {
@Test
@EnableFlags(Flags.FLAG_API_RICH_ONGOING)
- public void progressStyle_getProgressMax_nooSegments_returnsDefault() {
+ public void progressStyle_getProgressMax_noSegments_returnsDefault() {
final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
progressStyle.setProgressSegments(Collections.emptyList());
assertThat(progressStyle.getProgressMax()).isEqualTo(100);
@@ -2459,6 +2460,211 @@ public class NotificationTest {
@Test
@EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+ public void progressStyle_getProgressMax_onSegmentLimitExceeded_returnsSumOfSegmentLength() {
+ // GIVEN
+ final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
+ // limit is 10 for ProgressStyle
+ for (int i = 0; i < 30; i++) {
+ progressStyle
+ .addProgressSegment(new Notification.ProgressStyle.Segment(10));
+ }
+
+ // THEN
+ assertThat(progressStyle.getProgressMax()).isEqualTo(300);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+ public void progressStyle_addProgressSegment_dropsInvalidSegments() {
+ // GIVEN
+ final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
+ // Segments should be a positive integer.
+ progressStyle
+ .addProgressSegment(new Notification.ProgressStyle.Segment(0));
+ progressStyle
+ .addProgressSegment(new Notification.ProgressStyle.Segment(-1));
+
+ // THEN
+ assertThat(progressStyle.getProgressSegments()).isEmpty();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+ public void progressStyle_setProgressSegment_dropsInvalidSegments() {
+ // GIVEN
+ final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
+ // Segments should be a positive integer.
+ progressStyle
+ .setProgressSegments(List.of(new Notification.ProgressStyle.Segment(0),
+ new Notification.ProgressStyle.Segment(-1)));
+
+ // THEN
+ assertThat(progressStyle.getProgressSegments()).isEmpty();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+ public void progressStyle_addProgressPoint_dropsNegativePoints() {
+ // GIVEN
+ final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
+ // Points should not be a negative integer.
+ progressStyle
+ .addProgressPoint(new Notification.ProgressStyle.Point(-1))
+ .addProgressPoint(new Notification.ProgressStyle.Point(-100));
+
+ // THEN
+ assertThat(progressStyle.getProgressPoints()).isEmpty();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+ public void progressStyle_setProgressPoint_dropsNegativePoints() {
+ // GIVEN
+ final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
+ // Points should not be a negative integer.
+ progressStyle
+ .setProgressPoints(List.of(new Notification.ProgressStyle.Point(-1),
+ new Notification.ProgressStyle.Point(-100)));
+
+ // THEN
+ assertThat(progressStyle.getProgressPoints()).isEmpty();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+ public void progressStyle_createProgressModel_ignoresPointsExceedingMax() {
+ // GIVEN
+ final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
+ progressStyle.addProgressSegment(new Notification.ProgressStyle.Segment(100));
+ // Points should not larger than progress maximum.
+ progressStyle
+ .addProgressPoint(new Notification.ProgressStyle.Point(101))
+ .addProgressPoint(new Notification.ProgressStyle.Point(500));
+
+ // THEN
+ assertThat(progressStyle.createProgressModel(Color.BLUE, Color.RED).getPoints()).isEmpty();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+ public void progressStyle_createProgressModel_ignoresOverLimitPoints() {
+ // GIVEN
+ final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
+ progressStyle.addProgressSegment(new Notification.ProgressStyle.Segment(100));
+
+ // maximum 4 points are going to be rendered.
+ progressStyle
+ .addProgressPoint(new Notification.ProgressStyle.Point(0))
+ .addProgressPoint(new Notification.ProgressStyle.Point(20))
+ .addProgressPoint(new Notification.ProgressStyle.Point(150))
+ .addProgressPoint(new Notification.ProgressStyle.Point(50))
+ .addProgressPoint(new Notification.ProgressStyle.Point(70))
+ .addProgressPoint(new Notification.ProgressStyle.Point(80))
+ .addProgressPoint(new Notification.ProgressStyle.Point(90))
+ .addProgressPoint(new Notification.ProgressStyle.Point(95))
+ .addProgressPoint(new Notification.ProgressStyle.Point(100));
+ final int backgroundColor = Color.RED;
+ final int defaultProgressColor = Color.BLUE;
+ final int expectedProgressColor = Notification.ProgressStyle.sanitizeProgressColor(
+ /* color = */Notification.COLOR_DEFAULT,
+ /* bg = */backgroundColor,
+ /* defaultColor = */defaultProgressColor);
+
+ // THEN
+ assertThat(progressStyle.createProgressModel(defaultProgressColor, backgroundColor)
+ .getPoints()).isEqualTo(
+ List.of(new Notification.ProgressStyle.Point(0)
+ .setColor(expectedProgressColor),
+ new Notification.ProgressStyle.Point(20)
+ .setColor(expectedProgressColor),
+ new Notification.ProgressStyle.Point(50)
+ .setColor(expectedProgressColor),
+ new Notification.ProgressStyle.Point(70)
+ .setColor(expectedProgressColor)
+ )
+ );
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+ public void progressStyle_createProgressModel_mergeSegmentsOnOverflow() {
+ // GIVEN
+ final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
+
+ for (int i = 0; i < 15; i++) {
+ progressStyle
+ .addProgressSegment(new Notification.ProgressStyle.Segment(10));
+ }
+
+ final NotificationProgressModel progressModel = progressStyle.createProgressModel(
+ Color.BLUE, Color.RED);
+
+ // THEN
+ assertThat(progressModel.getSegments().size()).isEqualTo(1);
+ assertThat(progressModel.getProgressMax()).isEqualTo(150);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+ public void progressStyle_createProgressModel_useSegmentColorWhenAllMatch() {
+ // GIVEN
+ final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
+ final int segmentColor = Color.YELLOW;
+ final int defaultProgressColor = Color.BLUE;
+ final int backgroundColor = Color.RED;
+ // contrast ensured color for segmentColor.
+ final int expectedSegmentColor = Notification.ProgressStyle.sanitizeProgressColor(
+ /* color = */ segmentColor,
+ /* bg = */ backgroundColor,
+ /* defaultColor = */ defaultProgressColor);
+
+ for (int i = 0; i < 15; i++) {
+ progressStyle
+ .addProgressSegment(new Notification.ProgressStyle.Segment(10)
+ .setColor(segmentColor));
+ }
+
+ final NotificationProgressModel progressModel = progressStyle.createProgressModel(
+ defaultProgressColor, backgroundColor);
+
+ // THEN
+ assertThat(progressModel.getSegments())
+ .isEqualTo(List.of(new Notification.ProgressStyle.Segment(150)
+ .setColor(expectedSegmentColor)));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+ public void progressStyle_createProgressModel_useDefaultColorWhenAllNotMatch() {
+ // GIVEN
+ final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle();
+ final int defaultProgressColor = Color.BLUE;
+ final int backgroundColor = Color.RED;
+ // contrast ensured color for default progress color.
+ final int expectedSegmentColor = Notification.ProgressStyle.sanitizeProgressColor(
+ /* color = */ defaultProgressColor,
+ /* bg = */ backgroundColor,
+ /* defaultColor = */ defaultProgressColor);
+
+ for (int i = 0; i < 15; i++) {
+ progressStyle
+ .addProgressSegment(new Notification.ProgressStyle.Segment(5)
+ .setColor(Color.BLUE))
+ .addProgressSegment(new Notification.ProgressStyle.Segment(5)
+ .setColor(Color.CYAN));
+ }
+
+ final NotificationProgressModel progressModel = progressStyle.createProgressModel(
+ defaultProgressColor, backgroundColor);
+
+ // THEN
+ assertThat(progressModel.getSegments())
+ .isEqualTo(List.of(new Notification.ProgressStyle.Segment(150)
+ .setColor(expectedSegmentColor)));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
public void progressStyle_indeterminate_defaultValueFalse() {
final Notification.ProgressStyle progressStyle1 = new Notification.ProgressStyle();
diff --git a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt
index 4a227d8ff1ef..255d09b854bd 100644
--- a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt
+++ b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt
@@ -86,7 +86,7 @@ class DisplayTopologyTest {
verifyDisplay(display1, displayId1, width1, height1, noOfChildren = 1)
val display2 = display1.children[0]
- verifyDisplay(display1.children[0], displayId2, width2, height2, POSITION_TOP,
+ verifyDisplay(display2, displayId2, width2, height2, POSITION_TOP,
offset = width1 / 2 - width2 / 2, noOfChildren = 1)
var display = display2
@@ -99,6 +99,76 @@ class DisplayTopologyTest {
}
@Test
+ fun updateDisplay() {
+ val displayId = 1
+ val width = 800f
+ val height = 600f
+
+ val newWidth = 1000f
+ val newHeight = 500f
+ topology.addDisplay(displayId, width, height)
+ assertThat(topology.updateDisplay(displayId, newWidth, newHeight)).isTrue()
+
+ assertThat(topology.primaryDisplayId).isEqualTo(displayId)
+ verifyDisplay(topology.root!!, displayId, newWidth, newHeight, noOfChildren = 0)
+ }
+
+ @Test
+ fun updateDisplay_notUpdated() {
+ val displayId = 1
+ val width = 800f
+ val height = 600f
+ topology.addDisplay(displayId, width, height)
+
+ // Same size
+ assertThat(topology.updateDisplay(displayId, width, height)).isFalse()
+
+ // Display doesn't exist
+ assertThat(topology.updateDisplay(/* displayId= */ 100, width, height)).isFalse()
+
+ assertThat(topology.primaryDisplayId).isEqualTo(displayId)
+ verifyDisplay(topology.root!!, displayId, width, height, noOfChildren = 0)
+ }
+
+ @Test
+ fun updateDisplayDoesNotAffectDefaultTopology() {
+ val width1 = 700f
+ val height = 600f
+ topology.addDisplay(/* displayId= */ 1, width1, height)
+
+ val width2 = 800f
+ val noOfDisplays = 30
+ for (i in 2..noOfDisplays) {
+ topology.addDisplay(/* displayId= */ i, width2, height)
+ }
+
+ val displaysToUpdate = arrayOf(3, 7, 18)
+ val newWidth = 1000f
+ val newHeight = 1500f
+ for (i in displaysToUpdate) {
+ assertThat(topology.updateDisplay(/* displayId= */ i, newWidth, newHeight)).isTrue()
+ }
+
+ assertThat(topology.primaryDisplayId).isEqualTo(1)
+
+ val display1 = topology.root!!
+ verifyDisplay(display1, id = 1, width1, height, noOfChildren = 1)
+
+ val display2 = display1.children[0]
+ verifyDisplay(display2, id = 2, width2, height, POSITION_TOP,
+ offset = width1 / 2 - width2 / 2, noOfChildren = 1)
+
+ var display = display2
+ for (i in 3..noOfDisplays) {
+ display = display.children[0]
+ // The last display should have no children
+ verifyDisplay(display, id = i, if (i in displaysToUpdate) newWidth else width2,
+ if (i in displaysToUpdate) newHeight else height, POSITION_RIGHT, offset = 0f,
+ noOfChildren = if (i < noOfDisplays) 1 else 0)
+ }
+ }
+
+ @Test
fun removeDisplays() {
val displayId1 = 1
val width1 = 800f
@@ -117,7 +187,7 @@ class DisplayTopologyTest {
}
var removedDisplays = arrayOf(20)
- topology.removeDisplay(20)
+ assertThat(topology.removeDisplay(20)).isTrue()
assertThat(topology.primaryDisplayId).isEqualTo(displayId1)
@@ -139,11 +209,11 @@ class DisplayTopologyTest {
noOfChildren = if (i < noOfDisplays) 1 else 0)
}
- topology.removeDisplay(22)
+ assertThat(topology.removeDisplay(22)).isTrue()
removedDisplays += 22
- topology.removeDisplay(23)
+ assertThat(topology.removeDisplay(23)).isTrue()
removedDisplays += 23
- topology.removeDisplay(25)
+ assertThat(topology.removeDisplay(25)).isTrue()
removedDisplays += 25
assertThat(topology.primaryDisplayId).isEqualTo(displayId1)
@@ -174,7 +244,7 @@ class DisplayTopologyTest {
val height = 600f
topology.addDisplay(displayId, width, height)
- topology.removeDisplay(displayId)
+ assertThat(topology.removeDisplay(displayId)).isTrue()
assertThat(topology.primaryDisplayId).isEqualTo(Display.INVALID_DISPLAY)
assertThat(topology.root).isNull()
@@ -187,7 +257,7 @@ class DisplayTopologyTest {
val height = 600f
topology.addDisplay(displayId, width, height)
- topology.removeDisplay(3)
+ assertThat(topology.removeDisplay(3)).isFalse()
assertThat(topology.primaryDisplayId).isEqualTo(displayId)
verifyDisplay(topology.root!!, displayId, width, height, noOfChildren = 0)
@@ -203,7 +273,7 @@ class DisplayTopologyTest {
topology = DisplayTopology(/* root= */ null, displayId2)
topology.addDisplay(displayId1, width, height)
topology.addDisplay(displayId2, width, height)
- topology.removeDisplay(displayId2)
+ assertThat(topology.removeDisplay(displayId2)).isTrue()
assertThat(topology.primaryDisplayId).isEqualTo(displayId1)
verifyDisplay(topology.root!!, displayId1, width, height, noOfChildren = 0)
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index ed9fc1c9e547..18ab52dba8f3 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -25,7 +25,7 @@ import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH_HINT;
import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
-import static android.view.Surface.FRAME_RATE_COMPATIBILITY_GTE;
+import static android.view.Surface.FRAME_RATE_COMPATIBILITY_AT_LEAST;
import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
@@ -861,10 +861,10 @@ public class ViewRootImplTest {
assertEquals(mViewRootImpl.getFrameRateCompatibility(),
FRAME_RATE_COMPATIBILITY_FIXED_SOURCE);
assertFalse(mViewRootImpl.isFrameRateConflicted());
- mViewRootImpl.votePreferredFrameRate(24, FRAME_RATE_COMPATIBILITY_GTE);
+ mViewRootImpl.votePreferredFrameRate(24, FRAME_RATE_COMPATIBILITY_AT_LEAST);
if (toolkitFrameRateVelocityMappingReadOnly()) {
assertEquals(24, mViewRootImpl.getPreferredFrameRate(), 0.1);
- assertEquals(FRAME_RATE_COMPATIBILITY_GTE,
+ assertEquals(FRAME_RATE_COMPATIBILITY_AT_LEAST,
mViewRootImpl.getFrameRateCompatibility());
assertFalse(mViewRootImpl.isFrameRateConflicted());
} else {
@@ -888,10 +888,10 @@ public class ViewRootImplTest {
sInstrumentation.runOnMainSync(() -> {
assertFalse(mViewRootImpl.isFrameRateConflicted());
- mViewRootImpl.votePreferredFrameRate(60, FRAME_RATE_COMPATIBILITY_GTE);
+ mViewRootImpl.votePreferredFrameRate(60, FRAME_RATE_COMPATIBILITY_AT_LEAST);
if (toolkitFrameRateVelocityMappingReadOnly()) {
assertEquals(60, mViewRootImpl.getPreferredFrameRate(), 0.1);
- assertEquals(FRAME_RATE_COMPATIBILITY_GTE,
+ assertEquals(FRAME_RATE_COMPATIBILITY_AT_LEAST,
mViewRootImpl.getFrameRateCompatibility());
} else {
assertEquals(FRAME_RATE_CATEGORY_HIGH,
@@ -904,7 +904,7 @@ public class ViewRootImplTest {
mViewRootImpl.getFrameRateCompatibility());
// Should be false since 60 is a divisor of 120.
assertFalse(mViewRootImpl.isFrameRateConflicted());
- mViewRootImpl.votePreferredFrameRate(60, FRAME_RATE_COMPATIBILITY_GTE);
+ mViewRootImpl.votePreferredFrameRate(60, FRAME_RATE_COMPATIBILITY_AT_LEAST);
assertEquals(120, mViewRootImpl.getPreferredFrameRate(), 0.1);
// compatibility should be remained the same (FRAME_RATE_COMPATIBILITY_FIXED_SOURCE)
// since the frame rate 60 is smaller than 120.
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
index 00b4f464de50..d1fbc77cbd46 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
@@ -31,6 +31,7 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doNothing;
@@ -44,20 +45,27 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.UserInfo;
+import android.hardware.input.IInputManager;
+import android.hardware.input.InputManagerGlobal;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.platform.test.ravenwood.RavenwoodRule;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
+import android.view.InputDevice;
import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.internal.widget.flags.Flags;
import com.google.android.collect.Lists;
@@ -76,6 +84,8 @@ import java.util.concurrent.CompletableFuture;
public class LockPatternUtilsTest {
@Rule
public final RavenwoodRule mRavenwood = new RavenwoodRule();
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private ILockSettings mLockSettings;
private static final int USER_ID = 1;
@@ -395,4 +405,156 @@ public class LockPatternUtilsTest {
}
};
}
+
+ private InputManagerGlobal.TestSession configureExternalHardwareTest(InputDevice[] devices)
+ throws RemoteException {
+ final Context context = new ContextWrapper(InstrumentationRegistry.getTargetContext());
+ final ILockSettings ils = mock(ILockSettings.class);
+ when(ils.getBoolean(anyString(), anyBoolean(), anyInt())).thenThrow(RemoteException.class);
+ mLockPatternUtils = new LockPatternUtils(context, ils);
+
+ IInputManager inputManagerMock = mock(IInputManager.class);
+
+ int[] deviceIds = new int[devices.length];
+
+ for (int i = 0; i < devices.length; i++) {
+ when(inputManagerMock.getInputDevice(i)).thenReturn(devices[i]);
+ }
+
+ when(inputManagerMock.getInputDeviceIds()).thenReturn(deviceIds);
+ InputManagerGlobal.TestSession session =
+ InputManagerGlobal.createTestSession(inputManagerMock);
+
+ return session;
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
+ public void isPinEnhancedPrivacyEnabled_noDevicesAttached() throws RemoteException {
+ InputManagerGlobal.TestSession session = configureExternalHardwareTest(new InputDevice[0]);
+ assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID));
+ session.close();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
+ public void isPinEnhancedPrivacyEnabled_noEnabledDeviceAttached() throws RemoteException {
+ InputDevice.Builder builder = new InputDevice.Builder();
+ builder.setEnabled(false);
+ InputManagerGlobal.TestSession session =
+ configureExternalHardwareTest(new InputDevice[]{builder.build()});
+ assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID));
+ session.close();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
+ public void isPinEnhancedPrivacyEnabled_withoutHwKeyboard() throws RemoteException {
+ InputDevice.Builder builder = new InputDevice.Builder();
+ builder.setEnabled(true).setSources(InputDevice.SOURCE_TOUCHSCREEN);
+ InputManagerGlobal.TestSession session =
+ configureExternalHardwareTest(new InputDevice[]{builder.build()});
+ assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID));
+ session.close();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
+ public void isPinEnhancedPrivacyEnabled_withoutFullHwKeyboard() throws RemoteException {
+ InputDevice.Builder builder = new InputDevice.Builder();
+ builder
+ .setEnabled(true)
+ .setSources(InputDevice.SOURCE_KEYBOARD)
+ .setKeyboardType(InputDevice.KEYBOARD_TYPE_NON_ALPHABETIC);
+ InputManagerGlobal.TestSession session =
+ configureExternalHardwareTest(new InputDevice[]{builder.build()});
+ assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID));
+ session.close();
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
+ public void isPinEnhancedPrivacyEnabled_withHwKeyboardOldDefault() throws RemoteException {
+ InputDevice.Builder builder = new InputDevice.Builder();
+ builder
+ .setEnabled(true)
+ .setSources(InputDevice.SOURCE_KEYBOARD)
+ .setKeyboardType(InputDevice.KEYBOARD_TYPE_ALPHABETIC);
+ InputManagerGlobal.TestSession session =
+ configureExternalHardwareTest(new InputDevice[]{builder.build()});
+ assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID));
+ session.close();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
+ public void isPinEnhancedPrivacyEnabled_withHwKeyboard() throws RemoteException {
+ InputDevice.Builder builder = new InputDevice.Builder();
+ builder
+ .setEnabled(true)
+ .setSources(InputDevice.SOURCE_KEYBOARD)
+ .setKeyboardType(InputDevice.KEYBOARD_TYPE_ALPHABETIC);
+ InputManagerGlobal.TestSession session =
+ configureExternalHardwareTest(new InputDevice[]{builder.build()});
+ assertTrue(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID));
+ session.close();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
+ public void isVisiblePatternEnabled_noDevices() throws RemoteException {
+ InputManagerGlobal.TestSession session = configureExternalHardwareTest(new InputDevice[0]);
+ assertTrue(mLockPatternUtils.isVisiblePatternEnabled(USER_ID));
+ session.close();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
+ public void isVisiblePatternEnabled_noEnabledDevices() throws RemoteException {
+ InputDevice.Builder builder = new InputDevice.Builder();
+ builder.setEnabled(false);
+ InputManagerGlobal.TestSession session =
+ configureExternalHardwareTest(new InputDevice[]{builder.build()});
+ assertTrue(mLockPatternUtils.isVisiblePatternEnabled(USER_ID));
+ session.close();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
+ public void isVisiblePatternEnabled_noPointingDevices() throws RemoteException {
+ InputDevice.Builder builder = new InputDevice.Builder();
+ builder
+ .setEnabled(true)
+ .setSources(InputDevice.SOURCE_TOUCHSCREEN);
+ InputManagerGlobal.TestSession session =
+ configureExternalHardwareTest(new InputDevice[]{builder.build()});
+ assertTrue(mLockPatternUtils.isVisiblePatternEnabled(USER_ID));
+ session.close();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
+ public void isVisiblePatternEnabled_externalPointingDevice() throws RemoteException {
+ InputDevice.Builder builder = new InputDevice.Builder();
+ builder
+ .setEnabled(true)
+ .setSources(InputDevice.SOURCE_CLASS_POINTER);
+ InputManagerGlobal.TestSession session =
+ configureExternalHardwareTest(new InputDevice[]{builder.build()});
+ assertFalse(mLockPatternUtils.isVisiblePatternEnabled(USER_ID));
+ session.close();
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
+ public void isVisiblePatternEnabled_externalPointingDeviceOldDefault() throws RemoteException {
+ InputDevice.Builder builder = new InputDevice.Builder();
+ builder
+ .setEnabled(true)
+ .setSources(InputDevice.SOURCE_CLASS_POINTER);
+ InputManagerGlobal.TestSession session =
+ configureExternalHardwareTest(new InputDevice[]{builder.build()});
+ assertTrue(mLockPatternUtils.isVisiblePatternEnabled(USER_ID));
+ session.close();
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 21c44c9b92ee..4bcec702281d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -571,9 +571,9 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
// For flexible split, expand app offscreen as well
if (mDividerSnapAlgorithm.areOffscreenRatiosSupported()) {
if (position <= mDividerSnapAlgorithm.getMiddleTarget().position) {
- bounds1.top = bounds1.bottom - bounds2.width();
+ bounds1.top = bounds1.bottom - bounds2.height();
} else {
- bounds2.bottom = bounds2.top + bounds1.width();
+ bounds2.bottom = bounds2.top + bounds1.height();
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
index dfa2d9b6bb63..9a60cfeed7c1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
@@ -38,6 +38,7 @@ import androidx.core.util.putAll
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON
@@ -236,6 +237,7 @@ class DesktopModeLoggerTransitionObserver(
) {
// Sessions is finishing, log task updates followed by an exit event
identifyAndLogTaskUpdates(
+ transitionInfo,
preTransitionVisibleFreeformTasks,
postTransitionVisibleFreeformTasks,
)
@@ -252,12 +254,14 @@ class DesktopModeLoggerTransitionObserver(
desktopModeEventLogger.logSessionEnter(getEnterReason(transitionInfo))
identifyAndLogTaskUpdates(
+ transitionInfo,
preTransitionVisibleFreeformTasks,
postTransitionVisibleFreeformTasks,
)
} else if (isSessionActive) {
// Session is neither starting, nor finishing, log task updates if there are any
identifyAndLogTaskUpdates(
+ transitionInfo,
preTransitionVisibleFreeformTasks,
postTransitionVisibleFreeformTasks,
)
@@ -270,6 +274,7 @@ class DesktopModeLoggerTransitionObserver(
/** Compare the old and new state of taskInfos and identify and log the changes */
private fun identifyAndLogTaskUpdates(
+ transitionInfo: TransitionInfo,
preTransitionVisibleFreeformTasks: SparseArray<TaskInfo>,
postTransitionVisibleFreeformTasks: SparseArray<TaskInfo>,
) {
@@ -304,9 +309,19 @@ class DesktopModeLoggerTransitionObserver(
// find old tasks that were removed
preTransitionVisibleFreeformTasks.forEach { taskId, taskInfo ->
if (!postTransitionVisibleFreeformTasks.containsKey(taskId)) {
- desktopModeEventLogger.logTaskRemoved(
- buildTaskUpdateForTask(taskInfo, postTransitionVisibleFreeformTasks.size())
- )
+ val minimizeReason =
+ if (transitionInfo.type == Transitions.TRANSIT_MINIMIZE) {
+ MinimizeReason.MINIMIZE_BUTTON
+ } else {
+ null
+ }
+ val taskUpdate =
+ buildTaskUpdateForTask(
+ taskInfo,
+ postTransitionVisibleFreeformTasks.size(),
+ minimizeReason,
+ )
+ desktopModeEventLogger.logTaskRemoved(taskUpdate)
Trace.setCounter(
Trace.TRACE_TAG_WINDOW_MANAGER,
VISIBLE_TASKS_COUNTER_NAME,
@@ -320,7 +335,11 @@ class DesktopModeLoggerTransitionObserver(
}
}
- private fun buildTaskUpdateForTask(taskInfo: TaskInfo, visibleTasks: Int): TaskUpdate {
+ private fun buildTaskUpdateForTask(
+ taskInfo: TaskInfo,
+ visibleTasks: Int,
+ minimizeReason: MinimizeReason? = null,
+ ): TaskUpdate {
val screenBounds = taskInfo.configuration.windowConfiguration.bounds
val positionInParent = taskInfo.positionInParent
return TaskUpdate(
@@ -331,6 +350,7 @@ class DesktopModeLoggerTransitionObserver(
taskX = positionInParent.x,
taskY = positionInParent.y,
visibleTaskCount = visibleTasks,
+ minimizeReason = minimizeReason,
)
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
index 606a729305b4..90191345147c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
@@ -82,7 +82,7 @@ fun calculateInitialBounds(
// For portrait resizeable activities, respect apps fullscreen width but
// apply ideal size height.
Size(
- taskInfo.appCompatTaskInfo.topActivityLetterboxAppWidth,
+ taskInfo.appCompatTaskInfo.topActivityAppBounds.width(),
idealSize.height,
)
} else {
@@ -104,7 +104,7 @@ fun calculateInitialBounds(
// apply custom app width.
Size(
customPortraitWidthForLandscapeApp,
- taskInfo.appCompatTaskInfo.topActivityLetterboxAppHeight,
+ taskInfo.appCompatTaskInfo.topActivityAppBounds.height(),
)
} else {
// For portrait resizeable activities, simply apply ideal size.
@@ -196,13 +196,8 @@ fun maximizeSizeGivenAspectRatio(
/** Calculates the aspect ratio of an activity from its fullscreen bounds. */
fun calculateAspectRatio(taskInfo: RunningTaskInfo): Float {
- val appLetterboxWidth = taskInfo.appCompatTaskInfo.topActivityLetterboxAppWidth
- val appLetterboxHeight = taskInfo.appCompatTaskInfo.topActivityLetterboxAppHeight
- if (taskInfo.appCompatTaskInfo.isTopActivityLetterboxed || !taskInfo.canChangeAspectRatio) {
- return maxOf(appLetterboxWidth, appLetterboxHeight) /
- minOf(appLetterboxWidth, appLetterboxHeight).toFloat()
- }
- val appBounds = taskInfo.configuration.windowConfiguration.appBounds ?: return 1f
+ if (taskInfo.appCompatTaskInfo.topActivityAppBounds.isEmpty) return 1f
+ val appBounds = taskInfo.appCompatTaskInfo.topActivityAppBounds
return maxOf(appBounds.height(), appBounds.width()) /
minOf(appBounds.height(), appBounds.width()).toFloat()
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
index 37296531ee34..fd387d1811fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
@@ -350,7 +350,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
}
cancelPhysicsAnimation();
mMenuController.hideMenu(ANIM_TYPE_DISMISS, false /* resize */);
- mPipScheduler.scheduleRemovePip();
+ mPipScheduler.removePipAfterAnimation();
}
/** Sets the movement bounds to use to constrain PIP position animations. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index 7f673d2efc68..4461a5c6a70c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -122,26 +122,34 @@ public class PipScheduler {
* Schedules exit PiP via expand transition.
*/
public void scheduleExitPipViaExpand() {
- mMainExecutor.execute(() -> {
- if (!mPipTransitionState.isInPip()) return;
- WindowContainerTransaction wct = getExitPipViaExpandTransaction();
- if (wct != null) {
+ WindowContainerTransaction wct = getExitPipViaExpandTransaction();
+ if (wct != null) {
+ mMainExecutor.execute(() -> {
mPipTransitionController.startExitTransition(TRANSIT_EXIT_PIP, wct,
null /* destinationBounds */);
- }
- });
+ });
+ }
+ }
+
+ // TODO: Optimize this by running the animation as part of the transition
+ /** Runs remove PiP animation and schedules remove PiP transition after the animation ends. */
+ public void removePipAfterAnimation() {
+ SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
+ PipAlphaAnimator animator = mPipAlphaAnimatorSupplier.get(mContext,
+ mPipTransitionState.getPinnedTaskLeash(), tx, PipAlphaAnimator.FADE_OUT);
+ animator.setAnimationEndCallback(this::scheduleRemovePipImmediately);
+ animator.start();
}
/** Schedules remove PiP transition. */
- public void scheduleRemovePip() {
- mMainExecutor.execute(() -> {
- if (!mPipTransitionState.isInPip()) return;
- WindowContainerTransaction wct = getRemovePipTransaction();
- if (wct != null) {
+ private void scheduleRemovePipImmediately() {
+ WindowContainerTransaction wct = getRemovePipTransaction();
+ if (wct != null) {
+ mMainExecutor.execute(() -> {
mPipTransitionController.startExitTransition(TRANSIT_REMOVE_PIP, wct,
null /* destinationBounds */);
- }
- });
+ });
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 2e38449d4584..acb5622b041c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -278,8 +278,7 @@ public class PipTransition extends PipTransitionController implements
}
if (isRemovePipTransition(info)) {
- mPipTransitionState.setState(PipTransitionState.EXITING_PIP);
- return startRemoveAnimation(info, startTransaction, finishTransaction, finishCallback);
+ return removePipImmediately(info, startTransaction, finishTransaction, finishCallback);
}
return false;
}
@@ -669,18 +668,13 @@ public class PipTransition extends PipTransitionController implements
return true;
}
- private boolean startRemoveAnimation(@NonNull TransitionInfo info,
+ private boolean removePipImmediately(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- TransitionInfo.Change pipChange = getChangeByToken(info,
- mPipTransitionState.getPipTaskToken());
- mFinishCallback = finishCallback;
- PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipChange.getLeash(),
- startTransaction, PipAlphaAnimator.FADE_OUT);
- finishTransaction.setAlpha(pipChange.getLeash(), 0f);
- animator.setAnimationEndCallback(this::finishTransition);
- animator.start();
+ startTransaction.apply();
+ finishCallback.onTransitionFinished(null);
+ mPipTransitionState.setState(PipTransitionState.EXITED_PIP);
return true;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
index 43684fb92b64..0154ff31c989 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
@@ -46,6 +46,7 @@ import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON
@@ -566,7 +567,10 @@ class DesktopModeLoggerTransitionObserverTest : ShellTestCase() {
assertFalse(transitionObserver.isSessionActive)
verify(desktopModeEventLogger, times(1)).logSessionExit(eq(ExitReason.TASK_MINIMIZED))
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(DEFAULT_TASK_UPDATE))
+ verify(desktopModeEventLogger, times(1))
+ .logTaskRemoved(
+ eq(DEFAULT_TASK_UPDATE.copy(minimizeReason = MinimizeReason.MINIMIZE_BUTTON))
+ )
verifyZeroInteractions(desktopModeEventLogger)
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 4f37180baa37..e1c2153014fa 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -4160,8 +4160,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
screenOrientation = SCREEN_ORIENTATION_LANDSCAPE
configuration.windowConfiguration.appBounds = bounds
}
- appCompatTaskInfo.topActivityLetterboxAppWidth = bounds.width()
- appCompatTaskInfo.topActivityLetterboxAppHeight = bounds.height()
+ appCompatTaskInfo.topActivityAppBounds.set(0, 0, bounds.width(), bounds.height())
isResizeable = false
}
@@ -4879,15 +4878,19 @@ class DesktopTasksControllerTest : ShellTestCase() {
appCompatTaskInfo.isSystemFullscreenOverrideEnabled = enableSystemFullscreenOverride
if (deviceOrientation == ORIENTATION_LANDSCAPE) {
- configuration.windowConfiguration.appBounds =
- Rect(0, 0, DISPLAY_DIMENSION_LONG, DISPLAY_DIMENSION_SHORT)
- appCompatTaskInfo.topActivityLetterboxAppWidth = DISPLAY_DIMENSION_LONG
- appCompatTaskInfo.topActivityLetterboxAppHeight = DISPLAY_DIMENSION_SHORT
+ appCompatTaskInfo.topActivityAppBounds.set(
+ 0,
+ 0,
+ DISPLAY_DIMENSION_LONG,
+ DISPLAY_DIMENSION_SHORT,
+ )
} else {
- configuration.windowConfiguration.appBounds =
- Rect(0, 0, DISPLAY_DIMENSION_SHORT, DISPLAY_DIMENSION_LONG)
- appCompatTaskInfo.topActivityLetterboxAppWidth = DISPLAY_DIMENSION_SHORT
- appCompatTaskInfo.topActivityLetterboxAppHeight = DISPLAY_DIMENSION_LONG
+ appCompatTaskInfo.topActivityAppBounds.set(
+ 0,
+ 0,
+ DISPLAY_DIMENSION_SHORT,
+ DISPLAY_DIMENSION_LONG,
+ )
}
if (shouldLetterbox) {
@@ -4897,17 +4900,15 @@ class DesktopTasksControllerTest : ShellTestCase() {
screenOrientation == SCREEN_ORIENTATION_PORTRAIT
) {
// Letterbox to portrait size
- appCompatTaskInfo.setTopActivityLetterboxed(true)
- appCompatTaskInfo.topActivityLetterboxAppWidth = 1200
- appCompatTaskInfo.topActivityLetterboxAppHeight = 1600
+ appCompatTaskInfo.isTopActivityLetterboxed = true
+ appCompatTaskInfo.topActivityAppBounds.set(0, 0, 1200, 1600)
} else if (
deviceOrientation == ORIENTATION_PORTRAIT &&
screenOrientation == SCREEN_ORIENTATION_LANDSCAPE
) {
// Letterbox to landscape size
- appCompatTaskInfo.setTopActivityLetterboxed(true)
- appCompatTaskInfo.topActivityLetterboxAppWidth = 1600
- appCompatTaskInfo.topActivityLetterboxAppHeight = 1200
+ appCompatTaskInfo.isTopActivityLetterboxed = true
+ appCompatTaskInfo.topActivityAppBounds.set(0, 0, 1600, 1200)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
index a8aa25700c7e..3fe8c109807a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
@@ -120,22 +120,15 @@ public class PipSchedulerTest {
@Test
public void scheduleExitPipViaExpand_nullTaskToken_noop() {
setNullPipTaskToken();
- when(mMockPipTransitionState.isInPip()).thenReturn(true);
mPipScheduler.scheduleExitPipViaExpand();
- verify(mMockMainExecutor, times(1)).execute(mRunnableArgumentCaptor.capture());
- assertNotNull(mRunnableArgumentCaptor.getValue());
- mRunnableArgumentCaptor.getValue().run();
-
- verify(mMockPipTransitionController, never())
- .startExitTransition(eq(TRANSIT_EXIT_PIP), any(), isNull());
+ verify(mMockMainExecutor, never()).execute(any());
}
@Test
public void scheduleExitPipViaExpand_exitTransitionCalled() {
setMockPipTaskToken();
- when(mMockPipTransitionState.isInPip()).thenReturn(true);
mPipScheduler.scheduleExitPipViaExpand();
@@ -149,13 +142,20 @@ public class PipSchedulerTest {
@Test
public void removePipAfterAnimation() {
+ //TODO: Update once this is changed to run animation as part of transition
setMockPipTaskToken();
- when(mMockPipTransitionState.isInPip()).thenReturn(true);
- mPipScheduler.scheduleRemovePip();
+ mPipScheduler.removePipAfterAnimation();
+ verify(mMockAlphaAnimator, times(1))
+ .setAnimationEndCallback(mRunnableArgumentCaptor.capture());
+ assertNotNull(mRunnableArgumentCaptor.getValue());
+ verify(mMockAlphaAnimator, times(1)).start();
+
+ mRunnableArgumentCaptor.getValue().run();
verify(mMockMainExecutor, times(1)).execute(mRunnableArgumentCaptor.capture());
assertNotNull(mRunnableArgumentCaptor.getValue());
+
mRunnableArgumentCaptor.getValue().run();
verify(mMockPipTransitionController, times(1))
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 60584d9c6f72..f42017dc835a 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -226,6 +226,10 @@ public abstract class MediaRoute2ProviderService extends Service {
@GuardedBy("mSessionLock")
private final ArrayMap<String, MediaStreams> mOngoingMediaStreams = new ArrayMap<>();
+ @GuardedBy("mSessionLock")
+ private final ArrayMap<String, RoutingSessionInfo> mPendingSystemSessionReleases =
+ new ArrayMap<>();
+
public MediaRoute2ProviderService() {
mHandler = new Handler(Looper.getMainLooper());
}
@@ -419,7 +423,7 @@ public abstract class MediaRoute2ProviderService extends Service {
}
AudioFormat audioFormat = formats.mAudioFormat;
- var mediaStreamsBuilder = new MediaStreams.Builder();
+ var mediaStreamsBuilder = new MediaStreams.Builder(sessionInfo);
if (audioFormat != null) {
populateAudioStream(audioFormat, uid, mediaStreamsBuilder);
}
@@ -526,8 +530,14 @@ public abstract class MediaRoute2ProviderService extends Service {
RoutingSessionInfo sessionInfo;
synchronized (mSessionLock) {
sessionInfo = mSessionInfos.remove(sessionId);
- maybeReleaseMediaStreams(sessionId);
-
+ if (Flags.enableMirroringInMediaRouter2()) {
+ if (sessionInfo == null) {
+ sessionInfo = maybeReleaseMediaStreams(sessionId);
+ }
+ if (sessionInfo == null) {
+ sessionInfo = mPendingSystemSessionReleases.remove(sessionId);
+ }
+ }
if (sessionInfo == null) {
Log.w(TAG, "notifySessionReleased: Ignoring unknown session info.");
return;
@@ -544,20 +554,26 @@ public abstract class MediaRoute2ProviderService extends Service {
}
}
- /** Releases any system media routing resources associated with the given {@code sessionId}. */
- private boolean maybeReleaseMediaStreams(String sessionId) {
+ /**
+ * Releases any system media routing resources associated with the given {@code sessionId}.
+ *
+ * @return The {@link RoutingSessionInfo} that corresponds to the released media streams, or
+ * null if no streams were released.
+ */
+ @Nullable
+ private RoutingSessionInfo maybeReleaseMediaStreams(String sessionId) {
if (!Flags.enableMirroringInMediaRouter2()) {
- return false;
+ return null;
}
synchronized (mSessionLock) {
var streams = mOngoingMediaStreams.remove(sessionId);
if (streams != null) {
releaseAudioStream(streams.mAudioPolicy, streams.mAudioRecord);
// TODO: b/380431086: Release the video stream once implemented.
- return true;
+ return streams.mSessionInfo;
}
}
- return false;
+ return null;
}
// We cannot reach the code that requires MODIFY_AUDIO_ROUTING without holding it.
@@ -1026,11 +1042,15 @@ public abstract class MediaRoute2ProviderService extends Service {
if (!checkCallerIsSystem()) {
return;
}
- // We proactively release the system media routing once the system requests it, to
- // ensure it happens immediately.
- if (!maybeReleaseMediaStreams(sessionId)
- && !checkSessionIdIsValid(sessionId, "releaseSession")) {
- return;
+ synchronized (mSessionLock) {
+ // We proactively release the system media routing session resources when the
+ // system requests it, to ensure it happens immediately.
+ RoutingSessionInfo releasedSession = maybeReleaseMediaStreams(sessionId);
+ if (releasedSession != null) {
+ mPendingSystemSessionReleases.put(sessionId, releasedSession);
+ } else if (!checkSessionIdIsValid(sessionId, "releaseSession")) {
+ return;
+ }
}
addRequestId(requestId);
@@ -1054,9 +1074,19 @@ public abstract class MediaRoute2ProviderService extends Service {
@Nullable private final AudioPolicy mAudioPolicy;
@Nullable private final AudioRecord mAudioRecord;
+ /**
+ * Holds the last {@link RoutingSessionInfo} associated with these streams.
+ *
+ * @hide
+ */
+ @GuardedBy("MediaRoute2ProviderService.this.mSessionLock")
+ @NonNull
+ private RoutingSessionInfo mSessionInfo;
+
// TODO: b/380431086: Add the video equivalent.
private MediaStreams(Builder builder) {
+ this.mSessionInfo = builder.mSessionInfo;
this.mAudioPolicy = builder.mAudioPolicy;
this.mAudioRecord = builder.mAudioRecord;
}
@@ -1077,9 +1107,19 @@ public abstract class MediaRoute2ProviderService extends Service {
*/
public static final class Builder {
+ @NonNull private RoutingSessionInfo mSessionInfo;
@Nullable private AudioPolicy mAudioPolicy;
@Nullable private AudioRecord mAudioRecord;
+ /**
+ * Constructor.
+ *
+ * @param sessionInfo The {@link RoutingSessionInfo} associated with these streams.
+ */
+ Builder(@NonNull RoutingSessionInfo sessionInfo) {
+ mSessionInfo = requireNonNull(sessionInfo);
+ }
+
/** Populates system media audio-related structures. */
public Builder setAudioStream(
@NonNull AudioPolicy audioPolicy, @NonNull AudioRecord audioRecord) {
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 31e1eb36ad8d..70f5bb32a5d5 100644
--- a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
@@ -2074,15 +2074,19 @@ public class PackageWatchdog {
bootMitigationCounts.put(observer.name, observer.getBootMitigationCount());
}
+ FileOutputStream fileStream = null;
+ ObjectOutputStream objectStream = null;
try {
- FileOutputStream fileStream = new FileOutputStream(new File(filePath));
- ObjectOutputStream objectStream = new ObjectOutputStream(fileStream);
+ fileStream = new FileOutputStream(new File(filePath));
+ objectStream = new ObjectOutputStream(fileStream);
objectStream.writeObject(bootMitigationCounts);
objectStream.flush();
- objectStream.close();
- fileStream.close();
} catch (Exception e) {
Slog.i(TAG, "Could not save observers metadata to file: " + e);
+ return;
+ } finally {
+ IoUtils.closeQuietly(objectStream);
+ IoUtils.closeQuietly(fileStream);
}
}
@@ -2233,23 +2237,32 @@ public class PackageWatchdog {
void readAllObserversBootMitigationCountIfNecessary(String filePath) {
File metadataFile = new File(filePath);
if (metadataFile.exists()) {
+ FileInputStream fileStream = null;
+ ObjectInputStream objectStream = null;
+ HashMap<String, Integer> bootMitigationCounts = null;
try {
- FileInputStream fileStream = new FileInputStream(metadataFile);
- ObjectInputStream objectStream = new ObjectInputStream(fileStream);
- HashMap<String, Integer> bootMitigationCounts =
+ fileStream = new FileInputStream(metadataFile);
+ objectStream = new ObjectInputStream(fileStream);
+ bootMitigationCounts =
(HashMap<String, Integer>) objectStream.readObject();
- objectStream.close();
- fileStream.close();
-
- for (int i = 0; i < mAllObservers.size(); i++) {
- final ObserverInternal observer = mAllObservers.valueAt(i);
- if (bootMitigationCounts.containsKey(observer.name)) {
- observer.setBootMitigationCount(
- bootMitigationCounts.get(observer.name));
- }
- }
} catch (Exception e) {
Slog.i(TAG, "Could not read observer metadata file: " + e);
+ return;
+ } finally {
+ IoUtils.closeQuietly(objectStream);
+ IoUtils.closeQuietly(fileStream);
+ }
+
+ if (bootMitigationCounts == null || bootMitigationCounts.isEmpty()) {
+ Slog.i(TAG, "No observer in metadata file");
+ return;
+ }
+ for (int i = 0; i < mAllObservers.size(); i++) {
+ final ObserverInternal observer = mAllObservers.valueAt(i);
+ if (bootMitigationCounts.containsKey(observer.name)) {
+ observer.setBootMitigationCount(
+ bootMitigationCounts.get(observer.name));
+ }
}
}
}
diff --git a/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java
index ffae5176cebf..ac815f8aca85 100644
--- a/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java
@@ -2021,15 +2021,19 @@ public class PackageWatchdog {
bootMitigationCounts.put(observer.name, observer.getBootMitigationCount());
}
+ FileOutputStream fileStream = null;
+ ObjectOutputStream objectStream = null;
try {
- FileOutputStream fileStream = new FileOutputStream(new File(filePath));
- ObjectOutputStream objectStream = new ObjectOutputStream(fileStream);
+ fileStream = new FileOutputStream(new File(filePath));
+ objectStream = new ObjectOutputStream(fileStream);
objectStream.writeObject(bootMitigationCounts);
objectStream.flush();
- objectStream.close();
- fileStream.close();
} catch (Exception e) {
Slog.i(TAG, "Could not save observers metadata to file: " + e);
+ return;
+ } finally {
+ IoUtils.closeQuietly(objectStream);
+ IoUtils.closeQuietly(fileStream);
}
}
@@ -2180,23 +2184,32 @@ public class PackageWatchdog {
void readAllObserversBootMitigationCountIfNecessary(String filePath) {
File metadataFile = new File(filePath);
if (metadataFile.exists()) {
+ FileInputStream fileStream = null;
+ ObjectInputStream objectStream = null;
+ HashMap<String, Integer> bootMitigationCounts = null;
try {
- FileInputStream fileStream = new FileInputStream(metadataFile);
- ObjectInputStream objectStream = new ObjectInputStream(fileStream);
- HashMap<String, Integer> bootMitigationCounts =
+ fileStream = new FileInputStream(metadataFile);
+ objectStream = new ObjectInputStream(fileStream);
+ bootMitigationCounts =
(HashMap<String, Integer>) objectStream.readObject();
- objectStream.close();
- fileStream.close();
-
- for (int i = 0; i < mAllObservers.size(); i++) {
- final ObserverInternal observer = mAllObservers.valueAt(i);
- if (bootMitigationCounts.containsKey(observer.name)) {
- observer.setBootMitigationCount(
- bootMitigationCounts.get(observer.name));
- }
- }
} catch (Exception e) {
Slog.i(TAG, "Could not read observer metadata file: " + e);
+ return;
+ } finally {
+ IoUtils.closeQuietly(objectStream);
+ IoUtils.closeQuietly(fileStream);
+ }
+
+ if (bootMitigationCounts == null || bootMitigationCounts.isEmpty()) {
+ Slog.i(TAG, "No observer in metadata file");
+ return;
+ }
+ for (int i = 0; i < mAllObservers.size(); i++) {
+ final ObserverInternal observer = mAllObservers.valueAt(i);
+ if (bootMitigationCounts.containsKey(observer.name)) {
+ observer.setBootMitigationCount(
+ bootMitigationCounts.get(observer.name));
+ }
}
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 1c4def39eaa0..e01cb84f60ae 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -16,6 +16,19 @@
package com.android.providers.settings;
+import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_DEVICE_SPECIFIC_CONFIG;
+import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_GLOBAL;
+import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_LOCALE;
+import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_LOCK_SETTINGS;
+import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_NETWORK_POLICIES;
+import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_SECURE;
+import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_SIM_SPECIFIC_SETTINGS;
+import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_SIM_SPECIFIC_SETTINGS_2;
+import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_SOFTAP_CONFIG;
+import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_SYSTEM;
+import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_WIFI_NEW_CONFIG;
+import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_WIFI_SETTINGS_BACKUP_DATA;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -99,22 +112,6 @@ public class SettingsBackupAgent extends BackupAgentHelper {
private static final int NULL_SIZE = -1;
private static final float FONT_SCALE_DEF_VALUE = 1.0f;
- private static final String KEY_SYSTEM = "system";
- private static final String KEY_SECURE = "secure";
- private static final String KEY_GLOBAL = "global";
- private static final String KEY_LOCALE = "locale";
- private static final String KEY_LOCK_SETTINGS = "lock_settings";
- private static final String KEY_SOFTAP_CONFIG = "softap_config";
- private static final String KEY_NETWORK_POLICIES = "network_policies";
- private static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config";
- private static final String KEY_DEVICE_SPECIFIC_CONFIG = "device_specific_config";
- private static final String KEY_SIM_SPECIFIC_SETTINGS = "sim_specific_settings";
- // Restoring sim-specific data backed up from newer Android version to Android 12 was causing a
- // fatal crash. Creating a backup with a different key will prevent Android 12 versions from
- // restoring this data.
- private static final String KEY_SIM_SPECIFIC_SETTINGS_2 = "sim_specific_settings_2";
- private static final String KEY_WIFI_SETTINGS_BACKUP_DATA = "wifi_settings_backup_data";
-
// Versioning of the state file. Increment this version
// number any time the set of state items is altered.
private static final int STATE_VERSION = 9;
@@ -257,6 +254,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
if (com.android.server.backup.Flags.enableMetricsSettingsBackupAgents()) {
mBackupRestoreEventLogger = this.getBackupRestoreEventLogger();
+ mSettingsHelper.setBackupRestoreEventLogger(mBackupRestoreEventLogger);
numberOfSettingsPerKey = new HashMap<>();
areAgentMetricsEnabled = true;
}
@@ -412,9 +410,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
mSettingsHelper
.setLocaleData(
localeData,
- size,
- mBackupRestoreEventLogger,
- KEY_LOCALE);
+ size);
break;
case KEY_WIFI_CONFIG :
@@ -552,8 +548,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
if (nBytes > buffer.length) buffer = new byte[nBytes];
in.readFully(buffer, 0, nBytes);
mSettingsHelper
- .setLocaleData(
- buffer, nBytes, mBackupRestoreEventLogger, KEY_LOCALE);
+ .setLocaleData(buffer, nBytes);
// Restore older backups performing the necessary migrations.
if (version < FULL_BACKUP_ADDED_WIFI_NEW) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupRestoreKeys.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupRestoreKeys.java
new file mode 100644
index 000000000000..745c2fb5409d
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupRestoreKeys.java
@@ -0,0 +1,61 @@
+/*
+ * 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.providers.settings;
+
+import android.net.Uri;
+import android.provider.Settings;
+
+/**
+ * Class to store the keys used for backup and restore.
+ */
+final class SettingsBackupRestoreKeys {
+ static final String KEY_UNKNOWN = "unknown";
+ static final String KEY_SYSTEM = "system";
+ static final String KEY_SECURE = "secure";
+ static final String KEY_GLOBAL = "global";
+ static final String KEY_LOCALE = "locale";
+ static final String KEY_LOCK_SETTINGS = "lock_settings";
+ static final String KEY_SOFTAP_CONFIG = "softap_config";
+ static final String KEY_NETWORK_POLICIES = "network_policies";
+ static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config";
+ static final String KEY_DEVICE_SPECIFIC_CONFIG = "device_specific_config";
+ static final String KEY_SIM_SPECIFIC_SETTINGS = "sim_specific_settings";
+ // Restoring sim-specific data backed up from newer Android version to Android 12 was causing a
+ // fatal crash. Creating a backup with a different key will prevent Android 12 versions from
+ // restoring this data.
+ static final String KEY_SIM_SPECIFIC_SETTINGS_2 = "sim_specific_settings_2";
+ static final String KEY_WIFI_SETTINGS_BACKUP_DATA = "wifi_settings_backup_data";
+
+ /**
+ * Returns the key corresponding to the given URI.
+ *
+ * @param uri The URI of the setting's destination.
+ * @return The key corresponding to the given URI, or KEY_UNKNOWN if the URI is not recognized.
+ */
+ static String getKeyFromUri(Uri uri) {
+ if (uri.equals(Settings.Secure.CONTENT_URI)) {
+ return KEY_SECURE;
+ } else if (uri.equals(Settings.System.CONTENT_URI)) {
+ return KEY_SYSTEM;
+ } else if (uri.equals(Settings.Global.CONTENT_URI)) {
+ return KEY_GLOBAL;
+ } else {
+ return KEY_UNKNOWN;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 924c151a99a0..ab8d739feb43 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -17,6 +17,7 @@
package com.android.providers.settings;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.backup.BackupRestoreEventLogger;
@@ -84,6 +85,7 @@ public class SettingsHelper {
private Context mContext;
private AudioManager mAudioManager;
private TelephonyManager mTelephonyManager;
+ @Nullable private BackupRestoreEventLogger mBackupRestoreEventLogger;
/**
* A few settings elements are special in that a restore of those values needs to
@@ -741,11 +743,8 @@ public class SettingsHelper {
*
* @param data the comma separated BCP-47 language tags in bytes.
* @param size the size of the data in bytes.
- * @param backupRestoreEventLogger the logger to log the restore event.
- * @param dataType the data type of the setting for logging purposes.
*/
- /* package */ void setLocaleData(
- byte[] data, int size, BackupRestoreEventLogger backupRestoreEventLogger, String dataType) {
+ /* package */ void setLocaleData(byte[] data, int size) {
final Configuration conf = mContext.getResources().getConfiguration();
// Replace "_" with "-" to deal with older backups.
@@ -772,15 +771,15 @@ public class SettingsHelper {
am.updatePersistentConfigurationWithAttribution(config, mContext.getOpPackageName(),
mContext.getAttributionTag());
- if (Flags.enableMetricsSettingsBackupAgents()) {
- backupRestoreEventLogger
- .logItemsRestored(dataType, localeList.size());
+ if (Flags.enableMetricsSettingsBackupAgents() && mBackupRestoreEventLogger != null) {
+ mBackupRestoreEventLogger
+ .logItemsRestored(SettingsBackupRestoreKeys.KEY_LOCALE, localeList.size());
}
} catch (RemoteException e) {
- if (Flags.enableMetricsSettingsBackupAgents()) {
- backupRestoreEventLogger
+ if (Flags.enableMetricsSettingsBackupAgents() && mBackupRestoreEventLogger != null) {
+ mBackupRestoreEventLogger
.logItemsRestoreFailed(
- dataType,
+ SettingsBackupRestoreKeys.KEY_LOCALE,
localeList.size(),
ERROR_REMOTE_EXCEPTION_SETTING_LOCALE_DATA);
}
@@ -795,4 +794,13 @@ public class SettingsHelper {
AudioManager am = new AudioManager(mContext);
am.reloadAudioSettings();
}
+
+ /**
+ * Sets the backup restore event logger.
+ *
+ * @param backupRestoreEventLogger the logger to log B&R metrics.
+ */
+ void setBackupRestoreEventLogger(BackupRestoreEventLogger backupRestoreEventLogger) {
+ mBackupRestoreEventLogger = backupRestoreEventLogger;
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 55f48e3e367f..f1f03c31f718 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -120,6 +120,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.accessibility.util.AccessibilityUtils;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.display.RefreshRateSettingsUtils;
import com.android.internal.os.BackgroundThread;
@@ -2914,6 +2915,14 @@ public class SettingsProvider extends ContentProvider {
};
}
+ @VisibleForTesting
+ void injectServices(UserManager userManager, IPackageManager packageManager,
+ SystemConfigManager sysConfigManager) {
+ mUserManager = userManager;
+ mPackageManager = packageManager;
+ mSysConfigManager = sysConfigManager;
+ }
+
private static final class Arguments {
private static final Pattern WHERE_PATTERN_WITH_PARAM_NO_BRACKETS =
Pattern.compile("[\\s]*name[\\s]*=[\\s]*\\?[\\s]*");
@@ -3080,6 +3089,7 @@ public class SettingsProvider extends ContentProvider {
private static final String SSAID_USER_KEY = "userkey";
+ @GuardedBy("mLock")
private final SparseArray<SettingsState> mSettingsStates = new SparseArray<>();
private GenerationRegistry mGenerationRegistry;
@@ -3992,6 +4002,14 @@ public class SettingsProvider extends ContentProvider {
}
}
+ @VisibleForTesting
+ void injectSettings(SettingsState settings, int type, int userId) {
+ int key = makeKey(type, userId);
+ synchronized (mLock) {
+ mSettingsStates.put(key, settings);
+ }
+ }
+
private final class MyHandler extends Handler {
private static final int MSG_NOTIFY_URI_CHANGED = 1;
private static final int MSG_NOTIFY_DATA_CHANGED = 2;
@@ -4023,12 +4041,21 @@ public class SettingsProvider extends ContentProvider {
}
}
- private final class UpgradeController {
+ @VisibleForTesting
+ final class UpgradeController {
private static final int SETTINGS_VERSION = 226;
private final int mUserId;
+ private final Injector mInjector;
+
public UpgradeController(int userId) {
+ this(/* injector= */ null, userId);
+ }
+
+ @VisibleForTesting
+ UpgradeController(Injector injector, int userId) {
+ mInjector = injector == null ? new Injector() : injector;
mUserId = userId;
}
@@ -6136,8 +6163,8 @@ public class SettingsProvider extends ContentProvider {
systemSettings.getSettingLocked(Settings.System.PEAK_REFRESH_RATE);
final Setting minRefreshRateSetting =
systemSettings.getSettingLocked(Settings.System.MIN_REFRESH_RATE);
- float highestRefreshRate = RefreshRateSettingsUtils
- .findHighestRefreshRateForDefaultDisplay(getContext());
+ float highestRefreshRate =
+ mInjector.findHighestRefreshRateForDefaultDisplay(getContext());
if (!peakRefreshRateSetting.isNull()) {
try {
@@ -6318,6 +6345,14 @@ public class SettingsProvider extends ContentProvider {
private long getBitMask(int capability) {
return 1 << (capability - 1);
}
+
+ @VisibleForTesting
+ static class Injector {
+ float findHighestRefreshRateForDefaultDisplay(Context context) {
+ return RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(
+ context);
+ }
+ }
}
/**
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 5cd534e62ea9..bf3afeda448e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -107,7 +107,7 @@ import static com.android.aconfig_new_storage.Flags.enableAconfigStorageDaemon;
* the same lock to grab the current state to write to disk.
* </p>
*/
-final class SettingsState {
+public class SettingsState {
private static final boolean DEBUG = false;
private static final boolean DEBUG_PERSISTENCE = false;
@@ -1838,7 +1838,7 @@ final class SettingsState {
}
}
- class Setting {
+ public class Setting {
private String name;
private String value;
private String defaultValue;
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupRestoreKeysTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupRestoreKeysTest.java
new file mode 100644
index 000000000000..ef537e8c7fc0
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupRestoreKeysTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.providers.settings;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.net.Uri;
+import android.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link SettingsBackupRestoreKeys}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class SettingsBackupRestoreKeysTest {
+
+ @Test
+ public void getKeyFromUri_secureUri_returnsSecureKey() {
+ assertThat(SettingsBackupRestoreKeys.getKeyFromUri(Settings.Secure.CONTENT_URI))
+ .isEqualTo(SettingsBackupRestoreKeys.KEY_SECURE);
+ }
+
+ @Test
+ public void getKeyFromUri_systemUri_returnsSystemKey() {
+ assertThat(SettingsBackupRestoreKeys.getKeyFromUri(Settings.System.CONTENT_URI))
+ .isEqualTo(SettingsBackupRestoreKeys.KEY_SYSTEM);
+ }
+
+ @Test
+ public void getKeyFromUri_globalUri_returnsGlobalKey() {
+ assertThat(SettingsBackupRestoreKeys.getKeyFromUri(Settings.Global.CONTENT_URI))
+ .isEqualTo(SettingsBackupRestoreKeys.KEY_GLOBAL);
+ }
+
+ @Test
+ public void getKeyFromUri_unknownUri_returnsUnknownKey() {
+ assertThat(SettingsBackupRestoreKeys.getKeyFromUri(Uri.parse("content://unknown")))
+ .isEqualTo(SettingsBackupRestoreKeys.KEY_UNKNOWN);
+ }
+} \ No newline at end of file
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/UpgradeControllerTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/UpgradeControllerTest.java
new file mode 100644
index 000000000000..26ff376f828e
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/UpgradeControllerTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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.providers.settings;
+
+import static android.provider.Settings.System.MIN_REFRESH_RATE;
+import static android.provider.Settings.System.PEAK_REFRESH_RATE;
+
+import static com.android.providers.settings.SettingsProvider.SETTINGS_TYPE_GLOBAL;
+import static com.android.providers.settings.SettingsProvider.SETTINGS_TYPE_SECURE;
+import static com.android.providers.settings.SettingsProvider.SETTINGS_TYPE_SYSTEM;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.IPackageManager;
+import android.os.Looper;
+import android.os.SystemConfigManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class UpgradeControllerTest {
+ private static final int USER_ID = UserHandle.USER_SYSTEM;
+ private static final float HIGHEST_REFRESH_RATE = 130f;
+
+ private final Context mContext =
+ spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
+ private final SettingsProvider.SettingsRegistry.UpgradeController.Injector mInjector =
+ new SettingsProvider.SettingsRegistry.UpgradeController.Injector() {
+ @Override
+ float findHighestRefreshRateForDefaultDisplay(Context context) {
+ return HIGHEST_REFRESH_RATE;
+ }
+ };
+ private final SettingsProvider mSettingsProvider = new SettingsProvider() {
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+ };
+ private final SettingsProvider.SettingsRegistry mSettingsRegistry =
+ mSettingsProvider.new SettingsRegistry(Looper.getMainLooper());
+ private final SettingsProvider.SettingsRegistry.UpgradeController mUpgradeController =
+ mSettingsRegistry.new UpgradeController(mInjector, USER_ID);
+
+ @Mock
+ private UserManager mUserManager;
+
+ @Mock
+ private IPackageManager mPackageManager;
+
+ @Mock
+ private SystemConfigManager mSysConfigManager;
+
+ @Mock
+ private SettingsState mSystemSettings;
+
+ @Mock
+ private SettingsState mSecureSettings;
+
+ @Mock
+ private SettingsState mGlobalSettings;
+
+ @Mock
+ private SettingsState.Setting mMockSetting;
+
+ @Mock
+ private SettingsState.Setting mPeakRefreshRateSetting;
+
+ @Mock
+ private SettingsState.Setting mMinRefreshRateSetting;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mSettingsProvider.attachInfoForTesting(mContext, /* info= */ null);
+ mSettingsProvider.injectServices(mUserManager, mPackageManager, mSysConfigManager);
+ when(mSystemSettings.getSettingLocked(any())).thenReturn(mMockSetting);
+ when(mSecureSettings.getSettingLocked(any())).thenReturn(mMockSetting);
+ when(mGlobalSettings.getSettingLocked(any())).thenReturn(mMockSetting);
+ when(mMockSetting.isNull()).thenReturn(true);
+ when(mMockSetting.getValue()).thenReturn("0");
+
+ when(mSystemSettings.getSettingLocked(PEAK_REFRESH_RATE))
+ .thenReturn(mPeakRefreshRateSetting);
+ when(mSystemSettings.getSettingLocked(MIN_REFRESH_RATE))
+ .thenReturn(mMinRefreshRateSetting);
+
+ mSettingsRegistry.injectSettings(mSystemSettings, SETTINGS_TYPE_SYSTEM, USER_ID);
+ mSettingsRegistry.injectSettings(mSecureSettings, SETTINGS_TYPE_SECURE, USER_ID);
+ mSettingsRegistry.injectSettings(mGlobalSettings, SETTINGS_TYPE_GLOBAL, USER_ID);
+
+ // Lowest version so that all upgrades are run
+ when(mSecureSettings.getVersionLocked()).thenReturn(118);
+ }
+
+ @Test
+ public void testUpgrade_refreshRateSettings_defaultValues() {
+ when(mPeakRefreshRateSetting.isNull()).thenReturn(true);
+ when(mMinRefreshRateSetting.isNull()).thenReturn(true);
+
+ mUpgradeController.upgradeIfNeededLocked();
+
+ // Should remain unchanged
+ verify(mSystemSettings, never()).insertSettingLocked(eq(PEAK_REFRESH_RATE),
+ /* value= */ any(), /* tag= */ any(), /* makeDefault= */ anyBoolean(),
+ /* packageName= */ any());
+ verify(mSystemSettings, never()).insertSettingLocked(eq(MIN_REFRESH_RATE),
+ /* value= */ any(), /* tag= */ any(), /* makeDefault= */ anyBoolean(),
+ /* packageName= */ any());
+ }
+
+ @Test
+ public void testUpgrade_refreshRateSettings_enabled() {
+ when(mPeakRefreshRateSetting.isNull()).thenReturn(false);
+ when(mMinRefreshRateSetting.isNull()).thenReturn(false);
+ when(mPeakRefreshRateSetting.getValue()).thenReturn(String.valueOf(HIGHEST_REFRESH_RATE));
+ when(mMinRefreshRateSetting.getValue()).thenReturn(String.valueOf(HIGHEST_REFRESH_RATE));
+
+ mUpgradeController.upgradeIfNeededLocked();
+
+ // Highest refresh rate gets converted to infinity
+ verify(mSystemSettings).insertSettingLocked(eq(PEAK_REFRESH_RATE),
+ eq(String.valueOf(Float.POSITIVE_INFINITY)), /* tag= */ any(),
+ /* makeDefault= */ anyBoolean(), /* packageName= */ any());
+ verify(mSystemSettings).insertSettingLocked(eq(MIN_REFRESH_RATE),
+ eq(String.valueOf(Float.POSITIVE_INFINITY)), /* tag= */ any(),
+ /* makeDefault= */ anyBoolean(), /* packageName= */ any());
+ }
+
+ @Test
+ public void testUpgrade_refreshRateSettings_disabled() {
+ when(mPeakRefreshRateSetting.isNull()).thenReturn(false);
+ when(mMinRefreshRateSetting.isNull()).thenReturn(false);
+ when(mPeakRefreshRateSetting.getValue()).thenReturn("70f");
+ when(mMinRefreshRateSetting.getValue()).thenReturn("70f");
+
+ mUpgradeController.upgradeIfNeededLocked();
+
+ // Should remain unchanged
+ verify(mSystemSettings, never()).insertSettingLocked(eq(PEAK_REFRESH_RATE),
+ /* value= */ any(), /* tag= */ any(), /* makeDefault= */ anyBoolean(),
+ /* packageName= */ any());
+ verify(mSystemSettings, never()).insertSettingLocked(eq(MIN_REFRESH_RATE),
+ /* value= */ any(), /* tag= */ any(), /* makeDefault= */ anyBoolean(),
+ /* packageName= */ any());
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
index db33e7c628d7..79cf24b9c547 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
@@ -35,9 +35,8 @@ import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
-import com.android.compose.animation.scene.SceneScope
-import com.android.compose.animation.scene.SceneTransitionLayout
import com.android.compose.modifiers.thenIf
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.blueprint.ClockScenes.largeClockScene
@@ -61,7 +60,7 @@ constructor(
private val clockInteractor: KeyguardClockInteractor,
) {
@Composable
- fun SceneScope.DefaultClockLayout(
+ fun ContentScope.DefaultClockLayout(
smartSpacePaddingTop: (Resources) -> Int,
isShadeLayoutWide: Boolean,
modifier: Modifier = Modifier,
@@ -95,7 +94,7 @@ constructor(
}
Column(modifier) {
- SceneTransitionLayout(state) {
+ NestedSceneTransitionLayout(state, Modifier) {
scene(splitShadeLargeClockScene) {
LargeClockWithSmartSpace(
smartSpacePaddingTop = smartSpacePaddingTop,
@@ -134,7 +133,7 @@ constructor(
}
@Composable
- private fun SceneScope.SmallClockWithSmartSpace(
+ private fun ContentScope.SmallClockWithSmartSpace(
smartSpacePaddingTop: (Resources) -> Int,
modifier: Modifier = Modifier,
) {
@@ -159,7 +158,7 @@ constructor(
}
@Composable
- private fun SceneScope.LargeClockWithSmartSpace(
+ private fun ContentScope.LargeClockWithSmartSpace(
smartSpacePaddingTop: (Resources) -> Int,
shouldOffSetClockToOneHalf: Boolean = false,
) {
@@ -200,7 +199,7 @@ constructor(
}
@Composable
- private fun SceneScope.WeatherLargeClockWithSmartSpace(
+ private fun ContentScope.WeatherLargeClockWithSmartSpace(
smartSpacePaddingTop: (Resources) -> Int,
modifier: Modifier = Modifier,
) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index 55fafd5cfeca..8907aec7fd48 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -5,7 +5,6 @@ import androidx.compose.foundation.gestures.Orientation
import com.android.compose.animation.scene.ProgressConverter
import com.android.compose.animation.scene.TransitionKey
import com.android.compose.animation.scene.transitions
-import com.android.systemui.bouncer.ui.composable.Bouncer
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
@@ -110,17 +109,13 @@ val SceneContainerTransitions = transitions {
// Overlay transitions
- // TODO(b/376659778): Remove this transition once nested STLs are supported.
- from(Scenes.Gone, to = Overlays.NotificationsShade) {
- toNotificationsShadeTransition(translateClock = true)
- }
to(Overlays.NotificationsShade) { toNotificationsShadeTransition() }
to(Overlays.QuickSettingsShade) { toQuickSettingsShadeTransition() }
from(Overlays.NotificationsShade, to = Overlays.QuickSettingsShade) {
notificationsShadeToQuickSettingsShadeTransition()
}
from(Scenes.Gone, to = Overlays.NotificationsShade, key = SlightlyFasterShadeCollapse) {
- toNotificationsShadeTransition(translateClock = true, durationScale = 0.9)
+ toNotificationsShadeTransition(durationScale = 0.9)
}
from(Scenes.Gone, to = Overlays.QuickSettingsShade, key = SlightlyFasterShadeCollapse) {
toQuickSettingsShadeTransition(durationScale = 0.9)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt
index 6bdb36331709..3d62151baf2f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt
@@ -29,10 +29,7 @@ import com.android.systemui.shade.ui.composable.OverlayShade
import com.android.systemui.shade.ui.composable.Shade
import kotlin.time.Duration.Companion.milliseconds
-fun TransitionBuilder.toNotificationsShadeTransition(
- translateClock: Boolean = false,
- durationScale: Double = 1.0,
-) {
+fun TransitionBuilder.toNotificationsShadeTransition(durationScale: Double = 1.0) {
spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
swipeSpec =
spring(
@@ -45,11 +42,6 @@ fun TransitionBuilder.toNotificationsShadeTransition(
elevateInContent = Overlays.NotificationsShade,
)
scaleSize(OverlayShade.Elements.Panel, height = 0f)
- // TODO(b/376659778): This is a temporary hack to have a shared element transition with the
- // lockscreen clock. Remove once nested STLs are supported.
- if (!translateClock) {
- translate(ClockElementKeys.smallClockElementKey)
- }
// Avoid translating the status bar with the shade panel.
translate(NotificationsShade.Elements.StatusBar)
// Slide in the shade panel from the top edge.
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
index 8a5c96da5ac6..f821e429beb5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
@@ -20,6 +20,9 @@ package com.android.systemui.shade.ui.composable
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.rememberScrollableState
+import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.PaddingValues
@@ -41,16 +44,21 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
+import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexContentPicker
import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.effect.rememberOffsetOverscrollEffect
import com.android.compose.windowsizeclass.LocalWindowSizeClass
import com.android.systemui.res.R
@@ -61,7 +69,22 @@ fun SceneScope.OverlayShade(
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
- Box(modifier) {
+ // TODO(b/384653288) This should be removed when b/378470603 is done.
+ val idleEffect = rememberOffsetOverscrollEffect(Orientation.Vertical)
+ Box(
+ modifier
+ .overscroll(idleEffect)
+ .nestedScroll(
+ remember {
+ object : NestedScrollConnection {
+ override suspend fun onPreFling(available: Velocity): Velocity {
+ return available
+ }
+ }
+ }
+ )
+ .scrollable(rememberScrollableState { 0f }, Orientation.Vertical, idleEffect)
+ ) {
Scrim(onClicked = onScrimClicked)
Box(modifier = Modifier.fillMaxSize().panelPadding(), contentAlignment = Alignment.TopEnd) {
@@ -180,7 +203,6 @@ object OverlayShade {
object Dimensions {
val PanelCornerRadius = 46.dp
- val OverscrollLimit = 32.dp
}
object Shapes {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
index 0e3b03f74c02..be504cc0f704 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
@@ -18,11 +18,8 @@
package com.android.systemui.keyguard.ui.viewmodel
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.DisableSceneContainer
@@ -75,7 +72,6 @@ class AodBurnInViewModelTest : SysuiTestCase() {
private val burnInFlow = MutableStateFlow(BurnInModel())
@Before
- @DisableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
@DisableSceneContainer
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -219,50 +215,6 @@ class AodBurnInViewModelTest : SysuiTestCase() {
}
@Test
- @DisableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
- fun translationAndScale_whenFullyDozing_MigrationFlagOff_staysOutOfTopInset() =
- testScope.runTest {
- underTest.updateBurnInParams(burnInParameters.copy(minViewY = 100, topInset = 80))
- val movement by collectLastValue(underTest.movement)
- assertThat(movement?.translationX).isEqualTo(0)
-
- // Set to dozing (on AOD)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- from = KeyguardState.GONE,
- to = KeyguardState.AOD,
- value = 1f,
- transitionState = TransitionState.FINISHED,
- ),
- validateStep = false,
- )
-
- // Trigger a change to the burn-in model
- burnInFlow.value = BurnInModel(translationX = 20, translationY = -30, scale = 0.5f)
- assertThat(movement?.translationX).isEqualTo(20)
- // -20 instead of -30, due to inset of 80
- assertThat(movement?.translationY).isEqualTo(-20)
- assertThat(movement?.scale).isEqualTo(0.5f)
- assertThat(movement?.scaleClockOnly).isEqualTo(true)
-
- // Set to the beginning of GONE->AOD transition
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- from = KeyguardState.GONE,
- to = KeyguardState.AOD,
- value = 0f,
- transitionState = TransitionState.STARTED,
- ),
- validateStep = false,
- )
- assertThat(movement?.translationX).isEqualTo(0)
- assertThat(movement?.translationY).isEqualTo(0)
- assertThat(movement?.scale).isEqualTo(1f)
- assertThat(movement?.scaleClockOnly).isEqualTo(true)
- }
-
- @Test
- @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
fun translationAndScale_whenFullyDozing_MigrationFlagOn_staysOutOfTopInset() =
testScope.runTest {
underTest.updateBurnInParams(burnInParameters.copy(minViewY = 100, topInset = 80))
@@ -334,7 +286,6 @@ class AodBurnInViewModelTest : SysuiTestCase() {
@Test
@DisableSceneContainer
- @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
fun translationAndScale_sceneContainerOff_weatherLargeClock() =
testBurnInViewModelForClocks(
isSmallClock = false,
@@ -344,7 +295,6 @@ class AodBurnInViewModelTest : SysuiTestCase() {
@Test
@DisableSceneContainer
- @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
fun translationAndScale_sceneContainerOff_weatherSmallClock() =
testBurnInViewModelForClocks(
isSmallClock = true,
@@ -354,7 +304,6 @@ class AodBurnInViewModelTest : SysuiTestCase() {
@Test
@DisableSceneContainer
- @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
fun translationAndScale_sceneContainerOff_nonWeatherLargeClock() =
testBurnInViewModelForClocks(
isSmallClock = false,
@@ -364,7 +313,6 @@ class AodBurnInViewModelTest : SysuiTestCase() {
@Test
@DisableSceneContainer
- @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
fun translationAndScale_sceneContainerOff_nonWeatherSmallClock() =
testBurnInViewModelForClocks(
isSmallClock = true,
@@ -373,7 +321,6 @@ class AodBurnInViewModelTest : SysuiTestCase() {
)
@Test
- @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
@EnableSceneContainer
fun translationAndScale_sceneContainerOn_weatherLargeClock() =
testBurnInViewModelForClocks(
@@ -383,7 +330,6 @@ class AodBurnInViewModelTest : SysuiTestCase() {
)
@Test
- @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
@EnableSceneContainer
fun translationAndScale_sceneContainerOn_weatherSmallClock() =
testBurnInViewModelForClocks(
@@ -393,7 +339,6 @@ class AodBurnInViewModelTest : SysuiTestCase() {
)
@Test
- @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
@EnableSceneContainer
fun translationAndScale_sceneContainerOn_nonWeatherLargeClock() =
testBurnInViewModelForClocks(
@@ -403,7 +348,6 @@ class AodBurnInViewModelTest : SysuiTestCase() {
)
@Test
- @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
@EnableSceneContainer
@Ignore("b/367659687")
fun translationAndScale_sceneContainerOn_nonWeatherSmallClock() =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index 95ffc962797d..789477e38b55 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -19,12 +19,10 @@
package com.android.systemui.keyguard.ui.viewmodel
-import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import android.view.View
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
-import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.data.repository.communalSceneRepository
import com.android.systemui.communal.shared.model.CommunalScenes
@@ -73,7 +71,6 @@ import platform.test.runner.parameterized.Parameters
@SmallTest
@RunWith(ParameterizedAndroidJunit4::class)
-@EnableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
index b88861756889..5c6657b98801 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
@@ -8,6 +8,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -231,7 +232,8 @@ public class InternetAdapterTest extends SysuiTestCase {
mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
- verify(mSpyContext).startActivity(any());
+ verify(mInternetDialogController).startActivityForDialog(any());
+ verify(mSpyContext, never()).startActivity(any());
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 7b52dd836b51..5cd0846ded7e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -501,6 +501,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
}
@Test
+ @DisableFlags(com.android.systemui.shared.Flags.FLAG_NEW_CUSTOMIZATION_PICKER_UI)
public void onWallpaperColorsChanged_changeLockWallpaper() {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
diff --git a/packages/SystemUI/res/drawable/audio_bars_idle.xml b/packages/SystemUI/res/drawable/audio_bars_idle.xml
new file mode 100644
index 000000000000..92a24755fece
--- /dev/null
+++ b/packages/SystemUI/res/drawable/audio_bars_idle.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2021 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="168dp"
+ android:height="168dp"
+ android:viewportWidth="168"
+ android:viewportHeight="168">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_2_G"
+ android:translateX="121.161"
+ android:translateY="83.911">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="102.911"
+ android:translateY="83.911">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="139.661"
+ android:translateY="83.911">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index a3bad8f012ac..5ccedeafcb59 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -56,8 +56,8 @@
android:layout_marginTop="@dimen/volume_dialog_components_spacing"
android:background="@drawable/ripple_drawable_20dp"
android:contentDescription="@string/accessibility_volume_settings"
+ android:scaleType="centerInside"
android:soundEffectsEnabled="false"
- android:src="@drawable/horizontal_ellipsis"
android:tint="@androidprv:color/materialColorPrimary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container"
diff --git a/packages/SystemUI/res/raw/audio_bars_in.json b/packages/SystemUI/res/raw/audio_bars_in.json
new file mode 100644
index 000000000000..c90a59c47d64
--- /dev/null
+++ b/packages/SystemUI/res/raw/audio_bars_in.json
@@ -0,0 +1 @@
+{"v":"5.7.13","fr":60,"ip":0,"op":18,"w":168,"h":168,"nm":"audio_bars_in","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 5","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":5,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[120.75,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]},{"t":17,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-22.725],[5.957,-16.983],[5.961,0],[5.958,17.391],[0,23.149],[-5.958,17.39],[-5.961,0],[-5.957,-16.998]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":5,"s":[100]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[102.5,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]},{"t":17,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-38.225],[5.957,-32.483],[5.961,0],[5.958,32.016],[0,37.774],[-5.958,32.015],[-5.961,0],[-5.957,-32.498]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[65.75,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]},{"t":17,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-25.1],[5.957,-19.358],[5.961,0],[5.958,19.516],[0,25.274],[-5.958,19.515],[-5.961,0],[-5.957,-19.373]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]},{"t":17,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-18.6],[5.957,-12.858],[5.961,0],[5.958,13.141],[0,18.899],[-5.958,13.14],[-5.961,0],[-5.957,-12.873]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":5,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[47.25,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]},{"t":17,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-13.475],[5.957,-7.733],[5.961,0],[5.958,6.766],[0,12.524],[-5.958,6.765],[-5.961,0],[-5.957,-7.748]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":5,"s":[100]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]} \ No newline at end of file
diff --git a/packages/SystemUI/res/raw/audio_bars_out.json b/packages/SystemUI/res/raw/audio_bars_out.json
new file mode 100644
index 000000000000..5eab65e057ab
--- /dev/null
+++ b/packages/SystemUI/res/raw/audio_bars_out.json
@@ -0,0 +1 @@
+{"v":"5.7.13","fr":60,"ip":0,"op":31,"w":168,"h":168,"nm":"audio_bars_out","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 5","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"t":5,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[120.75,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-22.725],[5.957,-16.983],[5.961,0],[5.958,17.391],[0,23.149],[-5.958,17.39],[-5.961,0],[-5.957,-16.998]],"c":true}]},{"t":30,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"t":5,"s":[0]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[102.5,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-38.225],[5.957,-32.483],[5.961,0],[5.958,32.016],[0,37.774],[-5.958,32.015],[-5.961,0],[-5.957,-32.498]],"c":true}]},{"t":30,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[65.75,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-25.1],[5.957,-19.358],[5.961,0],[5.958,19.516],[0,25.274],[-5.958,19.515],[-5.961,0],[-5.957,-19.373]],"c":true}]},{"t":30,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-18.6],[5.957,-12.858],[5.961,0],[5.958,13.141],[0,18.899],[-5.958,13.14],[-5.961,0],[-5.957,-12.873]],"c":true}]},{"t":30,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"t":5,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[47.25,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-13.475],[5.957,-7.733],[5.961,0],[5.958,6.766],[0,12.524],[-5.958,6.765],[-5.961,0],[-5.957,-7.748]],"c":true}]},{"t":30,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"t":5,"s":[0]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]} \ No newline at end of file
diff --git a/packages/SystemUI/res/raw/audio_bars_playing.json b/packages/SystemUI/res/raw/audio_bars_playing.json
new file mode 100644
index 000000000000..6ee8e1915f36
--- /dev/null
+++ b/packages/SystemUI/res/raw/audio_bars_playing.json
@@ -0,0 +1 @@
+{"v":"5.7.13","fr":60,"ip":0,"op":121,"w":168,"h":168,"nm":"audio_bars_playing","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[120.75,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-22.725],[5.957,-16.983],[5.961,0],[5.958,17.391],[0,23.149],[-5.958,17.39],[-5.961,0],[-5.957,-16.998]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":38,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[-0.016,-14.1],[5.941,-8.358],[5.961,0],[5.958,8.516],[0,14.274],[-5.958,8.515],[-5.961,0],[-5.972,-8.373]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":70,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-22.725],[5.957,-16.983],[5.961,0],[5.958,17.391],[0,23.149],[-5.958,17.39],[-5.961,0],[-5.957,-16.998]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":102,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[-0.016,-14.1],[5.941,-8.358],[5.961,0],[5.958,8.516],[0,14.274],[-5.958,8.515],[-5.961,0],[-5.972,-8.373]],"c":true}]},{"t":120,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-22.725],[5.957,-16.983],[5.961,0],[5.958,17.391],[0,23.149],[-5.958,17.39],[-5.961,0],[-5.957,-16.998]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":121,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[102.5,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-38.225],[5.957,-32.483],[5.961,0],[5.958,32.016],[0,37.774],[-5.958,32.015],[-5.961,0],[-5.957,-32.498]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":32,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-19.1],[5.957,-13.358],[5.961,0],[5.958,13.641],[0,19.399],[-5.958,13.64],[-5.961,0],[-5.957,-13.373]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":65,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-38.225],[5.957,-32.483],[5.961,0],[5.958,32.016],[0,37.774],[-5.958,32.015],[-5.961,0],[-5.957,-32.498]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":97,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-19.1],[5.957,-13.358],[5.961,0],[5.958,13.641],[0,19.399],[-5.958,13.64],[-5.961,0],[-5.957,-13.373]],"c":true}]},{"t":120,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-38.225],[5.957,-32.483],[5.961,0],[5.958,32.016],[0,37.774],[-5.958,32.015],[-5.961,0],[-5.957,-32.498]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":121,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[65.75,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-25.1],[5.957,-19.358],[5.961,0],[5.958,19.516],[0,25.274],[-5.958,19.515],[-5.961,0],[-5.957,-19.373]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":29,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-15.85],[5.957,-10.108],[5.961,0],[5.958,10.516],[0,16.274],[-5.958,10.515],[-5.961,0],[-5.957,-10.123]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":59,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-25.1],[5.957,-19.358],[5.961,0],[5.958,19.516],[0,25.274],[-5.958,19.515],[-5.961,0],[-5.957,-19.373]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":91,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-15.85],[5.957,-10.108],[5.961,0],[5.958,10.516],[0,16.274],[-5.958,10.515],[-5.961,0],[-5.957,-10.123]],"c":true}]},{"t":120,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-25.1],[5.957,-19.358],[5.961,0],[5.958,19.516],[0,25.274],[-5.958,19.515],[-5.961,0],[-5.957,-19.373]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":121,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-18.6],[5.957,-12.858],[5.961,0],[5.958,13.141],[0,18.899],[-5.958,13.14],[-5.961,0],[-5.957,-12.873]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":24,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-9.225],[5.957,-3.483],[5.961,0],[5.958,3.766],[0,9.524],[-5.958,3.765],[-5.961,0],[-5.957,-3.498]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":54,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-18.6],[5.957,-12.858],[5.961,0],[5.958,13.141],[0,18.899],[-5.958,13.14],[-5.961,0],[-5.957,-12.873]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":86,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-9.225],[5.957,-3.483],[5.961,0],[5.958,3.766],[0,9.524],[-5.958,3.765],[-5.961,0],[-5.957,-3.498]],"c":true}]},{"t":120,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-18.6],[5.957,-12.858],[5.961,0],[5.958,13.141],[0,18.899],[-5.958,13.14],[-5.961,0],[-5.957,-12.873]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":121,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[47.25,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-13.475],[5.957,-7.733],[5.961,0],[5.958,6.766],[0,12.524],[-5.958,6.765],[-5.961,0],[-5.957,-7.748]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":19,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":48,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-13.475],[5.957,-7.733],[5.961,0],[5.958,6.766],[0,12.524],[-5.958,6.765],[-5.961,0],[-5.957,-7.748]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":81,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]},{"t":120,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-13.475],[5.957,-7.733],[5.961,0],[5.958,6.766],[0,12.524],[-5.958,6.765],[-5.961,0],[-5.957,-7.748]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":121,"st":0,"bm":0}],"markers":[{"tm":60,"cm":"1","dr":0}]} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
index 07bd813c2420..40a86dc3713e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
@@ -19,13 +19,12 @@ package com.android.keyguard
import android.content.Context
import android.view.View
import com.android.systemui.customization.R as customR
-import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.ui.view.KeyguardRootView
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.res.R
-import com.android.systemui.shared.R as sharedR
import com.android.systemui.shade.NotificationShadeWindowView
import com.android.systemui.shade.ShadeDisplayAware
+import com.android.systemui.shared.R as sharedR
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.END
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.START
@@ -55,16 +54,17 @@ constructor(
var statusViewCentered = false
private val filterKeyguardAndSplitShadeOnly: () -> Boolean = {
- statusBarStateController.getState() == KEYGUARD && !statusViewCentered }
+ statusBarStateController.getState() == KEYGUARD && !statusViewCentered
+ }
private val filterKeyguard: () -> Boolean = { statusBarStateController.getState() == KEYGUARD }
private val translateAnimator by lazy {
- val smartSpaceViews = if (MigrateClocksToBlueprint.isEnabled) {
- // Use scrollX instead of translationX as translation is already set by [AodBurnInLayer]
- val scrollXTranslation = { view: View, translation: Float ->
- view.scrollX = -translation.toInt()
- }
+ // Use scrollX instead of translationX as translation is already set by [AodBurnInLayer]
+ val scrollXTranslation = { view: View, translation: Float ->
+ view.scrollX = -translation.toInt()
+ }
+ val smartSpaceViews =
setOf(
ViewIdToTranslate(
viewId = sharedR.id.date_smartspace_view,
@@ -83,18 +83,8 @@ constructor(
direction = START,
shouldBeAnimated = filterKeyguard,
translateFunc = scrollXTranslation,
- )
+ ),
)
- } else {
- setOf(ViewIdToTranslate(
- viewId = R.id.keyguard_status_area,
- direction = START,
- shouldBeAnimated = filterKeyguard,
- translateFunc = { view, value ->
- (view as? KeyguardStatusAreaView)?.translateXFromUnfold = value
- }
- ))
- }
UnfoldConstantTranslateAnimator(
viewsIdToTranslate =
@@ -102,39 +92,39 @@ constructor(
ViewIdToTranslate(
viewId = customR.id.lockscreen_clock_view_large,
direction = START,
- shouldBeAnimated = filterKeyguardAndSplitShadeOnly
+ shouldBeAnimated = filterKeyguardAndSplitShadeOnly,
),
ViewIdToTranslate(
viewId = customR.id.lockscreen_clock_view,
direction = START,
- shouldBeAnimated = filterKeyguard
+ shouldBeAnimated = filterKeyguard,
),
ViewIdToTranslate(
viewId = R.id.notification_stack_scroller,
direction = END,
- shouldBeAnimated = filterKeyguardAndSplitShadeOnly
- )
+ shouldBeAnimated = filterKeyguardAndSplitShadeOnly,
+ ),
) + smartSpaceViews,
- progressProvider = unfoldProgressProvider
+ progressProvider = unfoldProgressProvider,
)
}
private val shortcutButtonsAnimator by lazy {
UnfoldConstantTranslateAnimator(
viewsIdToTranslate =
- setOf(
- ViewIdToTranslate(
- viewId = R.id.start_button,
- direction = START,
- shouldBeAnimated = filterKeyguard
+ setOf(
+ ViewIdToTranslate(
+ viewId = R.id.start_button,
+ direction = START,
+ shouldBeAnimated = filterKeyguard,
+ ),
+ ViewIdToTranslate(
+ viewId = R.id.end_button,
+ direction = END,
+ shouldBeAnimated = filterKeyguard,
+ ),
),
- ViewIdToTranslate(
- viewId = R.id.end_button,
- direction = END,
- shouldBeAnimated = filterKeyguard
- )
- ),
- progressProvider = unfoldProgressProvider
+ progressProvider = unfoldProgressProvider,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index 4c2dc41fb759..d8c628fd680b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -155,6 +155,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
override fun onAnimationEnd(animation: Animator) {
drawDwell = false
resetDwellAlpha()
+ invalidate()
}
})
start()
@@ -191,6 +192,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
override fun onAnimationEnd(animation: Animator) {
drawDwell = false
resetDwellAlpha()
+ invalidate()
}
})
start()
@@ -248,6 +250,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
override fun onAnimationEnd(animation: Animator) {
drawDwell = false
+ invalidate()
}
})
start()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index f549e64ca853..d0065c8b06c6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -39,7 +39,6 @@ import androidx.annotation.VisibleForTesting
import androidx.core.math.MathUtils
import com.android.app.animation.Interpolators
import com.android.internal.R
-import com.android.keyguard.KeyguardClockSwitchController
import com.android.keyguard.KeyguardViewController
import com.android.systemui.Flags.fasterUnlockTransition
import com.android.systemui.dagger.SysUISingleton
@@ -206,7 +205,7 @@ constructor(
fun onUnlockAnimationFinished() {}
}
- /** The SmartSpace view on the lockscreen, provided by [KeyguardClockSwitchController]. */
+ /** The SmartSpace view on the lockscreen. */
var lockscreenSmartspace: View? = null
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index a2ce4ec5ce9b..6d270b219c81 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -127,21 +127,18 @@ object KeyguardRootViewBinder {
if (Flags.nonTouchscreenDevicesBypassFalsing()) {
if (
event.action == MotionEvent.ACTION_DOWN &&
- event.buttonState == MotionEvent.BUTTON_PRIMARY &&
- !event.isTouchscreenSource()
+ event.buttonState == MotionEvent.BUTTON_PRIMARY &&
+ !event.isTouchscreenSource()
) {
consumed = true
} else if (
- event.action == MotionEvent.ACTION_UP &&
- !event.isTouchscreenSource()
+ event.action == MotionEvent.ACTION_UP && !event.isTouchscreenSource()
) {
statusBarKeyguardViewManager?.showBouncer(true)
consumed = true
}
}
- viewModel.setRootViewLastTapPosition(
- Point(event.x.toInt(), event.y.toInt())
- )
+ viewModel.setRootViewLastTapPosition(Point(event.x.toInt(), event.y.toInt()))
}
consumed
}
@@ -172,7 +169,6 @@ object KeyguardRootViewBinder {
launch("$TAG#alpha") {
viewModel.alpha(viewState).collect { alpha ->
view.alpha = alpha
- childViews[statusViewId]?.alpha = alpha
childViews[burnInLayerId]?.alpha = alpha
}
}
@@ -253,18 +249,6 @@ object KeyguardRootViewBinder {
}
launch {
- viewModel.burnInLayerAlpha.collect { alpha ->
- childViews[statusViewId]?.alpha = alpha
- }
- }
-
- launch {
- viewModel.lockscreenStateAlpha(viewState).collect { alpha ->
- childViews[statusViewId]?.alpha = alpha
- }
- }
-
- launch {
viewModel.scale.collect { scaleViewModel ->
if (scaleViewModel.scaleClockOnly) {
// For clocks except weather clock, we have scale transition besides
@@ -553,7 +537,6 @@ object KeyguardRootViewBinder {
return device?.supportsSource(InputDevice.SOURCE_TOUCHSCREEN) == true
}
- private val statusViewId = R.id.keyguard_status_view
private val burnInLayerId = R.id.burn_in_layer
private val aodNotificationIconContainerId = R.id.aod_notification_icon_container
private val largeClockId = customR.id.lockscreen_clock_view_large
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index 090b65922d2d..6fb31c0e4191 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -48,19 +48,16 @@ import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
import androidx.core.view.isInvisible
-import com.android.internal.policy.SystemBarUtils
import com.android.keyguard.ClockEventController
-import com.android.keyguard.KeyguardClockSwitch
import com.android.systemui.animation.view.LaunchableImageView
import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.communal.ui.binder.CommunalTutorialIndicatorViewBinder
import com.android.systemui.communal.ui.viewmodel.CommunalTutorialIndicatorViewModel
-import com.android.systemui.coroutines.newTracingContext
+import com.android.systemui.customization.R as customR
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.model.ClockSizeSetting
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewClockViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewSmartspaceViewBinder
@@ -80,7 +77,6 @@ import com.android.systemui.res.R
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shared.clocks.ClockRegistry
-import com.android.systemui.shared.clocks.DefaultClockController
import com.android.systemui.shared.clocks.shared.model.ClockPreviewConstants
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants
@@ -91,18 +87,13 @@ import com.android.systemui.util.settings.SecureSettings
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.json.JSONException
import org.json.JSONObject
-import com.android.app.tracing.coroutines.launchTraced as launch
-import com.android.systemui.customization.R as customR
/** Renders the preview of the lock screen. */
class KeyguardPreviewRenderer
@@ -110,7 +101,6 @@ class KeyguardPreviewRenderer
@AssistedInject
constructor(
@Application private val context: Context,
- @Application applicationScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
@Main private val mainHandler: Handler,
@Background private val backgroundDispatcher: CoroutineDispatcher,
@@ -157,8 +147,6 @@ constructor(
val surfacePackage: SurfaceControlViewHost.SurfacePackage
get() = checkNotNull(host.surfacePackage)
- private lateinit var largeClockHostView: FrameLayout
- private lateinit var smallClockHostView: FrameLayout
private var smartSpaceView: View? = null
private val disposables = DisposableHandles()
@@ -166,29 +154,18 @@ constructor(
private val shortcutsBindings = mutableSetOf<KeyguardQuickAffordanceViewBinder.Binding>()
- private val coroutineScope: CoroutineScope
-
@Style.Type private var themeStyle: Int? = null
init {
- coroutineScope =
- CoroutineScope(
- applicationScope.coroutineContext +
- Job() +
- newTracingContext("KeyguardPreviewRenderer")
- )
- disposables += DisposableHandle { coroutineScope.cancel() }
clockController.setFallbackWeatherData(WeatherData.getPlaceholderWeatherData())
-
quickAffordancesCombinedViewModel.enablePreviewMode(
initiallySelectedSlotId =
- bundle.getString(KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID)
- ?: KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
+ bundle.getString(KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID)
+ ?: KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance,
)
- if (MigrateClocksToBlueprint.isEnabled) {
- clockViewModel.shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance
- }
+
+ clockViewModel.shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance
runBlocking(mainDispatcher) {
host =
SurfaceControlViewHost(
@@ -348,6 +325,7 @@ constructor(
smartSpaceView?.alpha = if (shouldHighlightSelectedAffordance) DIM_ALPHA else 1.0f
}
+ @OptIn(ExperimentalCoroutinesApi::class)
private fun setupKeyguardRootView(previewContext: Context, rootView: FrameLayout) {
val keyguardRootView = KeyguardRootView(previewContext, null)
rootView.addView(
@@ -358,34 +336,23 @@ constructor(
),
)
- setUpUdfps(
- previewContext,
- if (MigrateClocksToBlueprint.isEnabled) keyguardRootView else rootView,
- )
+ setUpUdfps(previewContext, keyguardRootView)
setupShortcuts(keyguardRootView)
if (!shouldHideClock) {
setUpClock(previewContext, rootView)
- if (MigrateClocksToBlueprint.isEnabled) {
- KeyguardPreviewClockViewBinder.bind(
- keyguardRootView,
- clockViewModel,
- clockRegistry,
- ::updateClockAppearance,
- ClockPreviewConfig(
- previewContext,
- getPreviewShadeLayoutWide(display!!),
- SceneContainerFlag.isEnabled,
- ),
- )
- } else {
- KeyguardPreviewClockViewBinder.bind(
- largeClockHostView,
- smallClockHostView,
- clockViewModel,
- )
- }
+ KeyguardPreviewClockViewBinder.bind(
+ keyguardRootView,
+ clockViewModel,
+ clockRegistry,
+ ::updateClockAppearance,
+ ClockPreviewConfig(
+ previewContext,
+ getPreviewShadeLayoutWide(display!!),
+ SceneContainerFlag.isEnabled,
+ ),
+ )
}
setUpSmartspace(previewContext, rootView)
@@ -451,82 +418,22 @@ constructor(
.inflate(R.layout.udfps_keyguard_preview, parentView, false) as View
// Place the UDFPS view in the proper sensor location
- if (MigrateClocksToBlueprint.isEnabled) {
- val lockId = KeyguardPreviewClockViewBinder.lockId
- finger.id = lockId
- parentView.addView(finger)
- val cs = ConstraintSet()
- cs.clone(parentView as ConstraintLayout)
- cs.apply {
- constrainWidth(lockId, sensorBounds.width())
- constrainHeight(lockId, sensorBounds.height())
- connect(lockId, TOP, PARENT_ID, TOP, sensorBounds.top)
- connect(lockId, START, PARENT_ID, START, sensorBounds.left)
- }
- cs.applyTo(parentView)
- } else {
- val fingerprintLayoutParams =
- FrameLayout.LayoutParams(sensorBounds.width(), sensorBounds.height())
- fingerprintLayoutParams.setMarginsRelative(
- sensorBounds.left,
- sensorBounds.top,
- sensorBounds.right,
- sensorBounds.bottom,
- )
- parentView.addView(finger, fingerprintLayoutParams)
+ val lockId = KeyguardPreviewClockViewBinder.lockId
+ finger.id = lockId
+ parentView.addView(finger)
+ val cs = ConstraintSet()
+ cs.clone(parentView as ConstraintLayout)
+ cs.apply {
+ constrainWidth(lockId, sensorBounds.width())
+ constrainHeight(lockId, sensorBounds.height())
+ connect(lockId, TOP, PARENT_ID, TOP, sensorBounds.top)
+ connect(lockId, START, PARENT_ID, START, sensorBounds.left)
}
+ cs.applyTo(parentView)
}
private fun setUpClock(previewContext: Context, parentView: ViewGroup) {
val resources = parentView.resources
- if (!MigrateClocksToBlueprint.isEnabled) {
- largeClockHostView = FrameLayout(previewContext)
- largeClockHostView.layoutParams =
- FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.MATCH_PARENT,
- )
- largeClockHostView.isInvisible = true
- parentView.addView(largeClockHostView)
-
- smallClockHostView = FrameLayout(previewContext)
- val layoutParams =
- FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.WRAP_CONTENT,
- resources.getDimensionPixelSize(customR.dimen.small_clock_height),
- )
- layoutParams.topMargin =
- SystemBarUtils.getStatusBarHeight(previewContext) +
- resources.getDimensionPixelSize(customR.dimen.small_clock_padding_top)
- smallClockHostView.layoutParams = layoutParams
- smallClockHostView.setPaddingRelative(
- /* start = */ resources.getDimensionPixelSize(customR.dimen.clock_padding_start),
- /* top = */ 0,
- /* end = */ 0,
- /* bottom = */ 0,
- )
- smallClockHostView.clipChildren = false
- parentView.addView(smallClockHostView)
- smallClockHostView.isInvisible = true
- }
-
- // TODO (b/283465254): Move the listeners to KeyguardClockRepository
- if (!MigrateClocksToBlueprint.isEnabled) {
- val clockChangeListener =
- object : ClockRegistry.ClockChangeListener {
- override fun onCurrentClockChanged() {
- onClockChanged()
- }
- }
- clockRegistry.registerClockChangeListener(clockChangeListener)
- disposables += DisposableHandle {
- clockRegistry.unregisterClockChangeListener(clockChangeListener)
- }
-
- clockController.registerListeners(parentView)
- disposables += DisposableHandle { clockController.unregisterListeners() }
- }
-
val receiver =
object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
@@ -544,38 +451,9 @@ constructor(
},
)
disposables += DisposableHandle { broadcastDispatcher.unregisterReceiver(receiver) }
-
- if (!MigrateClocksToBlueprint.isEnabled) {
- val layoutChangeListener =
- View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
- if (clockController.clock !is DefaultClockController) {
- clockController.clock
- ?.largeClock
- ?.events
- ?.onTargetRegionChanged(
- KeyguardClockSwitch.getLargeClockRegion(parentView)
- )
- clockController.clock
- ?.smallClock
- ?.events
- ?.onTargetRegionChanged(
- KeyguardClockSwitch.getSmallClockRegion(parentView)
- )
- }
- }
- parentView.addOnLayoutChangeListener(layoutChangeListener)
- disposables += DisposableHandle {
- parentView.removeOnLayoutChangeListener(layoutChangeListener)
- }
- }
-
- onClockChanged()
}
private suspend fun updateClockAppearance(clock: ClockController, resources: Resources) {
- if (!MigrateClocksToBlueprint.isEnabled) {
- clockController.clock = clock
- }
val colors = wallpaperColors
if (clockRegistry.seedColor == null && colors != null) {
// Seed color null means users do not override any color on the clock. The default
@@ -601,9 +479,7 @@ constructor(
// In clock preview, we should have a seed color for clock
// before setting clock to clockEventController to avoid updateColor with seedColor == null
// So in update colors, it should already have the correct theme in clockFaceController
- if (MigrateClocksToBlueprint.isEnabled) {
- clockController.clock = clock
- }
+ clockController.clock = clock
// When set clock to clockController,it will reset fontsize based on context.resources
// We need to override it with overlaid resources
clock.largeClock.events.onFontSettingChanged(
@@ -611,19 +487,6 @@ constructor(
)
}
- private fun onClockChanged() {
- if (MigrateClocksToBlueprint.isEnabled) {
- return
- }
- coroutineScope.launch {
- val clock = clockRegistry.createCurrentClock()
- clockController.clock = clock
- updateClockAppearance(clock, context.resources)
- updateLargeClock(clock)
- updateSmallClock(clock)
- }
- }
-
private fun setupCommunalTutorialIndicator(keyguardRootView: ConstraintLayout) {
keyguardRootView.findViewById<TextView>(R.id.communal_tutorial_indicator)?.let {
indicatorView ->
@@ -657,34 +520,6 @@ constructor(
}
}
- private fun updateLargeClock(clock: ClockController) {
- if (MigrateClocksToBlueprint.isEnabled) {
- return
- }
- clock.largeClock.events.onTargetRegionChanged(
- KeyguardClockSwitch.getLargeClockRegion(largeClockHostView)
- )
- if (shouldHighlightSelectedAffordance) {
- clock.largeClock.view.alpha = DIM_ALPHA
- }
- largeClockHostView.removeAllViews()
- largeClockHostView.addView(clock.largeClock.view)
- }
-
- private fun updateSmallClock(clock: ClockController) {
- if (MigrateClocksToBlueprint.isEnabled) {
- return
- }
- clock.smallClock.events.onTargetRegionChanged(
- KeyguardClockSwitch.getSmallClockRegion(smallClockHostView)
- )
- if (shouldHighlightSelectedAffordance) {
- clock.smallClock.view.alpha = DIM_ALPHA
- }
- smallClockHostView.removeAllViews()
- smallClockHostView.addView(clock.smallClock.view)
- }
-
private fun getPreviewShadeLayoutWide(display: Display): Boolean {
return if (display.displayId == 0) {
shadeInteractor.isShadeLayoutWide.value
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
index 729759a9ad00..5d463f72d8b2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
@@ -23,7 +23,6 @@ import androidx.constraintlayout.widget.ConstraintSet.END
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
-import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.res.R
import com.android.systemui.shade.NotificationPanelView
import com.android.systemui.shade.ShadeDisplayAware
@@ -50,16 +49,13 @@ constructor(
sharedNotificationContainerBinder,
) {
override fun applyConstraints(constraintSet: ConstraintSet) {
- if (!MigrateClocksToBlueprint.isEnabled) {
- return
- }
constraintSet.apply {
connect(
R.id.nssl_placeholder,
TOP,
PARENT_ID,
TOP,
- context.resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin)
+ context.resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin),
)
connect(R.id.nssl_placeholder, START, PARENT_ID, START)
connect(R.id.nssl_placeholder, END, PARENT_ID, END)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
index 1c897237fe89..fb311a533aa2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
@@ -24,7 +24,6 @@ import com.android.app.animation.Interpolators
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -194,12 +193,7 @@ constructor(
(!useAltAod) && keyguardClockViewModel.clockSize.value == ClockSize.LARGE
val burnInY = MathUtils.lerp(0, burnIn.translationY, interpolated).toInt()
- val translationY =
- if (MigrateClocksToBlueprint.isEnabled) {
- max(params.topInset - params.minViewY, burnInY)
- } else {
- max(params.topInset, params.minViewY + burnInY) - params.minViewY
- }
+ val translationY = max(params.topInset - params.minViewY, burnInY)
BurnInModel(
translationX = MathUtils.lerp(0, burnIn.translationX, interpolated).toInt(),
translationY = translationY,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 9066d466ceca..eaba5d5a149c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -29,7 +29,6 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.PulseExpansionInteractor
import com.android.systemui.keyguard.shared.model.Edge
-import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
@@ -130,7 +129,6 @@ constructor(
PrimaryBouncerToLockscreenTransitionViewModel,
private val screenOffAnimationController: ScreenOffAnimationController,
private val aodBurnInViewModel: AodBurnInViewModel,
- private val aodAlphaViewModel: AodAlphaViewModel,
private val shadeInteractor: ShadeInteractor,
) {
val burnInLayerVisibility: Flow<Int> =
@@ -284,15 +282,6 @@ constructor(
.distinctUntilChanged()
}
- /** Specific alpha value for elements visible during [KeyguardState.LOCKSCREEN] */
- @Deprecated("only used for legacy status view")
- fun lockscreenStateAlpha(viewState: ViewStateAccessor): Flow<Float> {
- return aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState)
- }
-
- /** For elements that appear and move during the animation -> AOD */
- val burnInLayerAlpha: Flow<Float> = aodAlphaViewModel.alpha
-
val translationY: Flow<Float> = aodBurnInViewModel.movement.map { it.translationY.toFloat() }
val translationX: Flow<StateToValue> =
diff --git a/packages/SystemUI/src/com/android/systemui/lottie/LottieTaskExt.kt b/packages/SystemUI/src/com/android/systemui/lottie/LottieTaskExt.kt
new file mode 100644
index 000000000000..dd2525f5ca45
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/lottie/LottieTaskExt.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.lottie
+
+import com.airbnb.lottie.LottieComposition
+import com.airbnb.lottie.LottieListener
+import com.airbnb.lottie.LottieTask
+import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+/**
+ * Suspends until [LottieTask] is finished with a result or a failure.
+ *
+ * @return result of the [LottieTask] when it's successful
+ */
+suspend fun LottieTask<LottieComposition>.await() =
+ suspendCancellableCoroutine<LottieComposition> { continuation ->
+ val resultListener =
+ LottieListener<LottieComposition> { result ->
+ with(continuation) { if (!isCancelled && !isCompleted) resume(result) }
+ }
+ val failureListener =
+ LottieListener<Throwable> { throwable ->
+ with(continuation) {
+ if (!isCancelled && !isCompleted) resumeWithException(throwable)
+ }
+ }
+ addListener(resultListener)
+ addFailureListener(failureListener)
+ continuation.invokeOnCancellation {
+ removeListener(resultListener)
+ removeFailureListener(failureListener)
+ }
+ }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/NotificationScrimClip.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/NotificationScrimClip.kt
index 790793eab258..3049a40f18c4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/NotificationScrimClip.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/NotificationScrimClip.kt
@@ -17,16 +17,16 @@
package com.android.systemui.qs.composefragment.ui
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.drawWithCache
+import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.ClipOp
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.CompositingStrategy
import androidx.compose.ui.graphics.drawscope.clipRect
-import androidx.compose.ui.graphics.layer.CompositingStrategy
-import androidx.compose.ui.graphics.layer.drawLayer
+import androidx.compose.ui.graphics.graphicsLayer
/**
* Clipping modifier for clipping out the notification scrim as it slides over QS. It will clip out
@@ -34,16 +34,16 @@ import androidx.compose.ui.graphics.layer.drawLayer
* from the QS container.
*/
fun Modifier.notificationScrimClip(clipParams: () -> NotificationScrimClipParams): Modifier {
- return this.drawWithCache {
+ return this.graphicsLayer { compositingStrategy = CompositingStrategy.Offscreen }
+ .drawWithContent {
+ drawContent()
val params = clipParams()
val left = -params.leftInset.toFloat()
val right = size.width + params.rightInset.toFloat()
val top = params.top.toFloat()
val bottom = params.bottom.toFloat()
- val graphicsLayer = obtainGraphicsLayer()
- graphicsLayer.compositingStrategy = CompositingStrategy.Offscreen
- graphicsLayer.record {
- drawContent()
+ val clipSize = Size(right - left, bottom - top)
+ if (!clipSize.isEmpty()) {
clipRect {
drawRoundRect(
color = Color.Black,
@@ -54,9 +54,6 @@ fun Modifier.notificationScrimClip(clipParams: () -> NotificationScrimClipParams
)
}
}
- onDrawWithContent {
- drawLayer(graphicsLayer)
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 873059ee08db..e7fa27159e9e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -675,17 +675,11 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
}
private void add() {
- if (addFromPosition(getLayoutPosition())) {
- itemView.announceForAccessibility(
- itemView.getContext().getText(R.string.accessibility_qs_edit_tile_added));
- }
+ addFromPosition(getLayoutPosition());
}
private void remove() {
- if (removeFromPosition(getLayoutPosition())) {
- itemView.announceForAccessibility(
- itemView.getContext().getText(R.string.accessibility_qs_edit_tile_removed));
- }
+ removeFromPosition(getLayoutPosition());
}
boolean isCurrentTile() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
index 19b45d50c594..7516ca030d4b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
@@ -193,7 +193,7 @@ public class InternetAdapter extends RecyclerView.Adapter<InternetAdapter.Intern
if (mJob == null) {
mJob = WifiUtils.checkWepAllowed(mContext, mCoroutineScope, wifiEntry.getSsid(),
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, intent -> {
- mInternetDialogController.startActivity(intent, view);
+ mInternetDialogController.startActivityForDialog(intent);
return null;
}, () -> {
wifiConnect(wifiEntry, view);
@@ -211,7 +211,7 @@ public class InternetAdapter extends RecyclerView.Adapter<InternetAdapter.Intern
true /* connectForCaller */);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
- mContext.startActivity(intent);
+ mInternetDialogController.startActivityForDialog(intent);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index dbe1ae90b3f6..7036ef914a1c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -781,6 +781,10 @@ public class InternetDialogController implements AccessPointController.AccessPoi
mActivityStarter.postStartActivityDismissingKeyguard(intent, 0, controller);
}
+ void startActivityForDialog(Intent intent) {
+ mActivityStarter.startActivity(intent, false /* dismissShade */);
+ }
+
void launchNetworkSetting(View view) {
startActivity(getSettingsIntent(), view);
}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
index a382cf921152..e08114f6c3cd 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
@@ -21,10 +21,8 @@ import android.content.Context
import android.hardware.devicestate.DeviceStateManager
import android.os.PowerManager
import android.provider.Settings
-import androidx.core.view.OneShotPreDrawListener
import com.android.internal.util.LatencyTracker
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.ToAodFoldTransitionInteractor
@@ -125,11 +123,7 @@ constructor(
private val shadeFoldAnimator: ShadeFoldAnimator
get() {
- return if (MigrateClocksToBlueprint.isEnabled) {
- foldTransitionInteractor.get().foldAnimator
- } else {
- shadeViewController.shadeFoldAnimator
- }
+ return foldTransitionInteractor.get().foldAnimator
}
private fun setAnimationState(playing: Boolean) {
@@ -164,15 +158,7 @@ constructor(
setAnimationState(playing = true)
shadeFoldAnimator.prepareFoldToAodAnimation()
- // We don't need to wait for the scrim as it is already displayed
- // but we should wait for the initial animation preparations to be drawn
- // (setting initial alpha/translation)
- // TODO(b/254878364): remove this call to NPVC.getView()
- if (!MigrateClocksToBlueprint.isEnabled) {
- shadeFoldAnimator.view?.let { OneShotPreDrawListener.add(it, onReady) }
- } else {
- onReady.run()
- }
+ onReady.run()
} else {
// No animation, call ready callback immediately
onReady.run()
@@ -252,7 +238,7 @@ constructor(
if (isFolded) {
foldToAodLatencyTracker.onFolded()
}
- }
+ },
)
/**
@@ -272,6 +258,7 @@ constructor(
latencyTracker.onActionStart(LatencyTracker.ACTION_FOLD_TO_AOD)
}
}
+
/**
* Called once the Fold -> AOD animation is started.
*
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt
index 2e1f82d56fc4..70e342f3eefb 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt
@@ -17,45 +17,28 @@
package com.android.systemui.volume.dialog.settings.ui.binder
import android.view.View
-import com.android.systemui.lifecycle.WindowLifecycleState
-import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.lifecycle.setSnapshotBinding
-import com.android.systemui.lifecycle.viewModel
+import android.widget.ImageButton
import com.android.systemui.res.R
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
import com.android.systemui.volume.dialog.settings.ui.viewmodel.VolumeDialogSettingsButtonViewModel
import javax.inject.Inject
-import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@VolumeDialogScope
class VolumeDialogSettingsButtonViewBinder
@Inject
-constructor(private val viewModelFactory: VolumeDialogSettingsButtonViewModel.Factory) {
+constructor(private val viewModel: VolumeDialogSettingsButtonViewModel) {
- fun bind(view: View) {
- with(view) {
- val button = requireViewById<View>(R.id.volume_dialog_settings)
- repeatWhenAttached {
- viewModel(
- traceName = "VolumeDialogViewBinder",
- minWindowLifecycleState = WindowLifecycleState.ATTACHED,
- factory = { viewModelFactory.create() },
- ) { viewModel ->
- setSnapshotBinding {
- viewModel.isVisible
- .onEach { isVisible ->
- visibility = if (isVisible) View.VISIBLE else View.GONE
- }
- .launchIn(this)
+ fun CoroutineScope.bind(view: View) {
+ val button = view.requireViewById<ImageButton>(R.id.volume_dialog_settings)
+ viewModel.isVisible
+ .onEach { isVisible -> button.visibility = if (isVisible) View.VISIBLE else View.GONE }
+ .launchIn(this)
- button.setOnClickListener { viewModel.onButtonClicked() }
- }
+ viewModel.icon.onEach { button.setImageDrawable(it) }.launchIn(this)
- awaitCancellation()
- }
- }
- }
+ button.setOnClickListener { viewModel.onButtonClicked() }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt
index 015d773b2c02..03442dbcde66 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt
@@ -14,27 +14,206 @@
* limitations under the License.
*/
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
package com.android.systemui.volume.dialog.settings.ui.viewmodel
-import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.annotation.SuppressLint
+import android.content.Context
+import android.graphics.ColorFilter
+import android.graphics.drawable.Drawable
+import android.media.session.PlaybackState
+import androidx.annotation.ColorInt
+import com.airbnb.lottie.LottieComposition
+import com.airbnb.lottie.LottieCompositionFactory
+import com.airbnb.lottie.LottieDrawable
+import com.airbnb.lottie.LottieProperty
+import com.airbnb.lottie.SimpleColorFilter
+import com.airbnb.lottie.model.KeyPath
+import com.airbnb.lottie.value.LottieValueCallback
+import com.android.internal.R as internalR
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.UiBackground
+import com.android.systemui.lottie.await
+import com.android.systemui.res.R
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
import com.android.systemui.volume.dialog.settings.domain.VolumeDialogSettingsButtonInteractor
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
+import com.android.systemui.volume.panel.shared.model.filterData
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.resume
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.FlowCollector
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.buffer
+import kotlinx.coroutines.flow.distinctUntilChangedBy
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.runningFold
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.transform
+import kotlinx.coroutines.suspendCancellableCoroutine
class VolumeDialogSettingsButtonViewModel
-@AssistedInject
-constructor(private val interactor: VolumeDialogSettingsButtonInteractor) {
+@Inject
+constructor(
+ @Application private val context: Context,
+ @UiBackground private val uiBgCoroutineContext: CoroutineContext,
+ @VolumeDialog private val coroutineScope: CoroutineScope,
+ mediaOutputInteractor: MediaOutputInteractor,
+ private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,
+ private val interactor: VolumeDialogSettingsButtonInteractor,
+) {
+
+ @SuppressLint("UseCompatLoadingForDrawables")
+ private val drawables: Flow<Drawables> =
+ flow {
+ val color = context.getColor(internalR.color.materialColorPrimary)
+ emit(
+ Drawables(
+ start =
+ LottieCompositionFactory.fromRawRes(context, R.raw.audio_bars_in)
+ .await()
+ .toDrawable { setColor(color) },
+ playing =
+ LottieCompositionFactory.fromRawRes(context, R.raw.audio_bars_playing)
+ .await()
+ .toDrawable {
+ repeatCount = LottieDrawable.INFINITE
+ repeatMode = LottieDrawable.RESTART
+ setColor(color)
+ },
+ stop =
+ LottieCompositionFactory.fromRawRes(context, R.raw.audio_bars_out)
+ .await()
+ .toDrawable { setColor(color) },
+ idle = context.getDrawable(R.drawable.audio_bars_idle)!!,
+ )
+ )
+ }
+ .buffer()
+ .flowOn(uiBgCoroutineContext)
+ .stateIn(coroutineScope, SharingStarted.Eagerly, null)
+ .filterNotNull()
val isVisible = interactor.isVisible
+ val icon: Flow<Drawable> =
+ mediaOutputInteractor.defaultActiveMediaSession
+ .filterData()
+ .flatMapLatest { session ->
+ if (session == null) {
+ flowOf(null)
+ } else {
+ mediaDeviceSessionInteractor.playbackState(session)
+ }
+ }
+ .runningFold(null) { playbackStates: PlaybackStates?, playbackState: PlaybackState? ->
+ val isCurrentActive = playbackState?.isActive ?: false
+ if (playbackStates != null && isCurrentActive == playbackState?.isActive) {
+ return@runningFold playbackStates
+ }
+ playbackStates?.copy(
+ isPreviousActive = playbackStates.isCurrentActive,
+ isCurrentActive = isCurrentActive,
+ ) ?: PlaybackStates(isPreviousActive = null, isCurrentActive = isCurrentActive)
+ }
+ .filterNotNull()
+ // only apply the most recent state if we wait for the animation.
+ .buffer(capacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
+ // distinct again because the changed state might've been dropped by the buffer
+ .distinctUntilChangedBy { it.isCurrentActive }
+ .transform { emitDrawables(it) }
+ .runningFold(null) { previous: Drawable?, current: Drawable ->
+ // wait for the previous animation to finish before starting the new one
+ // this also waits for the current loop of the playing animation to finish
+ (previous as? LottieDrawable)?.awaitFinish()
+ (current as? LottieDrawable)?.start()
+ current
+ }
+ .filterNotNull()
+
+ private suspend fun FlowCollector<Drawable>.emitDrawables(playbackStates: PlaybackStates) {
+ val animations = drawables.first()
+ val stateChanged =
+ playbackStates.isPreviousActive != null &&
+ playbackStates.isPreviousActive != playbackStates.isCurrentActive
+ if (playbackStates.isCurrentActive) {
+ if (stateChanged) {
+ emit(animations.start)
+ }
+ emit(animations.playing)
+ } else {
+ if (stateChanged) {
+ emit(animations.stop)
+ }
+ emit(animations.idle)
+ }
+ }
fun onButtonClicked() {
interactor.onButtonClicked()
}
- @VolumeDialogScope
- @AssistedFactory
- interface Factory {
+ private data class PlaybackStates(val isPreviousActive: Boolean?, val isCurrentActive: Boolean)
+
+ private data class Drawables(
+ val start: LottieDrawable,
+ val playing: LottieDrawable,
+ val stop: LottieDrawable,
+ val idle: Drawable,
+ )
+}
+
+private fun LottieComposition.toDrawable(setup: LottieDrawable.() -> Unit = {}): LottieDrawable =
+ LottieDrawable().also { drawable ->
+ drawable.composition = this
+ drawable.setup()
+ }
- fun create(): VolumeDialogSettingsButtonViewModel
+/** Suspends until current loop of the repeating animation is finished */
+private suspend fun LottieDrawable.awaitFinish() = suspendCancellableCoroutine { continuation ->
+ if (!isRunning) {
+ continuation.resume(Unit)
+ return@suspendCancellableCoroutine
}
+ val listener =
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationRepeat(animation: Animator) {
+ continuation.resume(Unit)
+ removeAnimatorListener(this)
+ }
+
+ override fun onAnimationEnd(animation: Animator) {
+ continuation.resume(Unit)
+ removeAnimatorListener(this)
+ }
+
+ override fun onAnimationCancel(animation: Animator) {
+ continuation.resume(Unit)
+ removeAnimatorListener(this)
+ }
+ }
+ addAnimatorListener(listener)
+ continuation.invokeOnCancellation { removeAnimatorListener(listener) }
+}
+
+/**
+ * Overrides colors of the [LottieDrawable] to a specified [color]
+ *
+ * @see com.airbnb.lottie.LottieAnimationView
+ */
+private fun LottieDrawable.setColor(@ColorInt color: Int) {
+ val callback = LottieValueCallback<ColorFilter>(SimpleColorFilter(color))
+ addValueCallback(KeyPath("**"), LottieProperty.COLOR_FILTER, callback)
}
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 f30524638150..faf06b942cab 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
@@ -26,7 +26,7 @@ import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderStateModel
import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderViewModel
import com.android.systemui.volume.dialog.ui.utils.JankListenerFactory
-import com.android.systemui.volume.dialog.ui.utils.awaitAnimation
+import com.android.systemui.volume.dialog.ui.utils.suspendAnimate
import com.google.android.material.slider.LabelFormatter
import com.google.android.material.slider.Slider
import javax.inject.Inject
@@ -84,5 +84,5 @@ private suspend fun Slider.setValueAnimated(
interpolator = DecelerateInterpolator()
addListener(jankListener)
}
- .awaitAnimation<Float> { value = it }
+ .suspendAnimate<Float> { value = it }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt
index 10cf615ce0ce..5f124806dac7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt
@@ -22,6 +22,7 @@ import android.animation.ValueAnimator
import android.view.ViewPropertyAnimator
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.SpringAnimation
+import com.airbnb.lottie.LottieDrawable
import kotlin.coroutines.resume
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.suspendCancellableCoroutine
@@ -66,7 +67,7 @@ suspend fun ViewPropertyAnimator.suspendAnimate(
* is cancelled.
*/
@Suppress("UNCHECKED_CAST")
-suspend fun <T> ValueAnimator.awaitAnimation(onValueChanged: (T) -> Unit) {
+suspend fun <T> ValueAnimator.suspendAnimate(onValueChanged: (T) -> Unit) {
suspendCancellableCoroutine { continuation ->
addListener(
object : AnimatorListenerAdapter() {
@@ -103,6 +104,29 @@ suspend fun SpringAnimation.suspendAnimate(
}
}
+/**
+ * Starts the animation and suspends until it's finished. Cancels the animation if the running
+ * coroutine is cancelled.
+ */
+suspend fun LottieDrawable.suspendAnimate() = suspendCancellableCoroutine { continuation ->
+ val listener =
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ continuation.resumeIfCan(Unit)
+ }
+
+ override fun onAnimationCancel(animation: Animator) {
+ continuation.resumeIfCan(Unit)
+ }
+ }
+ addAnimatorListener(listener)
+ start()
+ continuation.invokeOnCancellation {
+ removeAnimatorListener(listener)
+ stop()
+ }
+}
+
private fun <T> CancellableContinuation<T>.resumeIfCan(value: T) {
if (!isCancelled && !isCompleted) {
resume(value)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt
index 6e1ebc820b08..12e624cae4d4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt
@@ -19,10 +19,10 @@ package com.android.systemui.volume.panel.component.mediaoutput.domain.interacto
import android.media.session.MediaController
import android.media.session.PlaybackState
import com.android.settingslib.volume.data.repository.MediaControllerRepository
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaControllerChangeModel
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
-import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -38,7 +38,7 @@ import kotlinx.coroutines.withContext
/** Allows to observe and change [MediaDeviceSession] state. */
@OptIn(ExperimentalCoroutinesApi::class)
-@VolumePanelScope
+@SysUISingleton
class MediaDeviceSessionInteractor
@Inject
constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
index b3848a6d7817..2973e11c365d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
@@ -24,12 +24,13 @@ import androidx.annotation.WorkerThread
import com.android.settingslib.media.MediaDevice
import com.android.settingslib.volume.data.repository.LocalMediaRepository
import com.android.settingslib.volume.data.repository.MediaControllerRepository
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.util.concurrency.Execution
import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory
import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSessions
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
-import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import com.android.systemui.volume.panel.shared.model.Result
import com.android.systemui.volume.panel.shared.model.filterData
import com.android.systemui.volume.panel.shared.model.wrapInResult
@@ -54,13 +55,13 @@ import kotlinx.coroutines.withContext
/** Provides observable models about the current media session state. */
@OptIn(ExperimentalCoroutinesApi::class)
-@VolumePanelScope
+@SysUISingleton
class MediaOutputInteractor
@Inject
constructor(
private val localMediaRepositoryFactory: LocalMediaRepositoryFactory,
private val packageManager: PackageManager,
- @VolumePanelScope private val coroutineScope: CoroutineScope,
+ @Application private val coroutineScope: CoroutineScope,
@Background private val backgroundCoroutineContext: CoroutineContext,
mediaControllerRepository: MediaControllerRepository,
private val mediaControllerInteractor: MediaControllerInteractor,
@@ -77,7 +78,7 @@ constructor(
.onStart { emit(activeSessions) }
}
.map { getMediaControllers(it) }
- .stateIn(coroutineScope, SharingStarted.Eagerly, MediaControllers(null, null))
+ .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), MediaControllers(null, null))
/** [MediaDeviceSessions] that contains currently active sessions. */
val activeMediaDeviceSessions: Flow<MediaDeviceSessions> =
@@ -89,7 +90,11 @@ constructor(
)
}
.flowOn(backgroundCoroutineContext)
- .stateIn(coroutineScope, SharingStarted.Eagerly, MediaDeviceSessions(null, null))
+ .stateIn(
+ coroutineScope,
+ SharingStarted.WhileSubscribed(),
+ MediaDeviceSessions(null, null),
+ )
/** Returns the default [MediaDeviceSession] from [activeMediaDeviceSessions] */
val defaultActiveMediaSession: StateFlow<Result<MediaDeviceSession?>> =
@@ -104,7 +109,7 @@ constructor(
}
.wrapInResult()
.flowOn(backgroundCoroutineContext)
- .stateIn(coroutineScope, SharingStarted.Eagerly, Result.Loading())
+ .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), Result.Loading())
private val localMediaRepository: Flow<LocalMediaRepository> =
defaultActiveMediaSession
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
index b26f0a6e71a3..782b24825bcf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
@@ -557,6 +557,13 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase {
}
@Test
+ public void startActivityForDialog_always_startActivityWithoutDismissShade() {
+ mInternetDialogController.startActivityForDialog(mock(Intent.class));
+
+ verify(mActivityStarter).startActivity(any(Intent.class), eq(false) /* dismissShade */);
+ }
+
+ @Test
public void launchWifiDetailsSetting_withNoWifiEntryKey_doNothing() {
mInternetDialogController.launchWifiDetailsSetting(null /* key */, mDialogLaunchView);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
index e47310727905..abbfa93edd17 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
@@ -87,7 +87,6 @@ val Kosmos.keyguardRootViewModel by Fixture {
primaryBouncerToLockscreenTransitionViewModel,
screenOffAnimationController = screenOffAnimationController,
aodBurnInViewModel = aodBurnInViewModel,
- aodAlphaViewModel = aodAlphaViewModel,
shadeInteractor = shadeInteractor,
)
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a184e905d0fa..50b6990c0c1c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -19396,9 +19396,6 @@ public class ActivityManagerService extends IActivityManager.Stub
creatorPackage);
if (creatorToken != null) {
extraIntent.setCreatorToken(creatorToken);
- // TODO remove Slog.wtf once proven FrameworkStatsLog works. b/375396329
- Slog.wtf(TAG, "A creator token is added to an intent. creatorPackage: "
- + creatorPackage + "; intent: " + extraIntent);
FrameworkStatsLog.write(INTENT_CREATOR_TOKEN_ADDED, creatorUid, false);
}
});
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 87f87c76725e..c82933c5069e 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -158,6 +158,7 @@ public class SettingsToPropertiesMapper {
"aoc",
"app_widgets",
"arc_next",
+ "art_cloud",
"art_mainline",
"art_performance",
"attack_tools",
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 2985ad330bc6..5740e16dc886 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2400,6 +2400,10 @@ public final class DisplayManagerService extends SystemService {
sendDisplayEventIfEnabledLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_BASIC_CHANGED);
applyDisplayChangedLocked(display);
+
+ if (mDisplayTopologyCoordinator != null) {
+ mDisplayTopologyCoordinator.onDisplayChanged(display.getDisplayInfoLocked());
+ }
}
private void applyDisplayChangedLocked(@NonNull LogicalDisplay display) {
diff --git a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
index 5b78726cc421..461a9f3f2a0d 100644
--- a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
+++ b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
@@ -85,13 +85,26 @@ class DisplayTopologyCoordinator {
}
/**
+ * Update the topology with display changes.
+ * @param info The new display info
+ */
+ void onDisplayChanged(DisplayInfo info) {
+ synchronized (mSyncRoot) {
+ if (mTopology.updateDisplay(info.displayId, getWidth(info), getHeight(info))) {
+ sendTopologyUpdateLocked();
+ }
+ }
+ }
+
+ /**
* Remove a display from the topology.
* @param displayId The logical display ID
*/
void onDisplayRemoved(int displayId) {
synchronized (mSyncRoot) {
- mTopology.removeDisplay(displayId);
- sendTopologyUpdateLocked();
+ if (mTopology.removeDisplay(displayId)) {
+ sendTopologyUpdateLocked();
+ }
}
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 0438a1bac662..0d6e502cf965 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -179,8 +179,29 @@ abstract class MediaRoute2Provider {
void onProviderStateChanged(@Nullable MediaRoute2Provider provider);
void onSessionCreated(@NonNull MediaRoute2Provider provider,
long requestId, @Nullable RoutingSessionInfo sessionInfo);
- void onSessionUpdated(@NonNull MediaRoute2Provider provider,
- @NonNull RoutingSessionInfo sessionInfo);
+
+ /**
+ * Called when there's a session info change.
+ *
+ * <p>If the provided {@code sessionInfo} has a null {@link
+ * RoutingSessionInfo#getClientPackageName()}, that means that it's applicable to all
+ * packages. We call this type of routing session "global". This is typically used for
+ * system provided {@link RoutingSessionInfo}. However, some applications may be exempted
+ * from the global routing sessions, because their media is being routed using a session
+ * different from the global routing session.
+ *
+ * @param provider The provider that owns the session that changed.
+ * @param sessionInfo The new {@link RoutingSessionInfo}.
+ * @param packageNamesWithRoutingSessionOverrides The names of packages that are not
+ * affected by global session changes. This set may only be non-empty when the {@code
+ * sessionInfo} is for the global session, and therefore has no {@link
+ * RoutingSessionInfo#getClientPackageName()}.
+ */
+ void onSessionUpdated(
+ @NonNull MediaRoute2Provider provider,
+ @NonNull RoutingSessionInfo sessionInfo,
+ Set<String> packageNamesWithRoutingSessionOverrides);
+
void onSessionReleased(@NonNull MediaRoute2Provider provider,
@NonNull RoutingSessionInfo sessionInfo);
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index 80d3c5c5c5ec..d6f7d3bdd4a4 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -16,6 +16,7 @@
package com.android.server.media;
+import static android.media.MediaRoute2ProviderService.REASON_REJECTED;
import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -499,6 +500,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider {
synchronized (mLock) {
var systemMediaSessionCallback = mRequestIdToSystemSessionRequest.get(requestId);
if (systemMediaSessionCallback != null) {
+ mRequestIdToSystemSessionRequest.remove(requestId);
mSystemSessionCallbacks.put(newSession.getOriginalId(), systemMediaSessionCallback);
systemMediaSessionCallback.onSessionUpdate(newSession);
return;
@@ -674,7 +676,11 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider {
private void dispatchSessionUpdated(RoutingSessionInfo session) {
mHandler.sendMessage(
- obtainMessage(mCallback::onSessionUpdated, this, session));
+ obtainMessage(
+ mCallback::onSessionUpdated,
+ this,
+ session,
+ /* packageNamesWithRoutingSessionOverrides= */ Set.of()));
}
private void dispatchSessionReleased(RoutingSessionInfo session) {
@@ -717,6 +723,19 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider {
for (RoutingSessionInfo sessionInfo : mSessionInfos) {
mCallback.onSessionReleased(this, sessionInfo);
}
+ if (Flags.enableMirroringInMediaRouter2()) {
+ for (var callback : mSystemSessionCallbacks.values()) {
+ callback.onSessionReleased();
+ }
+ mSystemSessionCallbacks.clear();
+ int requestsSize = mRequestIdToSystemSessionRequest.size();
+ for (int i = 0; i < requestsSize; i++) {
+ var callback = mRequestIdToSystemSessionRequest.valueAt(i);
+ var requestId = mRequestIdToSystemSessionRequest.keyAt(i);
+ callback.onRequestFailed(requestId, REASON_REJECTED);
+ }
+ mSystemSessionCallbacks.clear();
+ }
mSessionInfos.clear();
mReleasingSessions.clear();
mRequestIdToSessionCreationRequest.clear();
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 83ac05d9d4c3..5e6737a485af 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -2634,10 +2634,17 @@ class MediaRouter2ServiceImpl {
}
@Override
- public void onSessionUpdated(@NonNull MediaRoute2Provider provider,
- @NonNull RoutingSessionInfo sessionInfo) {
- sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionInfoChangedOnHandler,
- this, provider, sessionInfo));
+ public void onSessionUpdated(
+ @NonNull MediaRoute2Provider provider,
+ @NonNull RoutingSessionInfo sessionInfo,
+ Set<String> packageNamesWithRoutingSessionOverrides) {
+ sendMessage(
+ PooledLambda.obtainMessage(
+ UserHandler::onSessionInfoChangedOnHandler,
+ this,
+ provider,
+ sessionInfo,
+ packageNamesWithRoutingSessionOverrides));
}
@Override
@@ -3148,10 +3155,31 @@ class MediaRouter2ServiceImpl {
toOriginalRequestId(uniqueRequestId), sessionInfo);
}
- private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider,
- @NonNull RoutingSessionInfo sessionInfo) {
+ /**
+ * Implementation of {@link MediaRoute2Provider.Callback#onSessionUpdated}.
+ *
+ * <p>Must run on the thread that corresponds to this {@link UserHandler}.
+ */
+ private void onSessionInfoChangedOnHandler(
+ @NonNull MediaRoute2Provider provider,
+ @NonNull RoutingSessionInfo sessionInfo,
+ Set<String> packageNamesWithRoutingSessionOverrides) {
List<ManagerRecord> managers = getManagerRecords();
for (ManagerRecord manager : managers) {
+ if (Flags.enableMirroringInMediaRouter2()) {
+ String targetPackageName = manager.mTargetPackageName;
+ boolean skipDueToOverride =
+ targetPackageName != null
+ && packageNamesWithRoutingSessionOverrides.contains(
+ targetPackageName);
+ boolean sessionIsForTargetPackage =
+ TextUtils.isEmpty(sessionInfo.getClientPackageName()) // is global.
+ || TextUtils.equals(
+ targetPackageName, sessionInfo.getClientPackageName());
+ if (skipDueToOverride || !sessionIsForTargetPackage) {
+ continue;
+ }
+ }
manager.notifySessionUpdated(sessionInfo);
}
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 4aec3678af8b..60fced1e0c51 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -62,7 +62,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
static final String SYSTEM_SESSION_ID = "SYSTEM_SESSION";
private final AudioManager mAudioManager;
- private final Handler mHandler;
+ protected final Handler mHandler;
private final Context mContext;
private final UserHandle mUser;
@@ -116,7 +116,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
() -> {
publishProviderState();
if (updateSessionInfosIfNeeded()) {
- notifySessionInfoUpdated();
+ notifyGlobalSessionInfoUpdated();
}
});
@@ -129,7 +129,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
() -> {
publishProviderState();
if (updateSessionInfosIfNeeded()) {
- notifySessionInfoUpdated();
+ notifyGlobalSessionInfoUpdated();
}
}));
}
@@ -161,7 +161,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
public void setCallback(Callback callback) {
super.setCallback(callback);
notifyProviderState();
- notifySessionInfoUpdated();
+ notifyGlobalSessionInfoUpdated();
}
@Override
@@ -296,7 +296,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()
&& updateSessionInfosIfNeeded()) {
- notifySessionInfoUpdated();
+ notifyGlobalSessionInfoUpdated();
}
}
@@ -643,7 +643,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
notifyProviderState();
}
- void notifySessionInfoUpdated() {
+ void notifyGlobalSessionInfoUpdated() {
if (mCallback == null) {
return;
}
@@ -656,7 +656,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
sessionInfo = mSessionInfos.get(0);
}
- mCallback.onSessionUpdated(this, sessionInfo);
+ mCallback.onSessionUpdated(
+ this, sessionInfo, /* packageNamesWithRoutingSessionOverrides= */ Set.of());
}
@Override
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java
index a27a14b87d53..8931e3a1426e 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java
@@ -44,6 +44,7 @@ import com.android.server.media.MediaRoute2ProviderServiceProxy.SystemMediaSessi
import java.util.Collections;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Stream;
/**
@@ -82,7 +83,7 @@ import java.util.stream.Stream;
/** Maps request ids to pending session creation callbacks. */
@GuardedBy("mLock")
- private final LongSparseArray<PendingSessionCreationCallbackImpl> mPendingSessionCreations =
+ private final LongSparseArray<SystemMediaSessionCallbackImpl> mPendingSessionCreations =
new LongSparseArray<>();
private static final ComponentName COMPONENT_NAME =
@@ -157,7 +158,7 @@ import java.util.stream.Stream;
}
}
var pendingCreationCallback =
- new PendingSessionCreationCallbackImpl(
+ new SystemMediaSessionCallbackImpl(
targetProviderProxyId, requestId, clientPackageName);
mPendingSessionCreations.put(requestId, pendingCreationCallback);
targetProviderProxyRecord.requestCreateSystemMediaSession(
@@ -242,7 +243,7 @@ import java.util.stream.Stream;
}
updateSessionInfo();
notifyProviderState();
- notifySessionInfoUpdated();
+ notifyGlobalSessionInfoUpdated();
}
@Override
@@ -252,7 +253,7 @@ import java.util.stream.Stream;
updateProviderInfo();
}
updateSessionInfo();
- notifySessionInfoUpdated();
+ notifyGlobalSessionInfoUpdated();
}
/**
@@ -302,6 +303,43 @@ import java.util.stream.Stream;
setProviderState(builder.build());
}
+ @Override
+ /* package */ void notifyGlobalSessionInfoUpdated() {
+ if (mCallback == null) {
+ return;
+ }
+
+ RoutingSessionInfo sessionInfo;
+ Set<String> packageNamesWithRoutingSessionOverrides;
+ synchronized (mLock) {
+ if (mSessionInfos.isEmpty()) {
+ return;
+ }
+ packageNamesWithRoutingSessionOverrides = mPackageNameToSessionRecord.keySet();
+ sessionInfo = mSessionInfos.getFirst();
+ }
+
+ mCallback.onSessionUpdated(this, sessionInfo, packageNamesWithRoutingSessionOverrides);
+ }
+
+ private void onSessionOverrideUpdated(RoutingSessionInfo sessionInfo) {
+ // TODO: b/362507305 - Consider adding routes from other provider services. This is not a
+ // trivial change because a provider1-route to provider2-route transfer has seemingly two
+ // possible approachies. Either we first release the current session and then create the new
+ // one, in which case the audio is briefly going to leak through the system route. On the
+ // other hand, if we first create the provider2 session, then there will be a period during
+ // which there will be two overlapping routing policies asking for the exact same media
+ // stream.
+ var builder = new RoutingSessionInfo.Builder(sessionInfo);
+ mLastSystemProviderInfo.getRoutes().stream()
+ .map(MediaRoute2Info::getOriginalId)
+ .forEach(builder::addTransferableRoute);
+ mCallback.onSessionUpdated(
+ /* provider= */ this,
+ builder.build(),
+ /* packageNamesWithRoutingSessionOverrides= */ Set.of());
+ }
+
/**
* Equivalent to {@link #asSystemRouteId}, except it takes a unique route id instead of a
* original id.
@@ -432,13 +470,15 @@ import java.util.stream.Stream;
}
}
- private class PendingSessionCreationCallbackImpl implements SystemMediaSessionCallback {
+ private class SystemMediaSessionCallbackImpl implements SystemMediaSessionCallback {
private final String mProviderId;
private final long mRequestId;
private final String mClientPackageName;
+ // Accessed only on mHandler.
+ @Nullable private SystemMediaSessionRecord mSessionRecord;
- private PendingSessionCreationCallbackImpl(
+ private SystemMediaSessionCallbackImpl(
String providerId, long requestId, String clientPackageName) {
mProviderId = providerId;
mRequestId = requestId;
@@ -446,27 +486,51 @@ import java.util.stream.Stream;
}
@Override
- public void onSessionUpdate(RoutingSessionInfo sessionInfo) {
- SystemMediaSessionRecord systemMediaSessionRecord =
- new SystemMediaSessionRecord(mProviderId, sessionInfo);
- synchronized (mLock) {
- mPackageNameToSessionRecord.put(mClientPackageName, systemMediaSessionRecord);
- mPendingSessionCreations.remove(mRequestId);
- }
+ public void onSessionUpdate(@NonNull RoutingSessionInfo sessionInfo) {
+ mHandler.post(
+ () -> {
+ if (mSessionRecord != null) {
+ mSessionRecord.onSessionUpdate(sessionInfo);
+ }
+ SystemMediaSessionRecord systemMediaSessionRecord =
+ new SystemMediaSessionRecord(mProviderId, sessionInfo);
+ RoutingSessionInfo translatedSession;
+ synchronized (mLock) {
+ mSessionRecord = systemMediaSessionRecord;
+ mPackageNameToSessionRecord.put(
+ mClientPackageName, systemMediaSessionRecord);
+ mPendingSessionCreations.remove(mRequestId);
+ translatedSession = systemMediaSessionRecord.mTranslatedSessionInfo;
+ }
+ onSessionOverrideUpdated(translatedSession);
+ });
}
@Override
public void onRequestFailed(long requestId, @Reason int reason) {
- synchronized (mLock) {
- mPendingSessionCreations.remove(mRequestId);
- }
- notifyRequestFailed(requestId, reason);
+ mHandler.post(
+ () -> {
+ if (mSessionRecord != null) {
+ mSessionRecord.onRequestFailed(requestId, reason);
+ }
+ synchronized (mLock) {
+ mPendingSessionCreations.remove(mRequestId);
+ }
+ notifyRequestFailed(requestId, reason);
+ });
}
@Override
public void onSessionReleased() {
- // Unexpected. The session hasn't yet been created.
- throw new IllegalStateException();
+ mHandler.post(
+ () -> {
+ if (mSessionRecord != null) {
+ mSessionRecord.onSessionReleased();
+ } else {
+ // Should never happen. The session hasn't yet been created.
+ throw new IllegalStateException();
+ }
+ });
}
}
@@ -494,12 +558,13 @@ import java.util.stream.Stream;
}
@Override
- public void onSessionUpdate(RoutingSessionInfo sessionInfo) {
+ public void onSessionUpdate(@NonNull RoutingSessionInfo sessionInfo) {
+ RoutingSessionInfo translatedSessionInfo = mTranslatedSessionInfo;
synchronized (mLock) {
mSourceSessionInfo = sessionInfo;
mTranslatedSessionInfo = asSystemProviderSession(sessionInfo);
}
- notifySessionInfoUpdated();
+ onSessionOverrideUpdated(translatedSessionInfo);
}
@Override
@@ -512,7 +577,7 @@ import java.util.stream.Stream;
synchronized (mLock) {
removeSelfFromSessionMap();
}
- notifySessionInfoUpdated();
+ notifyGlobalSessionInfoUpdated();
}
@GuardedBy("SystemMediaRoute2Provider2.this.mLock")
@@ -536,6 +601,7 @@ import java.util.stream.Stream;
var builder =
new RoutingSessionInfo.Builder(session)
.setProviderId(mUniqueId)
+ .setSystemSession(true)
.clearSelectedRoutes()
.clearSelectableRoutes()
.clearDeselectableRoutes()
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 0c3c46c75eee..271c818f7daa 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -503,6 +503,31 @@ public class Notifier {
}
}
+ @VisibleForTesting
+ int getWakelockMonitorTypeForLogging(int flags) {
+ switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
+ case PowerManager.FULL_WAKE_LOCK, PowerManager.SCREEN_DIM_WAKE_LOCK,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
+ return PowerManager.FULL_WAKE_LOCK;
+ case PowerManager.DRAW_WAKE_LOCK:
+ return PowerManager.DRAW_WAKE_LOCK;
+ case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
+ if (mSuspendWhenScreenOffDueToProximityConfig) {
+ return -1;
+ }
+ return PowerManager.PARTIAL_WAKE_LOCK;
+ case PowerManager.PARTIAL_WAKE_LOCK:
+ return PowerManager.PARTIAL_WAKE_LOCK;
+ case PowerManager.DOZE_WAKE_LOCK:
+ // Doze wake locks are an internal implementation detail of the
+ // communication between dream manager service and power manager
+ // service. They have no additive battery impact.
+ return -1;
+ default:
+ return -1;
+ }
+ }
+
/**
* Notifies that the device is changing wakefulness.
* This function may be called even if the previous change hasn't finished in
@@ -1288,7 +1313,7 @@ public class Notifier {
if (mBatteryStatsInternal == null) {
return;
}
- final int type = flags & PowerManager.WAKE_LOCK_LEVEL_MASK;
+ final int type = getWakelockMonitorTypeForLogging(flags);
if (workSource == null || workSource.isEmpty()) {
final int mappedUid = mBatteryStatsInternal.getOwnerUid(ownerUid);
mFrameworkStatsLogger.wakelockStateChanged(mappedUid, tag, type, eventType);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index bf57f56df7c2..0aff1de72cb1 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -77,7 +77,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_SUPERVISOR_TASK_MSG;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
-import static com.android.server.wm.ActivityTaskManagerService.isPip2ExperimentEnabled;
import static com.android.server.wm.ClientLifecycleManager.shouldDispatchLaunchActivityItemIndependently;
import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_ALLOWLISTED;
import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE;
@@ -2526,7 +2525,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
void scheduleUpdatePictureInPictureModeIfNeeded(Task task, Rect targetRootTaskBounds) {
task.forAllActivities(r -> {
if (!r.attachedToProcess()) return;
- if (!isPip2ExperimentEnabled()) mPipModeChangedActivities.add(r);
+ mPipModeChangedActivities.add(r);
// If we are scheduling pip change, then remove this activity from multi-window
// change list as the processing of pip change will make sure multi-window changed
// message is processed in the right order relative to pip changed.
@@ -2535,7 +2534,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
mPipModeChangedTargetRootTaskBounds = targetRootTaskBounds;
- if (!isPip2ExperimentEnabled() && !mHandler.hasMessages(REPORT_PIP_MODE_CHANGED_MSG)) {
+ if (!mHandler.hasMessages(REPORT_PIP_MODE_CHANGED_MSG)) {
mHandler.sendEmptyMessage(REPORT_PIP_MODE_CHANGED_MSG);
}
}
diff --git a/services/core/java/com/android/server/wm/AppCompatUtils.java b/services/core/java/com/android/server/wm/AppCompatUtils.java
index 0369a0ff4c76..9f88bc952351 100644
--- a/services/core/java/com/android/server/wm/AppCompatUtils.java
+++ b/services/core/java/com/android/server/wm/AppCompatUtils.java
@@ -164,15 +164,13 @@ final class AppCompatUtils {
appCompatTaskInfo.setIsFromLetterboxDoubleTap(reachabilityOverrides.isFromDoubleTap());
+ appCompatTaskInfo.topActivityAppBounds.set(getAppBounds(top));
final boolean isTopActivityLetterboxed = top.areBoundsLetterboxed();
appCompatTaskInfo.setTopActivityLetterboxed(isTopActivityLetterboxed);
if (isTopActivityLetterboxed) {
final Rect bounds = top.getBounds();
- final Rect appBounds = getAppBounds(top);
appCompatTaskInfo.topActivityLetterboxWidth = bounds.width();
appCompatTaskInfo.topActivityLetterboxHeight = bounds.height();
- appCompatTaskInfo.topActivityLetterboxAppWidth = appBounds.width();
- appCompatTaskInfo.topActivityLetterboxAppHeight = appBounds.height();
// TODO(b/379824541) Remove duplicate information.
appCompatTaskInfo.topActivityLetterboxBounds = bounds;
// We need to consider if letterboxed or pillarboxed.
@@ -281,8 +279,7 @@ final class AppCompatUtils {
info.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
info.topActivityLetterboxWidth = TaskInfo.PROPERTY_VALUE_UNSET;
info.topActivityLetterboxHeight = TaskInfo.PROPERTY_VALUE_UNSET;
- info.topActivityLetterboxAppHeight = TaskInfo.PROPERTY_VALUE_UNSET;
- info.topActivityLetterboxAppWidth = TaskInfo.PROPERTY_VALUE_UNSET;
+ info.topActivityAppBounds.setEmpty();
info.topActivityLetterboxBounds = null;
info.cameraCompatTaskInfo.freeformCameraCompatMode =
CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_UNSPECIFIED;
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index dd1af0a497ca..6b6f0111305c 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -29,9 +29,6 @@ import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-
-import com.android.internal.R;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -687,11 +684,12 @@ class AsyncRotationController extends FadeAnimationController implements Consume
@Override
public Animation getFadeInAnimation() {
+ final Animation anim = super.getFadeInAnimation();
if (mHasScreenRotationAnimation) {
// Use a shorter animation so it is easier to align with screen rotation animation.
- return AnimationUtils.loadAnimation(mContext, R.anim.screen_rotate_0_enter);
+ anim.setDuration(getScaledDuration(SHORT_DURATION_MS));
}
- return super.getFadeInAnimation();
+ return anim;
}
@Override
diff --git a/services/core/java/com/android/server/wm/FadeAnimationController.java b/services/core/java/com/android/server/wm/FadeAnimationController.java
index 7af67e63f469..c60d3677319a 100644
--- a/services/core/java/com/android/server/wm/FadeAnimationController.java
+++ b/services/core/java/com/android/server/wm/FadeAnimationController.java
@@ -20,41 +20,51 @@ import static com.android.server.wm.AnimationSpecProto.WINDOW;
import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;
import android.annotation.NonNull;
-import android.content.Context;
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
+import android.view.animation.DecelerateInterpolator;
import android.view.animation.Transformation;
-import com.android.internal.R;
-
import java.io.PrintWriter;
/**
* An animation controller to fade-in/out for a window token.
*/
public class FadeAnimationController {
+ static final int SHORT_DURATION_MS = 200;
+ static final int MEDIUM_DURATION_MS = 350;
+
protected final DisplayContent mDisplayContent;
- protected final Context mContext;
public FadeAnimationController(DisplayContent displayContent) {
mDisplayContent = displayContent;
- mContext = displayContent.mWmService.mContext;
}
/**
* @return a fade-in Animation.
*/
public Animation getFadeInAnimation() {
- return AnimationUtils.loadAnimation(mContext, R.anim.fade_in);
+ final AlphaAnimation anim = new AlphaAnimation(0f, 1f);
+ anim.setDuration(getScaledDuration(MEDIUM_DURATION_MS));
+ anim.setInterpolator(new DecelerateInterpolator());
+ return anim;
}
/**
* @return a fade-out Animation.
*/
public Animation getFadeOutAnimation() {
- return AnimationUtils.loadAnimation(mContext, R.anim.fade_out);
+ final AlphaAnimation anim = new AlphaAnimation(1f, 0f);
+ anim.setDuration(getScaledDuration(SHORT_DURATION_MS));
+ anim.setInterpolator(new AccelerateInterpolator());
+ return anim;
+ }
+
+ long getScaledDuration(int durationMs) {
+ return (long) (durationMs * mDisplayContent.mWmService.getWindowAnimationScaleLocked());
}
/** Run the fade in/out animation for a window token. */
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9d9c53dfe0f4..db62cebf7603 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2945,7 +2945,7 @@ public class WindowManagerService extends IWindowManager.Stub
final DisplayContent dc = mRoot.getDisplayContent(displayId);
if (dc == null) {
if (callingPid != MY_PID) {
- throw new WindowManager.InvalidDisplayException(
+ throw new IllegalArgumentException(
"attachWindowContextToDisplayContent: trying to attach to a"
+ " non-existing display:" + displayId);
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index e45ada9438ae..fb197c566b7d 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -80,7 +80,6 @@ import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_WINDOW_ORG
import static com.android.server.wm.ActivityRecord.State.PAUSING;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
-import static com.android.server.wm.ActivityTaskManagerService.isPip2ExperimentEnabled;
import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
@@ -717,8 +716,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
if (forceHiddenForPip) {
wc.asTask().setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */);
- }
- if (forceHiddenForPip && !isPip2ExperimentEnabled()) {
// When removing pip, make sure that onStop is sent to the app ahead of
// onPictureInPictureModeChanged.
// See also PinnedStackTests#testStopBeforeMultiWindowCallbacksOnDismiss
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 60130d1f97be..30a967c5d4e6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -91,6 +91,7 @@ import android.server.ServerProtoEnums;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
+import android.tracing.perfetto.InitArguments;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.Dumpable;
@@ -792,6 +793,12 @@ public final class SystemServer implements Dumpable {
private void run() {
TimingsTraceAndSlog t = new TimingsTraceAndSlog();
try {
+ if (android.tracing.Flags.systemServerLargePerfettoShmemBuffer()) {
+ // Explicitly initialize a 4 MB shmem buffer for Perfetto producers (b/382369925)
+ android.tracing.perfetto.Producer.init(new InitArguments(
+ InitArguments.PERFETTO_BACKEND_SYSTEM, 4 * 1024));
+ }
+
t.traceBegin("InitBeforeStartServices");
// Record the process start information in sys props.
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt
index 5d427139a857..c65024f8f9d5 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt
@@ -26,6 +26,7 @@ import org.junit.Test
import org.mockito.ArgumentMatchers.anyFloat
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.verify
@@ -43,7 +44,7 @@ class DisplayTopologyCoordinatorTest {
@Before
fun setUp() {
- displayInfo.displayId = 2
+ displayInfo.displayId = Display.DEFAULT_DISPLAY
displayInfo.logicalWidth = 300
displayInfo.logicalHeight = 200
displayInfo.logicalDensityDpi = 100
@@ -90,6 +91,44 @@ class DisplayTopologyCoordinatorTest {
}
@Test
+ fun updateDisplay() {
+ whenever(mockTopology.updateDisplay(eq(Display.DEFAULT_DISPLAY), anyFloat(), anyFloat()))
+ .thenReturn(true)
+
+ coordinator.onDisplayChanged(displayInfo)
+
+ verify(mockTopologyChangedCallback).invoke(mockTopologyCopy)
+ }
+
+ @Test
+ fun updateDisplay_notChanged() {
+ whenever(mockTopology.updateDisplay(eq(Display.DEFAULT_DISPLAY), anyFloat(), anyFloat()))
+ .thenReturn(false)
+
+ coordinator.onDisplayChanged(displayInfo)
+
+ verify(mockTopologyChangedCallback, never()).invoke(any())
+ }
+
+ @Test
+ fun removeDisplay() {
+ whenever(mockTopology.removeDisplay(Display.DEFAULT_DISPLAY)).thenReturn(true)
+
+ coordinator.onDisplayRemoved(Display.DEFAULT_DISPLAY)
+
+ verify(mockTopologyChangedCallback).invoke(mockTopologyCopy)
+ }
+
+ @Test
+ fun removeDisplay_notChanged() {
+ whenever(mockTopology.removeDisplay(Display.DEFAULT_DISPLAY)).thenReturn(false)
+
+ coordinator.onDisplayRemoved(Display.DEFAULT_DISPLAY)
+
+ verify(mockTopologyChangedCallback, never()).invoke(any())
+ }
+
+ @Test
fun getTopology_copy() {
assertThat(coordinator.topology).isEqualTo(mockTopologyCopy)
}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
index 96741e0b1e87..469bd66b7e7b 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
@@ -21,6 +21,7 @@ import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
@@ -889,6 +890,32 @@ public class NotifierTest {
"my.package.name", false, null, null);
}
+ @Test
+ public void getWakelockMonitorTypeForLogging_evaluatesWakelockLevel() {
+ createNotifier();
+ assertEquals(mNotifier.getWakelockMonitorTypeForLogging(PowerManager.SCREEN_DIM_WAKE_LOCK),
+ PowerManager.FULL_WAKE_LOCK);
+ assertEquals(mNotifier.getWakelockMonitorTypeForLogging(
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK), PowerManager.FULL_WAKE_LOCK);
+ assertEquals(mNotifier.getWakelockMonitorTypeForLogging(PowerManager.DRAW_WAKE_LOCK),
+ PowerManager.DRAW_WAKE_LOCK);
+ assertEquals(mNotifier.getWakelockMonitorTypeForLogging(PowerManager.PARTIAL_WAKE_LOCK),
+ PowerManager.PARTIAL_WAKE_LOCK);
+ assertEquals(mNotifier.getWakelockMonitorTypeForLogging(
+ PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK),
+ PowerManager.PARTIAL_WAKE_LOCK);
+ assertEquals(mNotifier.getWakelockMonitorTypeForLogging(
+ PowerManager.DOZE_WAKE_LOCK), -1);
+
+ when(mResourcesSpy.getBoolean(
+ com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity))
+ .thenReturn(true);
+
+ createNotifier();
+ assertEquals(mNotifier.getWakelockMonitorTypeForLogging(
+ PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK), -1);
+ }
+
private final PowerManagerService.Injector mInjector = new PowerManagerService.Injector() {
@Override
Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
diff --git a/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java
index 34f0c191ecf5..fe9f63615757 100644
--- a/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java
+++ b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java
@@ -76,6 +76,7 @@ public class IntegrationTests {
private ActivityTestRule<EmptyActivity> mEmptyActivityRule =
new ActivityTestRule<>(EmptyActivity.class, false , true);
+
@Before
public void setUp() {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
@@ -163,7 +164,7 @@ public class IntegrationTests {
// of that state.
for (int i = 0; i < uiStates.size(); i++) {
StateTracker.StateData stateData = uiStates.get(i);
- if (stateData.mWidgetCategory.equals(AppJankStats.ANIMATION)) {
+ if (stateData.mWidgetCategory.equals(AppJankStats.WIDGET_CATEGORY_ANIMATION)) {
assertNotEquals(Long.MAX_VALUE, stateData.mVsyncIdEnd);
}
}
diff --git a/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java b/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java
index 30c568be7716..c90595782cd1 100644
--- a/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java
+++ b/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java
@@ -215,7 +215,8 @@ public class JankDataProcessorTest {
assertEquals(jankStats.getJankyFrameCount() * 2, pendingStat.getJankyFrames());
assertEquals(jankStats.getTotalFrameCount() * 2, pendingStat.getTotalFrames());
- int[] originalHistogramBuckets = jankStats.getFrameOverrunHistogram().getBucketCounters();
+ int[] originalHistogramBuckets =
+ jankStats.getRelativeFrameTimeHistogram().getBucketCounters();
int[] frameOverrunBuckets = pendingStat.getFrameOverrunBuckets();
for (int i = 0; i < frameOverrunBuckets.length; i++) {
diff --git a/tests/AppJankTest/src/android/app/jank/tests/JankUtils.java b/tests/AppJankTest/src/android/app/jank/tests/JankUtils.java
index 0b4d97ed20d6..df92898d76b1 100644
--- a/tests/AppJankTest/src/android/app/jank/tests/JankUtils.java
+++ b/tests/AppJankTest/src/android/app/jank/tests/JankUtils.java
@@ -17,7 +17,7 @@
package android.app.jank.tests;
import android.app.jank.AppJankStats;
-import android.app.jank.FrameOverrunHistogram;
+import android.app.jank.RelativeFrameTimeHistogram;
public class JankUtils {
private static final int APP_ID = 25;
@@ -29,8 +29,8 @@ public class JankUtils {
AppJankStats jankStats = new AppJankStats(
/*App Uid*/APP_ID,
/*Widget Id*/"test widget id",
- /*Widget Category*/AppJankStats.SCROLL,
- /*Widget State*/AppJankStats.SCROLLING,
+ /*Widget Category*/AppJankStats.WIDGET_CATEGORY_SCROLL,
+ /*Widget State*/AppJankStats.WIDGET_STATE_SCROLLING,
/*Total Frames*/100,
/*Janky Frames*/25,
getOverrunHistogram()
@@ -41,12 +41,12 @@ public class JankUtils {
/**
* Returns a mock histogram to be used with an AppJankStats object.
*/
- public static FrameOverrunHistogram getOverrunHistogram() {
- FrameOverrunHistogram overrunHistogram = new FrameOverrunHistogram();
- overrunHistogram.addFrameOverrunMillis(-2);
- overrunHistogram.addFrameOverrunMillis(1);
- overrunHistogram.addFrameOverrunMillis(5);
- overrunHistogram.addFrameOverrunMillis(25);
+ public static RelativeFrameTimeHistogram getOverrunHistogram() {
+ RelativeFrameTimeHistogram overrunHistogram = new RelativeFrameTimeHistogram();
+ overrunHistogram.addRelativeFrameTimeMillis(-2);
+ overrunHistogram.addRelativeFrameTimeMillis(1);
+ overrunHistogram.addRelativeFrameTimeMillis(5);
+ overrunHistogram.addRelativeFrameTimeMillis(25);
return overrunHistogram;
}
}
diff --git a/tests/AppJankTest/src/android/app/jank/tests/TestWidget.java b/tests/AppJankTest/src/android/app/jank/tests/TestWidget.java
index 5fff46038ead..71796d64ddee 100644
--- a/tests/AppJankTest/src/android/app/jank/tests/TestWidget.java
+++ b/tests/AppJankTest/src/android/app/jank/tests/TestWidget.java
@@ -45,8 +45,8 @@ public class TestWidget extends View {
*/
public void simulateAnimationStarting() {
if (jankTrackerCreated()) {
- mJankTracker.addUiState(AppJankStats.ANIMATION,
- Integer.toString(this.getId()), AppJankStats.ANIMATING);
+ mJankTracker.addUiState(AppJankStats.WIDGET_CATEGORY_ANIMATION,
+ Integer.toString(this.getId()), AppJankStats.WIDGET_STATE_ANIMATING);
}
}
@@ -55,8 +55,8 @@ public class TestWidget extends View {
*/
public void simulateAnimationEnding() {
if (jankTrackerCreated()) {
- mJankTracker.removeUiState(AppJankStats.ANIMATION,
- Integer.toString(this.getId()), AppJankStats.ANIMATING);
+ mJankTracker.removeUiState(AppJankStats.WIDGET_CATEGORY_ANIMATION,
+ Integer.toString(this.getId()), AppJankStats.WIDGET_STATE_ANIMATING);
}
}
diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java
index 700856c50bae..14c8de8db5fc 100644
--- a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java
+++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java
@@ -819,7 +819,7 @@ public class GraphicsActivity extends Activity {
private List<Float> getExpectedFrameRateForCompatibility(int compatibility) {
assumeTrue("**** testSurfaceControlFrameRateCompatibility SKIPPED for compatibility "
+ compatibility,
- compatibility == Surface.FRAME_RATE_COMPATIBILITY_GTE);
+ compatibility == Surface.FRAME_RATE_COMPATIBILITY_AT_LEAST);
Display display = getDisplay();
List<Float> expectedFrameRates = getRefreshRates(display.getMode(), display)
diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java
index 4d4827676c74..f1d4dc6b8faf 100644
--- a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java
+++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java
@@ -85,7 +85,8 @@ public class SurfaceControlTest {
@Test
public void testSurfaceControlFrameRateCompatibilityGte() throws InterruptedException {
GraphicsActivity activity = mActivityRule.getActivity();
- activity.testSurfaceControlFrameRateCompatibility(Surface.FRAME_RATE_COMPATIBILITY_GTE);
+ activity.testSurfaceControlFrameRateCompatibility(
+ Surface.FRAME_RATE_COMPATIBILITY_AT_LEAST);
}
@Test