summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/backup/BackupRestoreEventLogger.java17
-rw-r--r--core/java/android/app/jank/JankDataProcessor.java113
-rw-r--r--core/java/android/app/jank/JankTracker.java136
-rw-r--r--core/java/com/android/internal/app/OWNERS3
-rw-r--r--core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java34
-rw-r--r--core/tests/coretests/src/android/app/backup/DataTypeResultTest.java117
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble.pngbin0 -> 20393 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubbleBar.pngbin0 -> 20220 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_10_90.pngbin0 -> 20319 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_90_10.pngbin0 -> 20401 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView.pngbin0 -> 20635 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_10_90.pngbin0 -> 20522 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_90_10.pngbin0 -> 20569 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble.pngbin0 -> 21304 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubbleBar.pngbin0 -> 21159 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_10_90.pngbin0 -> 21276 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_90_10.pngbin0 -> 21283 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_expandedView.pngbin0 -> 21318 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubble.pngbin0 -> 20400 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubbleBar.pngbin0 -> 20082 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_expandedView.pngbin0 -> 20406 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubble.pngbin0 -> 22270 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubbleBar.pngbin0 -> 21917 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_expandedView.pngbin0 -> 22462 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryScreenshotTest.kt170
-rw-r--r--libs/WindowManager/Shell/shared/res/values/dimen.xml1
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZone.kt24
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt98
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt29
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java15
-rw-r--r--libs/WindowManager/Shell/tests/unittest/Android.bp1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java64
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt210
-rw-r--r--location/Android.bp1
-rw-r--r--packages/LocalTransport/src/com/android/localtransport/LocalTransport.java18
-rw-r--r--packages/SettingsLib/res/drawable/ic_1x_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_3g_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_4g_lte_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_4g_lte_plus_mobiledata_updated.xml27
-rw-r--r--packages/SettingsLib/res/drawable/ic_4g_mobiledata_updated.xml25
-rw-r--r--packages/SettingsLib/res/drawable/ic_4g_plus_mobiledata_updated.xml27
-rw-r--r--packages/SettingsLib/res/drawable/ic_5g_e_mobiledata_updated.xml25
-rw-r--r--packages/SettingsLib/res/drawable/ic_5g_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_default_updated.xml27
-rw-r--r--packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_updated.xml27
-rw-r--r--packages/SettingsLib/res/drawable/ic_carrier_wifi_updated.xml30
-rw-r--r--packages/SettingsLib/res/drawable/ic_e_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_g_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_h_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_h_plus_mobiledata_updated.xml27
-rw-r--r--packages/SettingsLib/res/drawable/ic_lte_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_lte_plus_mobiledata_updated.xml27
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java58
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java55
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt38
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt80
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt2
-rw-r--r--packages/SystemUI/res/drawable/ic_legacy_speaker_mute.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_legacy_speaker_on.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_legacy_volume_ringer_vibrate.xml27
-rw-r--r--packages/SystemUI/res/drawable/ic_speaker_mute.xml23
-rw-r--r--packages/SystemUI/res/drawable/ic_speaker_on.xml23
-rw-r--r--packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml47
-rw-r--r--packages/SystemUI/res/drawable/mobile_network_type_background_updated.xml30
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml2
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml2
-rw-r--r--packages/SystemUI/res/layout/internet_connectivity_dialog.xml2
-rw-r--r--packages/SystemUI/res/layout/volume_ringer_drawer_legacy.xml6
-rw-r--r--packages/SystemUI/res/values/dimens.xml25
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopup.kt65
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt74
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt845
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt53
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt13
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt4
-rw-r--r--ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodMethodCallLogger.java229
-rw-r--r--ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java17
-rw-r--r--ravenwood/texts/ravenwood-standard-options.txt4
-rw-r--r--ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java43
-rw-r--r--ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt1
-rw-r--r--ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt51
-rw-r--r--ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt120
-rw-r--r--ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt230
-rw-r--r--services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java19
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java152
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java18
-rw-r--r--tests/AppJankTest/res/values/strings.xml3
-rw-r--r--tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java3
-rw-r--r--tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java26
109 files changed, 3020 insertions, 1093 deletions
diff --git a/core/java/android/app/backup/BackupRestoreEventLogger.java b/core/java/android/app/backup/BackupRestoreEventLogger.java
index 112c5fd808ef..8bde3a5f2efa 100644
--- a/core/java/android/app/backup/BackupRestoreEventLogger.java
+++ b/core/java/android/app/backup/BackupRestoreEventLogger.java
@@ -34,9 +34,11 @@ import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* Class to log B&R stats for each data type that is backed up and restored by the calling app.
@@ -325,6 +327,21 @@ public final class BackupRestoreEventLogger {
}
}
+ /** @hide */
+ public static String toString(DataTypeResult result) {
+ Objects.requireNonNull(result, "result cannot be null");
+ StringBuilder string = new StringBuilder("type=").append(result.mDataType)
+ .append(", successCount=").append(result.mSuccessCount)
+ .append(", failCount=").append(result.mFailCount);
+ if (!result.mErrors.isEmpty()) {
+ string.append(", errors=").append(result.mErrors);
+ }
+ if (result.mMetadataHash != null) {
+ string.append(", metadataHash=").append(Arrays.toString(result.mMetadataHash));
+ }
+ return string.toString();
+ }
+
/**
* Encapsulate logging results for a single data type.
*/
diff --git a/core/java/android/app/jank/JankDataProcessor.java b/core/java/android/app/jank/JankDataProcessor.java
index b4c293eeb695..7718d159896e 100644
--- a/core/java/android/app/jank/JankDataProcessor.java
+++ b/core/java/android/app/jank/JankDataProcessor.java
@@ -34,11 +34,13 @@ import java.util.List;
/**
* This class is responsible for associating frames received from SurfaceFlinger to active widget
* states and logging those states back to the platform.
+ *
* @hide
*/
@FlaggedApi(Flags.FLAG_DETAILED_APP_JANK_METRICS_API)
public class JankDataProcessor {
-
+ private static final String TAG = "JankDataProcessor";
+ private static final boolean DEBUG_LOGGING = false;
private static final int MAX_IN_MEMORY_STATS = 25;
private static final int LOG_BATCH_FREQUENCY = 50;
private int mCurrentBatchCount = 0;
@@ -54,9 +56,10 @@ public class JankDataProcessor {
/**
* Called once per batch of JankData.
- * @param jankData data received from SurfaceFlinger to be processed
+ *
+ * @param jankData data received from SurfaceFlinger to be processed
* @param activityName name of the activity that is tracking jank metrics.
- * @param appUid the uid of the app.
+ * @param appUid the uid of the app.
*/
public void processJankData(List<JankData> jankData, String activityName, int appUid) {
// add all the previous and active states to the pending states list.
@@ -211,8 +214,6 @@ public class JankDataProcessor {
* clear any pending widget states.
*/
public void logMetricCounts() {
- //TODO b/374607503 when api changes are in add enum mapping for category and state.
-
try {
mPendingJankStats.values().forEach(stat -> {
FrameworkStatsLog.write(
@@ -221,15 +222,16 @@ public class JankDataProcessor {
/*activity name*/ stat.getActivityName(),
/*widget id*/ stat.getWidgetId(),
/*refresh rate*/ stat.getRefreshRate(),
- /*widget category*/ 0,
- /*widget state*/ 0,
+ /*widget category*/ widgetCategoryToInt(stat.getWidgetCategory()),
+ /*widget state*/ widgetStateToInt(stat.getWidgetState()),
/*total frames*/ stat.getTotalFrames(),
/*janky frames*/ stat.getJankyFrames(),
- /*histogram*/ stat.mFrameOverrunBuckets);
+ /*histogram*/ stat.getFrameOverrunBuckets());
Log.d(stat.mActivityName, stat.toString());
// return the pending stat to the pool it will be reset the next time its
// used.
mPendingJankStatsPool.release(stat);
+
}
);
// All stats have been recorded and added back to the pool for reuse, clear the pending
@@ -241,6 +243,96 @@ public class JankDataProcessor {
}
}
+ private int widgetCategoryToInt(String widgetCategory) {
+ switch (widgetCategory) {
+ case AppJankStats.WIDGET_CATEGORY_SCROLL -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__SCROLLING;
+ }
+ case AppJankStats.WIDGET_CATEGORY_ANIMATION -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__ANIMATION;
+ }
+ case AppJankStats.WIDGET_CATEGORY_MEDIA -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__MEDIA;
+ }
+ case AppJankStats.WIDGET_CATEGORY_NAVIGATION -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__NAVIGATION;
+ }
+ case AppJankStats.WIDGET_CATEGORY_KEYBOARD -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__KEYBOARD;
+ }
+ case AppJankStats.WIDGET_CATEGORY_OTHER -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__OTHER;
+ }
+ default -> {
+ if (DEBUG_LOGGING) {
+ Log.d(TAG, "Default Category Logged: "
+ + AppJankStats.WIDGET_CATEGORY_UNSPECIFIED);
+ }
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__WIDGET_CATEGORY_UNSPECIFIED;
+ }
+ }
+ }
+
+ private int widgetStateToInt(String widgetState) {
+ switch (widgetState) {
+ case AppJankStats.WIDGET_STATE_NONE -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__NONE;
+ }
+ case AppJankStats.WIDGET_STATE_SCROLLING -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__SCROLLING;
+ }
+ case AppJankStats.WIDGET_STATE_FLINGING -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__FLINGING;
+ }
+ case AppJankStats.WIDGET_STATE_SWIPING -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__SWIPING;
+ }
+ case AppJankStats.WIDGET_STATE_DRAGGING -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__DRAGGING;
+ }
+ case AppJankStats.WIDGET_STATE_ZOOMING -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__ZOOMING;
+ }
+ case AppJankStats.WIDGET_STATE_ANIMATING -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__ANIMATING;
+ }
+ case AppJankStats.WIDGET_STATE_PLAYBACK -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__PLAYBACK;
+ }
+ case AppJankStats.WIDGET_STATE_TAPPING -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__TAPPING;
+ }
+ case AppJankStats.WIDGET_STATE_PREDICTIVE_BACK -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__PREDICTIVE_BACK;
+ }
+ default -> {
+ if (DEBUG_LOGGING) {
+ Log.d(TAG, "Default State Logged: "
+ + AppJankStats.WIDGET_STATE_UNSPECIFIED);
+ }
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__WIDGET_STATE_UNSPECIFIED;
+ }
+ }
+ }
+
public static final class PendingJankStat {
private static final int NANOS_PER_MS = 1000000;
public long processedVsyncId = -1;
@@ -268,7 +360,7 @@ public class JankDataProcessor {
private int mRefreshRate;
- private static final int[] sFrameOverrunHistogramBounds = {
+ 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,
@@ -279,6 +371,7 @@ public class JankDataProcessor {
// Histogram of frame duration overruns encoded in predetermined buckets.
public PendingJankStat() {
}
+
public long getProcessedVsyncId() {
return processedVsyncId;
}
@@ -422,4 +515,4 @@ public class JankDataProcessor {
}
}
-}
+} \ No newline at end of file
diff --git a/core/java/android/app/jank/JankTracker.java b/core/java/android/app/jank/JankTracker.java
index a04f96a9f6e3..9c85b09f6be3 100644
--- a/core/java/android/app/jank/JankTracker.java
+++ b/core/java/android/app/jank/JankTracker.java
@@ -20,6 +20,7 @@ import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.os.Handler;
import android.os.HandlerThread;
+import android.util.Log;
import android.view.AttachedSurfaceControl;
import android.view.Choreographer;
import android.view.SurfaceControl;
@@ -30,16 +31,22 @@ import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
/**
* This class is responsible for registering callbacks that will receive JankData batches.
* It handles managing the background thread that JankData will be processed on. As well as acting
* as an intermediary between widgets and the state tracker, routing state changes to the tracker.
+ *
* @hide
*/
@FlaggedApi(Flags.FLAG_DETAILED_APP_JANK_METRICS_API)
public class JankTracker {
-
+ private static final boolean DEBUG = false;
+ private static final String DEBUG_KEY = "JANKTRACKER";
+ // How long to delay the JankData listener registration.
+ //TODO b/394956095 see if this can be reduced or eliminated.
+ private static final int REGISTRATION_DELAY_MS = 1000;
// Tracks states reported by widgets.
private StateTracker mStateTracker;
// Processes JankData batches and associates frames to widget states.
@@ -49,9 +56,6 @@ public class JankTracker {
private HandlerThread mHandlerThread = new HandlerThread("AppJankTracker");
private Handler mHandler = null;
- // Needed so we know when the view is attached to a window.
- private ViewTreeObserver mViewTreeObserver;
-
// Handle to a registered OnJankData listener.
private SurfaceControl.OnJankDataListenerRegistration mJankDataListenerRegistration;
@@ -76,6 +80,40 @@ public class JankTracker {
*/
private boolean mListenersRegistered = false;
+ @FlaggedApi(com.android.window.flags.Flags.FLAG_JANK_API)
+ private final SurfaceControl.OnJankDataListener mJankDataListener =
+ new SurfaceControl.OnJankDataListener() {
+ @Override
+ public void onJankDataAvailable(
+ @androidx.annotation.NonNull List<SurfaceControl.JankData> jankData) {
+ if (mJankDataProcessor == null) return;
+ mJankDataProcessor.processJankData(jankData, mActivityName, mAppUid);
+ }
+ };
+
+ private final ViewTreeObserver.OnWindowAttachListener mOnWindowAttachListener =
+ new ViewTreeObserver.OnWindowAttachListener() {
+ @Override
+ public void onWindowAttached() {
+ getHandler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mDecorView.getViewTreeObserver()
+ .removeOnWindowAttachListener(mOnWindowAttachListener);
+ registerForJankData();
+ }
+ }, REGISTRATION_DELAY_MS);
+ }
+
+ // Leave this empty. Only need to know when the DecorView is attached to the Window
+ // in order to get a handle to AttachedSurfaceControl. There is no need to tie
+ // anything to when the view is detached as all un-registration code is tied to
+ // the lifecycle of the enclosing activity.
+ @Override
+ public void onWindowDetached() {
+
+ }
+ };
public JankTracker(Choreographer choreographer, View decorView) {
mStateTracker = new StateTracker(choreographer);
@@ -108,9 +146,10 @@ public class JankTracker {
/**
* Will add the widget category, id and state as a UI state to associate frames to it.
+ *
* @param widgetCategory preselected general widget category
- * @param widgetId developer defined widget id if available.
- * @param widgetState the current active widget state.
+ * @param widgetId developer defined widget id if available.
+ * @param widgetState the current active widget state.
*/
public void addUiState(String widgetCategory, String widgetId, String widgetState) {
if (!shouldTrack()) return;
@@ -121,9 +160,10 @@ public class JankTracker {
/**
* Will remove the widget category, id and state as a ui state and no longer attribute frames
* to it.
+ *
* @param widgetCategory preselected general widget category
- * @param widgetId developer defined widget id if available.
- * @param widgetState no longer active widget state.
+ * @param widgetId developer defined widget id if available.
+ * @param widgetState no longer active widget state.
*/
public void removeUiState(String widgetCategory, String widgetId, String widgetState) {
if (!shouldTrack()) return;
@@ -133,10 +173,11 @@ public class JankTracker {
/**
* Call to update a jank state to a different state.
+ *
* @param widgetCategory preselected general widget category.
- * @param widgetId developer defined widget id if available.
- * @param currentState current state of the widget.
- * @param nextState the state the widget will be in.
+ * @param widgetId developer defined widget id if available.
+ * @param currentState current state of the widget.
+ * @param nextState the state the widget will be in.
*/
public void updateUiState(String widgetCategory, String widgetId, String currentState,
String nextState) {
@@ -150,10 +191,11 @@ public class JankTracker {
*/
public void enableAppJankTracking() {
// Add the activity as a state, this will ensure we track frames to the activity without the
- // need of a decorated widget to be used.
+ // need for a decorated widget to be used.
// TODO b/376116199 replace "NONE" with UNSPECIFIED once the API changes are merged.
mStateTracker.putState("NONE", mActivityName, "NONE");
mTrackingEnabled = true;
+ registerForJankData();
}
/**
@@ -163,10 +205,12 @@ public class JankTracker {
mTrackingEnabled = false;
// TODO b/376116199 replace "NONE" with UNSPECIFIED once the API changes are merged.
mStateTracker.removeState("NONE", mActivityName, "NONE");
+ unregisterForJankData();
}
/**
* Retrieve all pending widget states, this is intended for testing purposes only.
+ *
* @param stateDataList the ArrayList that will be populated with the pending states.
*/
@VisibleForTesting
@@ -190,16 +234,35 @@ public class JankTracker {
@VisibleForTesting
public void forceListenerRegistration() {
mSurfaceControl = mDecorView.getRootSurfaceControl();
- registerForJankData();
- // TODO b/376116199 Check if registration is good.
- mListenersRegistered = true;
+ registerJankDataListener();
+ }
+
+ private void unregisterForJankData() {
+ if (mJankDataListenerRegistration == null) return;
+
+ if (com.android.window.flags.Flags.jankApi()) {
+ mJankDataListenerRegistration.release();
+ }
+ mJankDataListenerRegistration = null;
+ mListenersRegistered = false;
}
private void registerForJankData() {
- if (mSurfaceControl == null) return;
- /*
- TODO b/376115668 Register for JankData batches from new JankTracking API
- */
+ if (mDecorView == null) return;
+
+ mSurfaceControl = mDecorView.getRootSurfaceControl();
+
+ if (mSurfaceControl == null || mListenersRegistered) return;
+
+ // Wait a short time before registering the listener. During development it was observed
+ // that if a listener is registered too quickly after a hot or warm start no data is
+ // received b/394956095.
+ getHandler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ registerJankDataListener();
+ }
+ }, REGISTRATION_DELAY_MS);
}
/**
@@ -218,23 +281,30 @@ public class JankTracker {
*/
private void registerWindowListeners() {
if (mDecorView == null) return;
- mViewTreeObserver = mDecorView.getViewTreeObserver();
- mViewTreeObserver.addOnWindowAttachListener(new ViewTreeObserver.OnWindowAttachListener() {
- @Override
- public void onWindowAttached() {
- getHandler().postDelayed(new Runnable() {
- @Override
- public void run() {
- forceListenerRegistration();
- }
- }, 1000);
+ mDecorView.getViewTreeObserver().addOnWindowAttachListener(mOnWindowAttachListener);
+ }
+
+ private void registerJankDataListener() {
+ if (mSurfaceControl == null) {
+ if (DEBUG) {
+ Log.d(DEBUG_KEY, "SurfaceControl is Null");
}
+ return;
+ }
- @Override
- public void onWindowDetached() {
- // TODO b/376116199 do we un-register the callback or just not process the data.
+ if (com.android.window.flags.Flags.jankApi()) {
+ mJankDataListenerRegistration = mSurfaceControl.registerOnJankDataListener(
+ mHandlerThread.getThreadExecutor(), mJankDataListener);
+
+ if (mJankDataListenerRegistration
+ == SurfaceControl.OnJankDataListenerRegistration.NONE) {
+ if (DEBUG) {
+ Log.d(DEBUG_KEY, "OnJankDataListenerRegistration is assigned NONE");
+ }
+ return;
}
- });
+ mListenersRegistered = true;
+ }
}
private Handler getHandler() {
diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index 52f18fb80c27..0bba24d4ce19 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -20,3 +20,6 @@ per-file *VisualQuery* = file:/core/java/android/service/voice/OWNERS
# System language settings
per-file *Locale* = file:platform/packages/apps/Settings:/src/com/android/settings/localepicker/OWNERS
+
+# Media
+per-file *MediaRoute* = file:/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS
diff --git a/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java b/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java
index 7b41217d6200..ab2e77e57b47 100644
--- a/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java
+++ b/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java
@@ -23,6 +23,8 @@ import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertThrows;
+
import android.app.backup.BackupRestoreEventLogger.DataTypeResult;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
@@ -32,6 +34,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.server.backup.Flags;
+import com.google.common.truth.Expect;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -42,6 +46,7 @@ import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
@Presubmit
@@ -64,6 +69,9 @@ public class BackupRestoreEventLoggerTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ @Rule
+ public final Expect expect = Expect.create();
+
@Before
public void setUp() throws Exception {
mHashDigest = MessageDigest.getInstance("SHA-256");
@@ -366,6 +374,32 @@ public class BackupRestoreEventLoggerTest {
assertThat(mLogger.getLoggingResults()).isEmpty();
}
+ @Test
+ public void testDataTypeResultToString_nullArgs() {
+ assertThrows(NullPointerException.class, () -> BackupRestoreEventLogger.toString(null));
+ }
+
+ @Test
+ public void testDataTypeResultToString_typeOnly() {
+ DataTypeResult result = new DataTypeResult("The Type is Bond, James Bond!");
+
+ expect.withMessage("toString()")
+ .that(BackupRestoreEventLogger.toString(result)).isEqualTo(
+ "type=The Type is Bond, James Bond!, successCount=0, failCount=0");
+ }
+
+ @Test
+ public void testDataTypeResultToString_allFields() {
+ DataTypeResult result = DataTypeResultTest.createDataTypeResult(
+ "The Type is Bond, James Bond!", /* successCount= */ 42, /* failCount= */ 108,
+ Map.of("D'OH!", 666, "", 0), new byte[] { 4, 8, 15, 16, 23, 42 });
+
+ expect.withMessage("toString()")
+ .that(BackupRestoreEventLogger.toString(result)).isEqualTo(
+ "type=The Type is Bond, James Bond!, successCount=42, failCount=108, "
+ + "errors={=0, D'OH!=666}, metadataHash=[4, 8, 15, 16, 23, 42]");
+ }
+
private static DataTypeResult getResultForDataType(
BackupRestoreEventLogger logger, String dataType) {
Optional<DataTypeResult> result = getResultForDataTypeIfPresent(logger, dataType);
diff --git a/core/tests/coretests/src/android/app/backup/DataTypeResultTest.java b/core/tests/coretests/src/android/app/backup/DataTypeResultTest.java
new file mode 100644
index 000000000000..cf9e9c6e2f95
--- /dev/null
+++ b/core/tests/coretests/src/android/app/backup/DataTypeResultTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2025 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.backup;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.app.backup.BackupRestoreEventLogger.DataTypeResult;
+import android.os.Bundle;
+import android.os.Parcel;
+
+import com.google.common.truth.Expect;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.Map;
+
+public final class DataTypeResultTest {
+
+ @Rule
+ public final Expect expect = Expect.create();
+
+ @Test
+ public void testGetters_defaultConstructorFields() {
+ var result = new DataTypeResult("The Type is Bond, James Bond!");
+
+ expect.withMessage("getDataType()").that(result.getDataType())
+ .isEqualTo("The Type is Bond, James Bond!");
+ expect.withMessage("getSuccessCount()").that(result.getSuccessCount()).isEqualTo(0);
+ expect.withMessage("getFailCount()").that(result.getFailCount()).isEqualTo(0);
+ expect.withMessage("getErrorsCount()").that(result.getErrors()).isEmpty();
+ expect.withMessage("getMetadataHash()").that(result.getMetadataHash()).isNull();
+ expect.withMessage("describeContents()").that(result.describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetters_allFields() {
+ DataTypeResult result = createDataTypeResult("The Type is Bond, James Bond!",
+ /* successCount= */ 42, /* failCount= */ 108, Map.of("D'OH!", 666),
+ new byte[] { 4, 8, 15, 16, 23, 42 });
+
+ expect.withMessage("getDataType()").that(result.getDataType())
+ .isEqualTo("The Type is Bond, James Bond!");
+ expect.withMessage("getSuccessCount()").that(result.getSuccessCount()).isEqualTo(42);
+ expect.withMessage("getFailCount()").that(result.getFailCount()).isEqualTo(108);
+ expect.withMessage("getErrorsCount()").that(result.getErrors()).containsExactly("D'OH!",
+ 666);
+ expect.withMessage("getMetadataHash()").that(result.getMetadataHash()).asList()
+ .containsExactly((byte) 4, (byte) 8, (byte) 15, (byte) 16, (byte) 23, (byte) 42)
+ .inOrder();
+ expect.withMessage("describeContents()").that(result.describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void testParcelMethods() {
+ DataTypeResult original = createDataTypeResult("The Type is Bond, James Bond!",
+ /* successCount= */ 42, /* failCount= */ 108, Map.of("D'OH!", 666),
+ new byte[] { 4, 8, 15, 16, 23, 42 });
+ Parcel parcel = Parcel.obtain();
+ try {
+ original.writeToParcel(parcel, /* flags= */ 0);
+
+ parcel.setDataPosition(0);
+ var clone = DataTypeResult.CREATOR.createFromParcel(parcel);
+ assertWithMessage("createFromParcel()").that(clone).isNotNull();
+
+ expect.withMessage("getDataType()").that(clone.getDataType())
+ .isEqualTo(original.getDataType());
+ expect.withMessage("getSuccessCount()").that(clone.getSuccessCount())
+ .isEqualTo(original.getSuccessCount());
+ expect.withMessage("getFailCount()").that(clone.getFailCount())
+ .isEqualTo(original.getFailCount());
+ expect.withMessage("getErrorsCount()").that(clone.getErrors())
+ .containsExactlyEntriesIn(original.getErrors()).inOrder();
+ expect.withMessage("getMetadataHash()").that(clone.getMetadataHash())
+ .isEqualTo(original.getMetadataHash());
+ expect.withMessage("describeContents()").that(clone.describeContents()).isEqualTo(0);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ static DataTypeResult createDataTypeResult(String dataType, int successCount, int failCount,
+ Map<String, Integer> errors, byte... metadataHash) {
+ Parcel parcel = Parcel.obtain();
+ try {
+ parcel.writeString(dataType);
+ parcel.writeInt(successCount);
+ parcel.writeInt(failCount);
+ Bundle errorsBundle = new Bundle();
+ errors.entrySet()
+ .forEach(entry -> errorsBundle.putInt(entry.getKey(), entry.getValue()));
+ parcel.writeBundle(errorsBundle);
+ parcel.writeByteArray(metadataHash);
+
+ parcel.setDataPosition(0);
+ var result = DataTypeResult.CREATOR.createFromParcel(parcel);
+ assertWithMessage("createFromParcel()").that(result).isNotNull();
+ return result;
+ } finally {
+ parcel.recycle();
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble.png
new file mode 100644
index 000000000000..15198748eea5
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubbleBar.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubbleBar.png
new file mode 100644
index 000000000000..99673f6400e9
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubbleBar.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_10_90.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_10_90.png
new file mode 100644
index 000000000000..ba4ebab75a7e
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_10_90.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_90_10.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_90_10.png
new file mode 100644
index 000000000000..b3ff64401a96
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_90_10.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView.png
new file mode 100644
index 000000000000..534e320a0596
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_10_90.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_10_90.png
new file mode 100644
index 000000000000..67c9f49171ba
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_10_90.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_90_10.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_90_10.png
new file mode 100644
index 000000000000..a0fb4902a6f3
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_90_10.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble.png
new file mode 100644
index 000000000000..27b35d447868
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubbleBar.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubbleBar.png
new file mode 100644
index 000000000000..11528a028a8f
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubbleBar.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_10_90.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_10_90.png
new file mode 100644
index 000000000000..ef9937700c08
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_10_90.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_90_10.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_90_10.png
new file mode 100644
index 000000000000..f0cf08bfcf4e
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_90_10.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_expandedView.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_expandedView.png
new file mode 100644
index 000000000000..bbaafb39845a
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_expandedView.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubble.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubble.png
new file mode 100644
index 000000000000..38ebf3f3201a
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubble.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubbleBar.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubbleBar.png
new file mode 100644
index 000000000000..2e4fd51e3932
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubbleBar.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_expandedView.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_expandedView.png
new file mode 100644
index 000000000000..a1ba9fb50d6a
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_expandedView.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubble.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubble.png
new file mode 100644
index 000000000000..51bb15e10d30
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubble.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubbleBar.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubbleBar.png
new file mode 100644
index 000000000000..b643e2a69b2c
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubbleBar.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_expandedView.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_expandedView.png
new file mode 100644
index 000000000000..e6eeab7129be
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_expandedView.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryScreenshotTest.kt b/libs/WindowManager/Shell/multivalentScreenshotTests/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryScreenshotTest.kt
new file mode 100644
index 000000000000..24f43d347163
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryScreenshotTest.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.shared.bubbles
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.view.View
+import android.view.WindowManager
+import android.widget.FrameLayout
+import androidx.annotation.ColorInt
+import androidx.core.graphics.blue
+import androidx.core.graphics.green
+import androidx.core.graphics.red
+import androidx.core.graphics.toColorInt
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import com.android.wm.shell.shared.bubbles.DragZoneFactory.DesktopWindowModeChecker
+import com.android.wm.shell.shared.bubbles.DragZoneFactory.SplitScreenModeChecker
+import com.android.wm.shell.shared.bubbles.DragZoneFactory.SplitScreenModeChecker.SplitScreenMode
+import com.android.wm.shell.testing.goldenpathmanager.WMShellGoldenPathManager
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+import platform.test.screenshot.DeviceEmulationSpec
+import platform.test.screenshot.Displays
+import platform.test.screenshot.ViewScreenshotTestRule
+import platform.test.screenshot.ViewScreenshotTestRule.Mode
+import platform.test.screenshot.getEmulatedDevicePathConfig
+
+@RunWith(ParameterizedAndroidJunit4::class)
+class DragZoneFactoryScreenshotTest(private val param: Param) {
+ companion object {
+ @Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs(): List<Param> {
+ val params = mutableListOf<Param>()
+ val draggedObjects =
+ listOf(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ DraggedObject.BubbleBar(BubbleBarLocation.LEFT),
+ DraggedObject.ExpandedView(BubbleBarLocation.LEFT),
+ )
+ DeviceEmulationSpec.forDisplays(Displays.Tablet, isDarkTheme = false).forEach { tablet
+ ->
+ draggedObjects.forEach { draggedObject ->
+ params.add(Param(tablet, draggedObject, SplitScreenMode.NONE))
+ }
+ }
+ DeviceEmulationSpec.forDisplays(Displays.FoldableInner, isDarkTheme = false).forEach {
+ foldable ->
+ draggedObjects.forEach { draggedObject ->
+ params.add(Param(foldable, draggedObject, SplitScreenMode.NONE))
+ val isBubble = draggedObject is DraggedObject.Bubble
+ val isExpandedView = draggedObject is DraggedObject.ExpandedView
+ val addMoreSplitModes = isBubble || (isExpandedView && foldable.isLandscape)
+ if (addMoreSplitModes) {
+ params.add(Param(foldable, draggedObject, SplitScreenMode.SPLIT_10_90))
+ params.add(Param(foldable, draggedObject, SplitScreenMode.SPLIT_90_10))
+ }
+ }
+ }
+ return params
+ }
+ }
+
+ class Param(
+ val emulationSpec: DeviceEmulationSpec,
+ val draggedObject: DraggedObject,
+ val splitScreenMode: SplitScreenMode
+ ) {
+ private val draggedObjectName =
+ when (draggedObject) {
+ is DraggedObject.Bubble -> "bubble"
+ is DraggedObject.BubbleBar -> "bubbleBar"
+ is DraggedObject.ExpandedView -> "expandedView"
+ }
+
+ private val splitScreenModeName =
+ when (splitScreenMode) {
+ SplitScreenMode.NONE -> ""
+ SplitScreenMode.SPLIT_50_50 -> "_split_50_50"
+ SplitScreenMode.SPLIT_10_90 -> "_split_10_90"
+ SplitScreenMode.SPLIT_90_10 -> "_split_90_10"
+ }
+
+ val testName = "$draggedObjectName$splitScreenModeName"
+
+ override fun toString() = "${emulationSpec}_$testName"
+ }
+
+ @get:Rule
+ val screenshotRule =
+ ViewScreenshotTestRule(
+ param.emulationSpec,
+ WMShellGoldenPathManager(getEmulatedDevicePathConfig(param.emulationSpec))
+ )
+
+ private val context = getApplicationContext<Context>()
+
+ @Test
+ fun dragZones() {
+ screenshotRule.screenshotTest("dragZones_${param.testName}", mode = Mode.MatchSize) {
+ activity ->
+ activity.actionBar?.hide()
+ val dragZoneFactory = createDragZoneFactory()
+ val dragZones = dragZoneFactory.createSortedDragZones(param.draggedObject)
+ val container = FrameLayout(context)
+ dragZones.forEach { zone -> container.addZoneView(zone) }
+ container
+ }
+ }
+
+ private fun createDragZoneFactory(): DragZoneFactory {
+ val deviceConfig =
+ DeviceConfig.create(context, context.getSystemService(WindowManager::class.java)!!)
+ val splitScreenModeChecker = SplitScreenModeChecker { param.splitScreenMode }
+ val desktopWindowModeChecker = DesktopWindowModeChecker { true }
+ return DragZoneFactory(
+ context,
+ deviceConfig,
+ splitScreenModeChecker,
+ desktopWindowModeChecker
+ )
+ }
+
+ private fun FrameLayout.addZoneView(zone: DragZone) {
+ val view = View(context)
+ this.addView(view, 0)
+ view.layoutParams = FrameLayout.LayoutParams(zone.bounds.width(), zone.bounds.height())
+ view.background = createZoneDrawable(zone.color)
+ view.x = zone.bounds.left.toFloat()
+ view.y = zone.bounds.top.toFloat()
+ }
+
+ private fun createZoneDrawable(@ColorInt color: Int): Drawable {
+ val shape = GradientDrawable()
+ shape.shape = GradientDrawable.RECTANGLE
+ shape.setColor(Color.argb(128, color.red, color.green, color.blue))
+ shape.setStroke(2, color)
+ return shape
+ }
+
+ private val DragZone.color: Int
+ @ColorInt
+ get() =
+ when (this) {
+ is DragZone.Bubble -> "#3F5C8B".toColorInt()
+ is DragZone.Dismiss -> "#8B3F3F".toColorInt()
+ is DragZone.Split -> "#89B675".toColorInt()
+ is DragZone.FullScreen -> "#4ED075".toColorInt()
+ is DragZone.DesktopWindow -> "#EC928E".toColorInt()
+ }
+}
diff --git a/libs/WindowManager/Shell/shared/res/values/dimen.xml b/libs/WindowManager/Shell/shared/res/values/dimen.xml
index 5f013c52d70d..11a6f32d7454 100644
--- a/libs/WindowManager/Shell/shared/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/shared/res/values/dimen.xml
@@ -38,6 +38,7 @@
<dimen name="drag_zone_v_split_from_expanded_view_height_fold_short">100dp</dimen>
<!-- Bubble drop target dimensions -->
+ <dimen name="drop_target_elevation">1dp</dimen>
<dimen name="drop_target_full_screen_padding">20dp</dimen>
<dimen name="drop_target_desktop_window_padding_small">100dp</dimen>
<dimen name="drop_target_desktop_window_padding_large">130dp</dimen>
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZone.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZone.kt
index 5d346c047123..6eff75c9a479 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZone.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZone.kt
@@ -31,29 +31,41 @@ sealed interface DragZone {
/** The bounds of this drag zone. */
val bounds: Rect
+ /** The bounds of the drop target associated with this drag zone. */
+ val dropTarget: Rect?
fun contains(x: Int, y: Int) = bounds.contains(x, y)
/** Represents the bubble drag area on the screen. */
- sealed class Bubble(override val bounds: Rect) : DragZone {
- data class Left(override val bounds: Rect, val dropTarget: Rect) : Bubble(bounds)
- data class Right(override val bounds: Rect, val dropTarget: Rect) : Bubble(bounds)
+ sealed class Bubble(override val bounds: Rect, override val dropTarget: Rect) : DragZone {
+ data class Left(override val bounds: Rect, override val dropTarget: Rect) :
+ Bubble(bounds, dropTarget)
+
+ data class Right(override val bounds: Rect, override val dropTarget: Rect) :
+ Bubble(bounds, dropTarget)
}
/** Represents dragging to Desktop Window. */
- data class DesktopWindow(override val bounds: Rect, val dropTarget: Rect) : DragZone
+ data class DesktopWindow(override val bounds: Rect, override val dropTarget: Rect) : DragZone
/** Represents dragging to Full Screen. */
- data class FullScreen(override val bounds: Rect, val dropTarget: Rect) : DragZone
+ data class FullScreen(override val bounds: Rect, override val dropTarget: Rect) : DragZone
/** Represents dragging to dismiss. */
- data class Dismiss(override val bounds: Rect) : DragZone
+ data class Dismiss(override val bounds: Rect) : DragZone {
+ override val dropTarget: Rect? = null
+ }
/** Represents dragging to enter Split or replace a Split app. */
sealed class Split(override val bounds: Rect) : DragZone {
+ override val dropTarget: Rect? = null
+
data class Left(override val bounds: Rect) : Split(bounds)
+
data class Right(override val bounds: Rect) : Split(bounds)
+
data class Top(override val bounds: Rect) : Split(bounds)
+
data class Bottom(override val bounds: Rect) : Split(bounds)
}
}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt
index 29ce8d90e66f..2dc183f3f707 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt
@@ -16,22 +16,54 @@
package com.android.wm.shell.shared.bubbles
+import android.content.Context
+import android.graphics.Rect
+import android.view.View
+import android.widget.FrameLayout
+import androidx.core.animation.Animator
+import androidx.core.animation.AnimatorListenerAdapter
+import androidx.core.animation.ValueAnimator
+
/**
* Manages animating drop targets in response to dragging bubble icons or bubble expanded views
* across different drag zones.
*/
class DropTargetManager(
+ context: Context,
+ private val container: FrameLayout,
private val isLayoutRtl: Boolean,
- private val dragZoneChangedListener: DragZoneChangedListener
+ private val dragZoneChangedListener: DragZoneChangedListener,
) {
private var state: DragState? = null
+ private val dropTargetView = View(context)
+ private var animator: ValueAnimator? = null
+
+ private companion object {
+ const val ANIMATION_DURATION_MS = 250L
+ }
/** Must be called when a drag gesture is starting. */
fun onDragStarted(draggedObject: DraggedObject, dragZones: List<DragZone>) {
val state = DragState(dragZones, draggedObject)
dragZoneChangedListener.onInitialDragZoneSet(state.initialDragZone)
this.state = state
+ animator?.cancel()
+ setupDropTarget()
+ }
+
+ private fun setupDropTarget() {
+ if (dropTargetView.parent != null) container.removeView(dropTargetView)
+ container.addView(dropTargetView, 0)
+ // TODO b/393173014: set elevation and background
+ dropTargetView.alpha = 0f
+ dropTargetView.scaleX = 1f
+ dropTargetView.scaleY = 1f
+ dropTargetView.translationX = 0f
+ dropTargetView.translationY = 0f
+ // the drop target is added with a width and height of 1 pixel. when it gets resized, we use
+ // set its scale to the width and height of the bounds it should have to avoid layout passes
+ dropTargetView.layoutParams = FrameLayout.LayoutParams(/* width= */ 1, /* height= */ 1)
}
/** Called when the user drags to a new location. */
@@ -42,14 +74,67 @@ class DropTargetManager(
state.currentDragZone = newDragZone
if (oldDragZone != newDragZone) {
dragZoneChangedListener.onDragZoneChanged(from = oldDragZone, to = newDragZone)
+ updateDropTarget()
}
}
/** Called when the drag ended. */
fun onDragEnded() {
+ startFadeAnimation(from = dropTargetView.alpha, to = 0f) {
+ container.removeView(dropTargetView)
+ }
state = null
}
+ private fun updateDropTarget() {
+ val currentDragZone = state?.currentDragZone ?: return
+ val dropTargetBounds = currentDragZone.dropTarget
+ when {
+ dropTargetBounds == null -> startFadeAnimation(from = dropTargetView.alpha, to = 0f)
+ dropTargetView.alpha == 0f -> {
+ dropTargetView.translationX = dropTargetBounds.exactCenterX()
+ dropTargetView.translationY = dropTargetBounds.exactCenterY()
+ dropTargetView.scaleX = dropTargetBounds.width().toFloat()
+ dropTargetView.scaleY = dropTargetBounds.height().toFloat()
+ startFadeAnimation(from = 0f, to = 1f)
+ }
+ else -> startMorphAnimation(dropTargetBounds)
+ }
+ }
+
+ private fun startFadeAnimation(from: Float, to: Float, onEnd: (() -> Unit)? = null) {
+ animator?.cancel()
+ val animator = ValueAnimator.ofFloat(from, to).setDuration(ANIMATION_DURATION_MS)
+ animator.addUpdateListener { _ -> dropTargetView.alpha = animator.animatedValue as Float }
+ if (onEnd != null) {
+ animator.doOnEnd(onEnd)
+ }
+ this.animator = animator
+ animator.start()
+ }
+
+ private fun startMorphAnimation(bounds: Rect) {
+ animator?.cancel()
+ val startAlpha = dropTargetView.alpha
+ val startTx = dropTargetView.translationX
+ val startTy = dropTargetView.translationY
+ val startScaleX = dropTargetView.scaleX
+ val startScaleY = dropTargetView.scaleY
+ val animator = ValueAnimator.ofFloat(0f, 1f).setDuration(ANIMATION_DURATION_MS)
+ animator.addUpdateListener { _ ->
+ val fraction = animator.animatedValue as Float
+ dropTargetView.alpha = startAlpha + (1 - startAlpha) * fraction
+ dropTargetView.translationX = startTx + (bounds.exactCenterX() - startTx) * fraction
+ dropTargetView.translationY = startTy + (bounds.exactCenterY() - startTy) * fraction
+ dropTargetView.scaleX =
+ startScaleX + (bounds.width().toFloat() - startScaleX) * fraction
+ dropTargetView.scaleY =
+ startScaleY + (bounds.height().toFloat() - startScaleY) * fraction
+ }
+ this.animator = animator
+ animator.start()
+ }
+
/** Stores the current drag state. */
private inner class DragState(
private val dragZones: List<DragZone>,
@@ -72,7 +157,18 @@ class DropTargetManager(
interface DragZoneChangedListener {
/** An initial drag zone was set. Called when a drag starts. */
fun onInitialDragZoneSet(dragZone: DragZone)
+
/** Called when the object was dragged to a different drag zone. */
fun onDragZoneChanged(from: DragZone, to: DragZone)
}
+
+ private fun Animator.doOnEnd(onEnd: () -> Unit) {
+ addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ onEnd()
+ }
+ }
+ )
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 0afceac8a861..d767a0b5bd57 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -467,10 +467,7 @@ class DesktopTasksController(
}
// TODO(342378842): Instead of using default display, support multiple displays
val displayId = runningTask?.displayId ?: DEFAULT_DISPLAY
- val deskId =
- checkNotNull(taskRepository.getDefaultDeskId(displayId)) {
- "Expected a default desk to exist"
- }
+ val deskId = getDefaultDeskId(displayId)
return moveTaskToDesk(
taskId = taskId,
deskId = deskId,
@@ -715,10 +712,7 @@ class DesktopTasksController(
* [startDragToDesktop].
*/
private fun finalizeDragToDesktop(taskInfo: RunningTaskInfo) {
- val deskId =
- checkNotNull(taskRepository.getDefaultDeskId(taskInfo.displayId)) {
- "Expected a default desk to exist"
- }
+ val deskId = getDefaultDeskId(taskInfo.displayId)
ProtoLog.v(
WM_SHELL_DESKTOP_MODE,
"DesktopTasksController: finalizeDragToDesktop taskId=%d deskId=%d",
@@ -2050,8 +2044,10 @@ class DesktopTasksController(
unminimizeReason = UnminimizeReason.APP_HANDLE_MENU_BUTTON,
)
} else {
- moveBackgroundTaskToDesktop(
+ val deskId = getDefaultDeskId(callingTask.displayId)
+ moveTaskToDesk(
requestedTaskId,
+ deskId,
WindowContainerTransaction(),
DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON,
)
@@ -2661,10 +2657,7 @@ class DesktopTasksController(
displayId: Int,
remoteTransition: RemoteTransition? = null,
) {
- val deskId =
- checkNotNull(taskRepository.getDefaultDeskId(displayId)) {
- "Expected a default desk to exist"
- }
+ val deskId = getDefaultDeskId(displayId)
activateDesk(deskId, remoteTransition)
}
@@ -2728,13 +2721,15 @@ class DesktopTasksController(
/** Removes the default desk in the given display. */
@Deprecated("Deprecated with multi-desks.", ReplaceWith("removeDesk()"))
fun removeDefaultDeskInDisplay(displayId: Int) {
- val deskId =
- checkNotNull(taskRepository.getDefaultDeskId(displayId)) {
- "Expected a default desk to exist"
- }
+ val deskId = getDefaultDeskId(displayId)
removeDesk(displayId = displayId, deskId = deskId)
}
+ private fun getDefaultDeskId(displayId: Int) =
+ checkNotNull(taskRepository.getDefaultDeskId(displayId)) {
+ "Expected a default desk to exist in display: $displayId"
+ }
+
/** Removes the given desk. */
fun removeDesk(deskId: Int) {
val displayId = taskRepository.getDisplayForDesk(deskId)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java
index 71697596afd3..a837e7d308eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java
@@ -296,6 +296,7 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
return;
}
+ mMagneticTarget.updateLocationOnScreen();
createOrUpdateDismissTarget();
if (mTargetViewContainer.getVisibility() != View.VISIBLE) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 4f2e028a1df0..2fa09664b73f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -381,7 +381,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
private void notifyRunningTaskAppeared(RunningTaskInfo taskInfo) {
if (mListener == null
|| !shouldEnableRunningTasksForDesktopMode()
- || taskInfo.realActivity == null) {
+ || taskInfo.realActivity == null
+ || excludeTaskFromGeneratedList(taskInfo)) {
return;
}
try {
@@ -397,7 +398,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
private void notifyRunningTaskChanged(RunningTaskInfo taskInfo) {
if (mListener == null
|| !shouldEnableRunningTasksForDesktopMode()
- || taskInfo.realActivity == null) {
+ || taskInfo.realActivity == null
+ || excludeTaskFromGeneratedList(taskInfo)) {
return;
}
try {
@@ -413,7 +415,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
private void notifyRunningTaskVanished(RunningTaskInfo taskInfo) {
if (mListener == null
|| !shouldEnableRunningTasksForDesktopMode()
- || taskInfo.realActivity == null) {
+ || taskInfo.realActivity == null
+ || excludeTaskFromGeneratedList(taskInfo)) {
return;
}
try {
@@ -430,7 +433,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
if (mListener == null
|| !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue()
|| taskInfo.realActivity == null
- || enableShellTopTaskTracking()) {
+ || enableShellTopTaskTracking()
+ || excludeTaskFromGeneratedList(taskInfo)) {
return;
}
try {
@@ -447,7 +451,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
if (mListener == null
|| !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue()
|| taskInfo.realActivity == null
- || enableShellTopTaskTracking()) {
+ || enableShellTopTaskTracking()
+ || excludeTaskFromGeneratedList(taskInfo)) {
return;
}
try {
diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp
index bf5e374c7607..bff12d026b93 100644
--- a/libs/WindowManager/Shell/tests/unittest/Android.bp
+++ b/libs/WindowManager/Shell/tests/unittest/Android.bp
@@ -45,6 +45,7 @@ android_test {
"androidx.test.rules",
"androidx.test.ext.junit",
"androidx.datastore_datastore",
+ "androidx.core_core-animation-testing",
"kotlinx_coroutines_test",
"androidx.dynamicanimation_dynamicanimation",
"dagger2",
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 5028479b6ace..a546b3ea7d8f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -107,6 +107,7 @@ import java.util.function.Consumer;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class RecentTasksControllerTest extends ShellTestCase {
+ private static final String SYSTEM_UI_PACKAGE_NAME = "com.android.systemui";
@Mock
private Context mContext;
@@ -582,6 +583,19 @@ public class RecentTasksControllerTest extends ShellTestCase {
@Test
@EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS})
+ public void onTaskAdded_orDesktopWallpaperActivity_doesNotTriggerOnRunningTaskAppeared()
+ throws Exception {
+ RunningTaskInfo taskInfo = makeDesktopWallpaperActivityTaskInfo(/* taskId= */10);
+ mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+
+ mRecentTasksControllerReal.onTaskAdded(taskInfo);
+
+ verify(mRecentTasksListener, never()).onRunningTaskAppeared(any());
+ }
+
+ @Test
+ @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS})
public void taskWindowingModeChanged_desktopRunningAppsEnabled_triggersOnRunningTaskChanged()
throws Exception {
mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
@@ -593,6 +607,19 @@ public class RecentTasksControllerTest extends ShellTestCase {
}
@Test
+ @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS})
+ public void taskInfoChanged_forDesktopWallpaperActivity_doesNotTriggerOnRunningTaskChanged()
+ throws Exception {
+ RunningTaskInfo taskInfo = makeDesktopWallpaperActivityTaskInfo(/* taskId= */10);
+ mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+
+ mRecentTasksControllerReal.onTaskRunningInfoChanged(taskInfo);
+
+ verify(mRecentTasksListener, never()).onRunningTaskChanged(any());
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
@DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS)
public void
@@ -619,6 +646,20 @@ public class RecentTasksControllerTest extends ShellTestCase {
verify(mRecentTasksListener).onRunningTaskVanished(taskInfo);
}
+
+ @Test
+ @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS})
+ public void onTaskRemoved_forDesktopWallpaperActivity_doesNotTriggerOnRunningTaskVanished()
+ throws Exception {
+ RunningTaskInfo taskInfo = makeDesktopWallpaperActivityTaskInfo(/* taskId= */10);
+ mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+
+ mRecentTasksControllerReal.onTaskRemoved(taskInfo);
+
+ verify(mRecentTasksListener, never()).onRunningTaskVanished(any());
+ }
+
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
@DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS)
@@ -659,6 +700,18 @@ public class RecentTasksControllerTest extends ShellTestCase {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ public void onDesktopWallpaperActivityMovedToFront_doesNotTriggerOnTaskMovedToFront()
+ throws Exception {
+ RunningTaskInfo taskInfo = makeDesktopWallpaperActivityTaskInfo(/* taskId= */10);
+ mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+
+ mRecentTasksControllerReal.onTaskMovedToFrontThroughTransition(taskInfo);
+
+ verify(mRecentTasksListener, never()).onTaskMovedToFront(any());
+ }
+
+ @Test
public void getNullSplitBoundsNonSplitTask() {
SplitBounds sb = mRecentTasksController.getSplitBoundsForTaskId(3);
assertNull("splitBounds should be null for non-split task", sb);
@@ -829,16 +882,25 @@ public class RecentTasksControllerTest extends ShellTestCase {
* Helper to create a running task with a given task id.
*/
private RunningTaskInfo makeRunningTaskInfo(int taskId) {
+ return makeRunningTaskInfo(taskId, new ComponentName("com." + taskId, "Activity" + taskId));
+ }
+
+ private RunningTaskInfo makeRunningTaskInfo(int taskId, ComponentName intentComponent) {
RunningTaskInfo info = new RunningTaskInfo();
info.taskId = taskId;
info.realActivity = new ComponentName("testPackage", "testClass");
Intent intent = new Intent();
- intent.setComponent(new ComponentName("com." + taskId, "Activity" + taskId));
+ intent.setComponent(intentComponent);
info.baseIntent = intent;
info.lastNonFullscreenBounds = new Rect();
return info;
}
+ private RunningTaskInfo makeDesktopWallpaperActivityTaskInfo(int taskId) {
+ return makeRunningTaskInfo(taskId, new ComponentName(SYSTEM_UI_PACKAGE_NAME,
+ DesktopWallpaperActivity.class.getName()));
+ }
+
/**
* Helper to set the raw task list on the controller.
*/
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt
index efb91c5fbfda..180a6915b45f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt
@@ -16,23 +16,33 @@
package com.android.wm.shell.shared.bubbles
+import android.content.Context
import android.graphics.Rect
+import android.view.View
+import android.widget.FrameLayout
+import androidx.core.animation.AnimatorTestRule
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFails
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import kotlin.test.assertFails
/** Unit tests for [DropTargetManager]. */
@SmallTest
@RunWith(AndroidJUnit4::class)
class DropTargetManagerTest {
+ @get:Rule val animatorTestRule = AnimatorTestRule()
+
+ private val context = getApplicationContext<Context>()
private lateinit var dropTargetManager: DropTargetManager
private lateinit var dragZoneChangedListener: FakeDragZoneChangedListener
- private val dropTarget = Rect(0, 0, 0, 0)
+ private lateinit var container: FrameLayout
// create 3 drop zones that are horizontally next to each other
// -------------------------------------------------
@@ -43,15 +53,20 @@ class DropTargetManagerTest {
// | | | |
// -------------------------------------------------
private val bubbleLeftDragZone =
- DragZone.Bubble.Left(bounds = Rect(0, 0, 100, 100), dropTarget = dropTarget)
+ DragZone.Bubble.Left(bounds = Rect(0, 0, 100, 100), dropTarget = Rect(0, 0, 50, 200))
private val dismissDragZone = DragZone.Dismiss(bounds = Rect(100, 0, 200, 100))
private val bubbleRightDragZone =
- DragZone.Bubble.Right(bounds = Rect(200, 0, 300, 100), dropTarget = dropTarget)
+ DragZone.Bubble.Right(bounds = Rect(200, 0, 300, 100), dropTarget = Rect(200, 0, 280, 150))
+
+ private val dropTargetView: View
+ get() = container.getChildAt(0)
@Before
fun setUp() {
+ container = FrameLayout(context)
dragZoneChangedListener = FakeDragZoneChangedListener()
- dropTargetManager = DropTargetManager(isLayoutRtl = false, dragZoneChangedListener)
+ dropTargetManager =
+ DropTargetManager(context, container, isLayoutRtl = false, dragZoneChangedListener)
}
@Test
@@ -79,17 +94,21 @@ class DropTargetManagerTest {
DraggedObject.Bubble(BubbleBarLocation.LEFT),
listOf(bubbleLeftDragZone, bubbleRightDragZone, dismissDragZone)
)
- dropTargetManager.onDragUpdated(
- bubbleRightDragZone.bounds.centerX(),
- bubbleRightDragZone.bounds.centerY()
- )
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ bubbleRightDragZone.bounds.centerX(),
+ bubbleRightDragZone.bounds.centerY()
+ )
+ }
assertThat(dragZoneChangedListener.fromDragZone).isEqualTo(bubbleLeftDragZone)
assertThat(dragZoneChangedListener.toDragZone).isEqualTo(bubbleRightDragZone)
- dropTargetManager.onDragUpdated(
- dismissDragZone.bounds.centerX(),
- dismissDragZone.bounds.centerY()
- )
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ dismissDragZone.bounds.centerX(),
+ dismissDragZone.bounds.centerY()
+ )
+ }
assertThat(dragZoneChangedListener.fromDragZone).isEqualTo(bubbleRightDragZone)
assertThat(dragZoneChangedListener.toDragZone).isEqualTo(dismissDragZone)
}
@@ -100,10 +119,12 @@ class DropTargetManagerTest {
DraggedObject.Bubble(BubbleBarLocation.LEFT),
listOf(bubbleLeftDragZone, bubbleRightDragZone, dismissDragZone)
)
- dropTargetManager.onDragUpdated(
- bubbleLeftDragZone.bounds.centerX(),
- bubbleLeftDragZone.bounds.centerY()
- )
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ bubbleLeftDragZone.bounds.centerX(),
+ bubbleLeftDragZone.bounds.centerY()
+ )
+ }
assertThat(dragZoneChangedListener.fromDragZone).isNull()
assertThat(dragZoneChangedListener.toDragZone).isNull()
}
@@ -118,7 +139,9 @@ class DropTargetManagerTest {
val pointY = 200
assertThat(bubbleLeftDragZone.contains(pointX, pointY)).isFalse()
assertThat(bubbleRightDragZone.contains(pointX, pointY)).isFalse()
- dropTargetManager.onDragUpdated(pointX, pointY)
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(pointX, pointY)
+ }
assertThat(dragZoneChangedListener.fromDragZone).isNull()
assertThat(dragZoneChangedListener.toDragZone).isNull()
}
@@ -135,27 +158,30 @@ class DropTargetManagerTest {
// drag to a point that is within both the bubble right zone and split zone
val (pointX, pointY) =
- Pair(
- bubbleRightDragZone.bounds.centerX(),
- bubbleRightDragZone.bounds.centerY()
- )
+ Pair(bubbleRightDragZone.bounds.centerX(), bubbleRightDragZone.bounds.centerY())
assertThat(splitDragZone.contains(pointX, pointY)).isTrue()
- dropTargetManager.onDragUpdated(pointX, pointY)
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(pointX, pointY)
+ }
// verify we dragged to the bubble right zone because that has higher priority than split
assertThat(dragZoneChangedListener.fromDragZone).isEqualTo(bubbleLeftDragZone)
assertThat(dragZoneChangedListener.toDragZone).isEqualTo(bubbleRightDragZone)
- dropTargetManager.onDragUpdated(
- bubbleRightDragZone.bounds.centerX(),
- 150 // below the bubble and dismiss drag zones but within split
- )
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ bubbleRightDragZone.bounds.centerX(),
+ 150 // below the bubble and dismiss drag zones but within split
+ )
+ }
assertThat(dragZoneChangedListener.fromDragZone).isEqualTo(bubbleRightDragZone)
assertThat(dragZoneChangedListener.toDragZone).isEqualTo(splitDragZone)
val (dismissPointX, dismissPointY) =
Pair(dismissDragZone.bounds.centerX(), dismissDragZone.bounds.centerY())
assertThat(splitDragZone.contains(dismissPointX, dismissPointY)).isTrue()
- dropTargetManager.onDragUpdated(dismissPointX, dismissPointY)
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(dismissPointX, dismissPointY)
+ }
assertThat(dragZoneChangedListener.fromDragZone).isEqualTo(splitDragZone)
assertThat(dragZoneChangedListener.toDragZone).isEqualTo(dismissDragZone)
}
@@ -166,7 +192,9 @@ class DropTargetManagerTest {
DraggedObject.Bubble(BubbleBarLocation.LEFT),
listOf(bubbleLeftDragZone, bubbleRightDragZone, dismissDragZone)
)
- dropTargetManager.onDragEnded()
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragEnded()
+ }
dropTargetManager.onDragUpdated(
bubbleRightDragZone.bounds.centerX(),
bubbleRightDragZone.bounds.centerY()
@@ -175,6 +203,129 @@ class DropTargetManagerTest {
assertThat(dragZoneChangedListener.toDragZone).isNull()
}
+ @Test
+ fun onDragStarted_dropTargetAddedToContainer() {
+ dropTargetManager.onDragStarted(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ listOf(bubbleLeftDragZone, bubbleRightDragZone)
+ )
+ assertThat(container.childCount).isEqualTo(1)
+ assertThat(dropTargetView.alpha).isEqualTo(0)
+ }
+
+ @Test
+ fun onDragEnded_dropTargetRemovedFromContainer() {
+ dropTargetManager.onDragStarted(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ listOf(bubbleLeftDragZone, bubbleRightDragZone)
+ )
+ assertThat(container.childCount).isEqualTo(1)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragEnded()
+ animatorTestRule.advanceTimeBy(250)
+ }
+ assertThat(container.childCount).isEqualTo(0)
+ }
+
+ @Test
+ fun startNewDrag_beforeDropTargetRemoved() {
+ dropTargetManager.onDragStarted(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ listOf(bubbleLeftDragZone, bubbleRightDragZone)
+ )
+ assertThat(container.childCount).isEqualTo(1)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragEnded()
+ // advance the timer by 100ms so the animation doesn't complete
+ animatorTestRule.advanceTimeBy(100)
+ }
+ assertThat(container.childCount).isEqualTo(1)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragStarted(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ listOf(bubbleLeftDragZone, bubbleRightDragZone)
+ )
+ }
+ assertThat(container.childCount).isEqualTo(1)
+ }
+
+ @Test
+ fun updateDragZone_withDropTarget_dropTargetUpdated() {
+ dropTargetManager.onDragStarted(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ listOf(dismissDragZone, bubbleLeftDragZone, bubbleRightDragZone)
+ )
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ bubbleRightDragZone.bounds.centerX(),
+ bubbleRightDragZone.bounds.centerY()
+ )
+ animatorTestRule.advanceTimeBy(250)
+ }
+
+ assertThat(dropTargetView.alpha).isEqualTo(1)
+ verifyDropTargetPosition(bubbleRightDragZone.dropTarget)
+ }
+
+ @Test
+ fun updateDragZone_withoutDropTarget_dropTargetHidden() {
+ dropTargetManager.onDragStarted(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ listOf(dismissDragZone, bubbleLeftDragZone, bubbleRightDragZone)
+ )
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ dismissDragZone.bounds.centerX(),
+ dismissDragZone.bounds.centerY()
+ )
+ animatorTestRule.advanceTimeBy(250)
+ }
+
+ assertThat(dropTargetView.alpha).isEqualTo(0)
+ }
+
+ @Test
+ fun updateDragZone_betweenZonesWithDropTarget_dropTargetUpdated() {
+ dropTargetManager.onDragStarted(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ listOf(dismissDragZone, bubbleLeftDragZone, bubbleRightDragZone)
+ )
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ bubbleRightDragZone.bounds.centerX(),
+ bubbleRightDragZone.bounds.centerY()
+ )
+ animatorTestRule.advanceTimeBy(250)
+ }
+
+ assertThat(dropTargetView.alpha).isEqualTo(1)
+ verifyDropTargetPosition(bubbleRightDragZone.dropTarget)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ bubbleLeftDragZone.bounds.centerX(),
+ bubbleLeftDragZone.bounds.centerY()
+ )
+ animatorTestRule.advanceTimeBy(250)
+ }
+
+ assertThat(dropTargetView.alpha).isEqualTo(1)
+ verifyDropTargetPosition(bubbleLeftDragZone.dropTarget)
+ }
+
+ private fun verifyDropTargetPosition(rect: Rect) {
+ assertThat(dropTargetView.scaleX).isEqualTo(rect.width())
+ assertThat(dropTargetView.scaleY).isEqualTo(rect.height())
+ assertThat(dropTargetView.translationX).isEqualTo(rect.exactCenterX())
+ assertThat(dropTargetView.translationY).isEqualTo(rect.exactCenterY())
+ }
+
private class FakeDragZoneChangedListener : DropTargetManager.DragZoneChangedListener {
var initialDragZone: DragZone? = null
var fromDragZone: DragZone? = null
@@ -183,6 +334,7 @@ class DropTargetManagerTest {
override fun onInitialDragZoneSet(dragZone: DragZone) {
initialDragZone = dragZone
}
+
override fun onDragZoneChanged(from: DragZone, to: DragZone) {
fromDragZone = from
toDragZone = to
diff --git a/location/Android.bp b/location/Android.bp
index bc02d1f852de..80556a2376bf 100644
--- a/location/Android.bp
+++ b/location/Android.bp
@@ -42,6 +42,7 @@ java_sdk_library {
"FlaggedApi",
],
},
+ jarjar_prefix: "com.android.internal.hidden_from_bootclasspath",
}
platform_compat_config {
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index a3b06e8c71fc..1af3bc898306 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -23,6 +23,7 @@ import android.app.backup.BackupAnnotations;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupManagerMonitor;
+import android.app.backup.BackupRestoreEventLogger;
import android.app.backup.BackupRestoreEventLogger.DataTypeResult;
import android.app.backup.BackupTransport;
import android.app.backup.RestoreDescription;
@@ -52,7 +53,6 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -924,21 +924,9 @@ public class LocalTransport extends BackupTransport {
BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS,
DataTypeResult.class);
for (DataTypeResult result : results) {
- Log.i(TAG, "\tdataType: " + result.getDataType());
- Log.i(TAG, "\tsuccessCount: " + result.getSuccessCount());
- Log.i(TAG, "\tfailCount: " + result.getFailCount());
- Log.i(TAG, "\tmetadataHash: " + Arrays.toString(result.getMetadataHash()));
-
- if (!result.getErrors().isEmpty()) {
- Log.i(TAG, "\terrors {");
- for (String error : result.getErrors().keySet()) {
- Log.i(TAG, "\t\t" + error + ": " + result.getErrors().get(error));
- }
- Log.i(TAG, "\t}");
- }
-
- Log.i(TAG, "}");
+ Log.i(TAG, "\t" + BackupRestoreEventLogger.toString(result));
}
+ Log.i(TAG, "}");
}
}
}
diff --git a/packages/SettingsLib/res/drawable/ic_1x_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_1x_mobiledata_updated.xml
new file mode 100644
index 000000000000..bd2fad2fedc0
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_1x_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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="17dp"
+ android:height="12.88dp"
+ android:viewportWidth="13.53"
+ android:viewportHeight="10.25">
+ <path
+ android:pathData="M3.738,10.252C3.468,10.252 3.234,10.154 3.038,9.958C2.847,9.757 2.751,9.522 2.751,9.251L2.751,2.587L1.372,3.497C1.167,3.628 0.943,3.672 0.7,3.63C0.462,3.588 0.276,3.467 0.14,3.266C0.01,3.065 -0.032,2.844 0.014,2.601C0.066,2.358 0.192,2.172 0.392,2.041L3.185,0.2C3.265,0.149 3.344,0.104 3.423,0.067C3.507,0.025 3.619,0.004 3.759,0.004C4.03,0.004 4.259,0.102 4.445,0.298C4.637,0.494 4.732,0.734 4.732,1.019L4.732,9.251C4.732,9.522 4.634,9.757 4.438,9.958C4.242,10.154 4.009,10.252 3.738,10.252ZM12.582,10.245C12.391,10.245 12.218,10.194 12.064,10.091C11.915,9.984 11.796,9.848 11.707,9.685L9.803,6.038L9.593,5.961L7.332,1.411C7.136,1.084 7.127,0.769 7.304,0.466C7.482,0.163 7.755,0.011 8.123,0.011C8.301,0.011 8.466,0.065 8.62,0.172C8.779,0.279 8.903,0.415 8.991,0.578L10.783,4.015L11.014,4.05L13.373,8.796C13.569,9.132 13.581,9.459 13.408,9.776C13.236,10.089 12.96,10.245 12.582,10.245ZM7.92,10.238C7.57,10.238 7.309,10.089 7.136,9.79C6.968,9.491 6.978,9.186 7.164,8.873L9.621,4.008L9.817,4.008L11.63,0.557C11.719,0.398 11.836,0.27 11.98,0.172C12.125,0.069 12.288,0.018 12.47,0.018C12.816,0.018 13.075,0.163 13.247,0.452C13.42,0.741 13.411,1.047 13.219,1.369L10.909,5.982L10.762,5.989L8.781,9.713C8.697,9.867 8.578,9.993 8.424,10.091C8.27,10.189 8.102,10.238 7.92,10.238Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_3g_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_3g_mobiledata_updated.xml
new file mode 100644
index 000000000000..8e632e69a56e
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_3g_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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="17dp"
+ android:height="12.21dp"
+ android:viewportWidth="14.51"
+ android:viewportHeight="10.42">
+ <path
+ android:pathData="M2.827,10.416C2.225,10.416 1.726,10.311 1.329,10.101C0.937,9.891 0.629,9.606 0.405,9.247C0.181,8.888 0.051,8.58 0.013,8.323C-0.019,8.066 0.023,7.849 0.139,7.672C0.256,7.49 0.415,7.371 0.615,7.315C0.816,7.254 1.003,7.259 1.175,7.329C1.353,7.394 1.481,7.495 1.56,7.63C1.644,7.765 1.733,7.922 1.826,8.099C1.92,8.272 2.041,8.416 2.19,8.533C2.34,8.65 2.533,8.708 2.771,8.708C3.089,8.708 3.343,8.615 3.534,8.428C3.726,8.237 3.821,7.959 3.821,7.595L3.821,6.888C3.821,6.529 3.726,6.256 3.534,6.069C3.348,5.882 3.077,5.789 2.722,5.789L2.456,5.789C2.251,5.789 2.071,5.714 1.917,5.565C1.768,5.416 1.693,5.236 1.693,5.026C1.693,4.816 1.768,4.636 1.917,4.487C2.067,4.338 2.244,4.263 2.449,4.263L2.666,4.263C2.984,4.263 3.222,4.177 3.38,4.004C3.544,3.831 3.625,3.558 3.625,3.185L3.625,2.618C3.625,2.315 3.544,2.084 3.38,1.925C3.217,1.766 2.998,1.687 2.722,1.687C2.531,1.687 2.37,1.729 2.239,1.813C2.109,1.892 1.999,2.004 1.91,2.149C1.822,2.294 1.738,2.427 1.658,2.548C1.579,2.665 1.453,2.756 1.28,2.821C1.108,2.882 0.926,2.882 0.734,2.821C0.543,2.756 0.391,2.632 0.279,2.45C0.172,2.268 0.142,2.049 0.188,1.792C0.24,1.531 0.384,1.248 0.622,0.945C0.86,0.642 1.159,0.408 1.518,0.245C1.882,0.082 2.326,0 2.848,0C3.67,0 4.323,0.215 4.808,0.644C5.294,1.069 5.536,1.636 5.536,2.345L5.536,2.8C5.536,3.332 5.417,3.768 5.179,4.109C4.941,4.445 4.598,4.69 4.15,4.844L4.15,4.9C4.678,5.017 5.086,5.259 5.375,5.628C5.669,5.992 5.816,6.484 5.816,7.105L5.816,7.679C5.816,8.514 5.55,9.179 5.018,9.674C4.491,10.169 3.761,10.416 2.827,10.416ZM10.943,10.416C9.819,10.411 8.92,10.031 8.248,9.275C7.581,8.514 7.247,7.406 7.247,5.95L7.247,4.417C7.247,2.975 7.588,1.878 8.269,1.127C8.951,0.371 9.863,-0.005 11.006,0C11.52,0 11.954,0.075 12.308,0.224C12.668,0.369 12.973,0.576 13.225,0.847C13.482,1.113 13.659,1.374 13.757,1.631C13.855,1.883 13.862,2.121 13.778,2.345C13.694,2.569 13.55,2.732 13.344,2.835C13.144,2.938 12.948,2.968 12.756,2.926C12.565,2.884 12.416,2.802 12.308,2.681C12.201,2.555 12.091,2.422 11.979,2.282C11.867,2.142 11.727,2.032 11.559,1.953C11.391,1.869 11.191,1.827 10.957,1.827C10.439,1.822 10.024,2.011 9.711,2.394C9.403,2.777 9.249,3.358 9.249,4.137L9.249,6.293C9.249,7.063 9.408,7.644 9.725,8.036C10.047,8.428 10.467,8.624 10.985,8.624C11.489,8.624 11.884,8.477 12.168,8.183C12.453,7.889 12.607,7.474 12.63,6.937L12.63,6.265L11.657,6.265C11.452,6.265 11.275,6.188 11.125,6.034C10.976,5.875 10.901,5.689 10.901,5.474C10.901,5.255 10.978,5.068 11.132,4.914C11.291,4.755 11.48,4.676 11.699,4.676L13.666,4.676C13.9,4.676 14.098,4.755 14.261,4.914C14.425,5.073 14.509,5.269 14.513,5.502L14.513,6.538C14.513,7.77 14.191,8.724 13.547,9.401C12.908,10.078 12.04,10.416 10.943,10.416Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_4g_lte_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_4g_lte_mobiledata_updated.xml
new file mode 100644
index 000000000000..bba359e8b238
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_4g_lte_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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="34dp"
+ android:height="14.07dp"
+ android:viewportWidth="27.29"
+ android:viewportHeight="11.29">
+ <path
+ android:pathData="M4.552,11.195C4.286,11.195 4.058,11.099 3.866,10.908C3.68,10.717 3.586,10.488 3.586,10.222L3.586,8.171L3.74,7.891L3.74,2.823L4.72,3.53L3.712,3.53L1.808,7.366L4.37,7.366L4.797,7.275L5.777,7.275C6.015,7.275 6.218,7.359 6.386,7.527C6.554,7.695 6.638,7.898 6.638,8.136C6.638,8.369 6.554,8.57 6.386,8.738C6.218,8.906 6.015,8.99 5.777,8.99L1.192,8.99C0.856,8.99 0.572,8.88 0.338,8.661C0.11,8.442 -0.005,8.169 -0.005,7.842C-0.005,7.683 0.016,7.569 0.058,7.499C0.1,7.424 0.142,7.35 0.184,7.275L3.124,1.633C3.222,1.446 3.374,1.283 3.579,1.143C3.789,1.003 4.013,0.933 4.251,0.933C4.606,0.933 4.905,1.061 5.147,1.318C5.39,1.57 5.511,1.876 5.511,2.235L5.511,10.222C5.511,10.488 5.416,10.717 5.224,10.908C5.038,11.099 4.814,11.195 4.552,11.195ZM11.303,11.286C10.179,11.281 9.28,10.901 8.608,10.145C7.941,9.384 7.607,8.276 7.607,6.82L7.607,5.287C7.607,3.845 7.948,2.748 8.629,1.997C9.311,1.241 10.223,0.865 11.366,0.87C11.88,0.87 12.314,0.945 12.668,1.094C13.028,1.239 13.333,1.446 13.585,1.717C13.842,1.983 14.019,2.244 14.117,2.501C14.215,2.753 14.222,2.991 14.138,3.215C14.054,3.439 13.91,3.602 13.704,3.705C13.504,3.808 13.308,3.838 13.116,3.796C12.925,3.754 12.776,3.672 12.668,3.551C12.561,3.425 12.451,3.292 12.339,3.152C12.227,3.012 12.087,2.902 11.919,2.823C11.751,2.739 11.551,2.697 11.317,2.697C10.799,2.692 10.384,2.881 10.071,3.264C9.763,3.647 9.609,4.228 9.609,5.007L9.609,7.163C9.609,7.933 9.768,8.514 10.085,8.906C10.407,9.298 10.827,9.494 11.345,9.494C11.849,9.494 12.244,9.347 12.528,9.053C12.813,8.759 12.967,8.344 12.99,7.807L12.99,7.135L12.017,7.135C11.812,7.135 11.635,7.058 11.485,6.904C11.336,6.745 11.261,6.559 11.261,6.344C11.261,6.125 11.338,5.938 11.492,5.784C11.651,5.625 11.84,5.546 12.059,5.546L14.026,5.546C14.26,5.546 14.458,5.625 14.621,5.784C14.785,5.943 14.869,6.139 14.873,6.372L14.873,7.408C14.873,8.64 14.551,9.594 13.907,10.271C13.268,10.948 12.4,11.286 11.303,11.286ZM16.641,6.09C16.434,6.09 16.256,6.016 16.108,5.867C15.962,5.719 15.89,5.543 15.89,5.338L15.89,0.689C15.89,0.501 15.957,0.34 16.091,0.206C16.226,0.069 16.385,0 16.57,0C16.758,0 16.919,0.069 17.053,0.206C17.187,0.34 17.255,0.501 17.255,0.689L17.255,4.83L18.54,4.83C18.713,4.83 18.863,4.892 18.989,5.015C19.115,5.138 19.178,5.286 19.178,5.46C19.178,5.631 19.115,5.779 18.989,5.905C18.863,6.028 18.713,6.09 18.54,6.09L16.641,6.09ZM20.979,6.166C20.792,6.166 20.63,6.098 20.496,5.964C20.365,5.827 20.299,5.664 20.299,5.477L20.299,0.731L21.664,0.731L21.664,5.477C21.664,5.664 21.597,5.827 21.462,5.964C21.328,6.098 21.167,6.166 20.979,6.166ZM19.648,1.331C19.474,1.331 19.324,1.27 19.198,1.147C19.075,1.023 19.014,0.876 19.014,0.706C19.014,0.532 19.075,0.384 19.198,0.26C19.324,0.137 19.474,0.076 19.648,0.076L22.306,0.076C22.48,0.076 22.628,0.137 22.751,0.26C22.877,0.384 22.941,0.532 22.941,0.706C22.941,0.876 22.877,1.023 22.751,1.147C22.628,1.27 22.48,1.331 22.306,1.331L19.648,1.331ZM24.553,6.09C24.346,6.09 24.168,6.016 24.019,5.867C23.874,5.719 23.801,5.543 23.801,5.338L23.801,0.823C23.801,0.619 23.874,0.444 24.019,0.298C24.168,0.15 24.346,0.076 24.553,0.076L26.59,0.076C26.763,0.076 26.912,0.137 27.035,0.26C27.161,0.384 27.224,0.531 27.224,0.701C27.224,0.872 27.161,1.019 27.035,1.142C26.912,1.266 26.763,1.327 26.59,1.327L25.158,1.327L25.158,4.838L26.657,4.838C26.831,4.838 26.979,4.9 27.102,5.023C27.225,5.146 27.287,5.293 27.287,5.464C27.287,5.635 27.225,5.782 27.102,5.905C26.979,6.028 26.831,6.09 26.657,6.09L24.553,6.09ZM24.637,3.595L24.637,2.444L26.3,2.444C26.46,2.444 26.595,2.5 26.707,2.612C26.822,2.724 26.88,2.86 26.88,3.02C26.88,3.177 26.822,3.312 26.707,3.427C26.595,3.539 26.46,3.595 26.3,3.595L24.637,3.595Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_4g_lte_plus_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_4g_lte_plus_mobiledata_updated.xml
new file mode 100644
index 000000000000..cb6fd50a07ea
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_4g_lte_plus_mobiledata_updated.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2025 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="34dp"
+ android:height="11.93dp"
+ android:viewportWidth="32.18"
+ android:viewportHeight="11.29">
+ <path
+ android:pathData="M4.552,11.195C4.286,11.195 4.058,11.099 3.866,10.908C3.68,10.717 3.586,10.488 3.586,10.222L3.586,8.171L3.74,7.891L3.74,2.823L4.72,3.53L3.712,3.53L1.808,7.366L4.37,7.366L4.797,7.275L5.777,7.275C6.015,7.275 6.218,7.359 6.386,7.527C6.554,7.695 6.638,7.898 6.638,8.136C6.638,8.369 6.554,8.57 6.386,8.738C6.218,8.906 6.015,8.99 5.777,8.99L1.192,8.99C0.856,8.99 0.572,8.88 0.338,8.661C0.11,8.442 -0.005,8.169 -0.005,7.842C-0.005,7.683 0.016,7.569 0.058,7.499C0.1,7.424 0.142,7.35 0.184,7.275L3.124,1.633C3.222,1.446 3.374,1.283 3.579,1.143C3.789,1.003 4.013,0.933 4.251,0.933C4.606,0.933 4.905,1.061 5.147,1.318C5.39,1.57 5.511,1.876 5.511,2.235L5.511,10.222C5.511,10.488 5.416,10.717 5.224,10.908C5.038,11.099 4.814,11.195 4.552,11.195ZM11.303,11.286C10.179,11.281 9.28,10.901 8.608,10.145C7.941,9.384 7.607,8.276 7.607,6.82L7.607,5.287C7.607,3.845 7.948,2.748 8.629,1.997C9.311,1.241 10.223,0.865 11.366,0.87C11.88,0.87 12.314,0.945 12.668,1.094C13.028,1.239 13.333,1.446 13.585,1.717C13.842,1.983 14.019,2.244 14.117,2.501C14.215,2.753 14.222,2.991 14.138,3.215C14.054,3.439 13.91,3.602 13.704,3.705C13.504,3.808 13.308,3.838 13.116,3.796C12.925,3.754 12.776,3.672 12.668,3.551C12.561,3.425 12.451,3.292 12.339,3.152C12.227,3.012 12.087,2.902 11.919,2.823C11.751,2.739 11.551,2.697 11.317,2.697C10.799,2.692 10.384,2.881 10.071,3.264C9.763,3.647 9.609,4.228 9.609,5.007L9.609,7.163C9.609,7.933 9.768,8.514 10.085,8.906C10.407,9.298 10.827,9.494 11.345,9.494C11.849,9.494 12.244,9.347 12.528,9.053C12.813,8.759 12.967,8.344 12.99,7.807L12.99,7.135L12.017,7.135C11.812,7.135 11.635,7.058 11.485,6.904C11.336,6.745 11.261,6.559 11.261,6.344C11.261,6.125 11.338,5.938 11.492,5.784C11.651,5.625 11.84,5.546 12.059,5.546L14.026,5.546C14.26,5.546 14.458,5.625 14.621,5.784C14.785,5.943 14.869,6.139 14.873,6.372L14.873,7.408C14.873,8.64 14.551,9.594 13.907,10.271C13.268,10.948 12.4,11.286 11.303,11.286ZM16.641,6.09C16.434,6.09 16.256,6.016 16.108,5.867C15.962,5.719 15.89,5.543 15.89,5.338L15.89,0.689C15.89,0.501 15.957,0.34 16.091,0.206C16.226,0.069 16.385,0 16.57,0C16.758,0 16.919,0.069 17.053,0.206C17.187,0.34 17.255,0.501 17.255,0.689L17.255,4.83L18.54,4.83C18.713,4.83 18.863,4.892 18.989,5.015C19.115,5.138 19.178,5.286 19.178,5.46C19.178,5.631 19.115,5.779 18.989,5.905C18.863,6.028 18.713,6.09 18.54,6.09L16.641,6.09ZM20.979,6.166C20.792,6.166 20.63,6.098 20.496,5.964C20.365,5.827 20.299,5.664 20.299,5.477L20.299,0.731L21.664,0.731L21.664,5.477C21.664,5.664 21.597,5.827 21.462,5.964C21.328,6.098 21.167,6.166 20.979,6.166ZM19.648,1.331C19.474,1.331 19.324,1.27 19.198,1.147C19.075,1.023 19.014,0.876 19.014,0.706C19.014,0.532 19.075,0.384 19.198,0.26C19.324,0.137 19.474,0.076 19.648,0.076L22.306,0.076C22.48,0.076 22.628,0.137 22.751,0.26C22.877,0.384 22.941,0.532 22.941,0.706C22.941,0.876 22.877,1.023 22.751,1.147C22.628,1.27 22.48,1.331 22.306,1.331L19.648,1.331ZM24.553,6.09C24.346,6.09 24.168,6.016 24.019,5.867C23.874,5.719 23.801,5.543 23.801,5.338L23.801,0.823C23.801,0.619 23.874,0.444 24.019,0.298C24.168,0.15 24.346,0.076 24.553,0.076L26.59,0.076C26.763,0.076 26.912,0.137 27.035,0.26C27.161,0.384 27.224,0.531 27.224,0.701C27.224,0.872 27.161,1.019 27.035,1.142C26.912,1.266 26.763,1.327 26.59,1.327L25.158,1.327L25.158,4.838L26.657,4.838C26.831,4.838 26.979,4.9 27.102,5.023C27.225,5.146 27.287,5.293 27.287,5.464C27.287,5.635 27.225,5.782 27.102,5.905C26.979,6.028 26.831,6.09 26.657,6.09L24.553,6.09ZM24.637,3.595L24.637,2.444L26.3,2.444C26.46,2.444 26.595,2.5 26.707,2.612C26.822,2.724 26.88,2.86 26.88,3.02C26.88,3.177 26.822,3.312 26.707,3.427C26.595,3.539 26.46,3.595 26.3,3.595L24.637,3.595Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M30.101,5.346C29.923,5.346 29.768,5.282 29.637,5.154C29.509,5.023 29.445,4.867 29.445,4.686L29.445,1.742C29.445,1.561 29.509,1.406 29.637,1.278C29.768,1.147 29.923,1.082 30.101,1.082C30.28,1.082 30.433,1.147 30.561,1.278C30.689,1.406 30.753,1.561 30.753,1.742L30.753,4.686C30.753,4.867 30.689,5.023 30.561,5.154C30.433,5.282 30.28,5.346 30.101,5.346ZM28.677,3.858C28.499,3.858 28.345,3.795 28.217,3.67C28.089,3.542 28.025,3.39 28.025,3.214C28.025,3.038 28.089,2.887 28.217,2.762C28.345,2.634 28.499,2.57 28.677,2.57L31.525,2.57C31.704,2.57 31.857,2.634 31.985,2.762C32.113,2.887 32.177,3.038 32.177,3.214C32.177,3.39 32.113,3.542 31.985,3.67C31.857,3.795 31.704,3.858 31.525,3.858L28.677,3.858Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_4g_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_4g_mobiledata_updated.xml
new file mode 100644
index 000000000000..562bcaf2fdba
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_4g_mobiledata_updated.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2025 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="19dp"
+ android:height="13.31dp"
+ android:viewportWidth="14.88"
+ android:viewportHeight="10.42">
+ <path
+ android:pathData="M4.552,10.325C4.286,10.325 4.058,10.229 3.866,10.038C3.68,9.847 3.586,9.618 3.586,9.352L3.586,7.301L3.74,7.021L3.74,1.953L4.72,2.66L3.712,2.66L1.808,6.496L4.37,6.496L4.797,6.405L5.777,6.405C6.015,6.405 6.218,6.489 6.386,6.657C6.554,6.825 6.638,7.028 6.638,7.266C6.638,7.499 6.554,7.7 6.386,7.868C6.218,8.036 6.015,8.12 5.777,8.12L1.192,8.12C0.856,8.12 0.572,8.01 0.338,7.791C0.11,7.572 -0.005,7.299 -0.005,6.972C-0.005,6.813 0.016,6.699 0.058,6.629C0.1,6.554 0.142,6.48 0.184,6.405L3.124,0.763C3.222,0.576 3.374,0.413 3.579,0.273C3.789,0.133 4.013,0.063 4.251,0.063C4.606,0.063 4.905,0.191 5.147,0.448C5.39,0.7 5.511,1.006 5.511,1.365L5.511,9.352C5.511,9.618 5.416,9.847 5.224,10.038C5.038,10.229 4.814,10.325 4.552,10.325ZM11.303,10.416C10.179,10.411 9.28,10.031 8.608,9.275C7.941,8.514 7.607,7.406 7.607,5.95L7.607,4.417C7.607,2.975 7.948,1.878 8.629,1.127C9.311,0.371 10.223,-0.005 11.366,0C11.88,0 12.314,0.075 12.668,0.224C13.028,0.369 13.333,0.576 13.585,0.847C13.842,1.113 14.019,1.374 14.117,1.631C14.215,1.883 14.222,2.121 14.138,2.345C14.054,2.569 13.91,2.732 13.704,2.835C13.504,2.938 13.308,2.968 13.116,2.926C12.925,2.884 12.776,2.802 12.668,2.681C12.561,2.555 12.451,2.422 12.339,2.282C12.227,2.142 12.087,2.032 11.919,1.953C11.751,1.869 11.551,1.827 11.317,1.827C10.799,1.822 10.384,2.011 10.071,2.394C9.763,2.777 9.609,3.358 9.609,4.137L9.609,6.293C9.609,7.063 9.768,7.644 10.085,8.036C10.407,8.428 10.827,8.624 11.345,8.624C11.849,8.624 12.244,8.477 12.528,8.183C12.813,7.889 12.967,7.474 12.99,6.937L12.99,6.265L12.017,6.265C11.812,6.265 11.635,6.188 11.485,6.034C11.336,5.875 11.261,5.689 11.261,5.474C11.261,5.255 11.338,5.068 11.492,4.914C11.651,4.755 11.84,4.676 12.059,4.676L14.026,4.676C14.26,4.676 14.458,4.755 14.621,4.914C14.785,5.073 14.869,5.269 14.873,5.502L14.873,6.538C14.873,7.77 14.551,8.724 13.907,9.401C13.268,10.078 12.4,10.416 11.303,10.416Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_4g_plus_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_4g_plus_mobiledata_updated.xml
new file mode 100644
index 000000000000..73e8994681c2
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_4g_plus_mobiledata_updated.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2025 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="23dp"
+ android:height="12.5dp"
+ android:viewportWidth="19.17"
+ android:viewportHeight="10.42">
+ <path
+ android:pathData="M4.552,10.325C4.286,10.325 4.058,10.229 3.866,10.038C3.68,9.847 3.586,9.618 3.586,9.352L3.586,7.301L3.74,7.021L3.74,1.953L4.72,2.66L3.712,2.66L1.808,6.496L4.37,6.496L4.797,6.405L5.777,6.405C6.015,6.405 6.218,6.489 6.386,6.657C6.554,6.825 6.638,7.028 6.638,7.266C6.638,7.499 6.554,7.7 6.386,7.868C6.218,8.036 6.015,8.12 5.777,8.12L1.192,8.12C0.856,8.12 0.572,8.01 0.338,7.791C0.11,7.572 -0.005,7.299 -0.005,6.972C-0.005,6.813 0.016,6.699 0.058,6.629C0.1,6.554 0.142,6.48 0.184,6.405L3.124,0.763C3.222,0.576 3.374,0.413 3.579,0.273C3.789,0.133 4.013,0.063 4.251,0.063C4.606,0.063 4.905,0.191 5.147,0.448C5.39,0.7 5.511,1.006 5.511,1.365L5.511,9.352C5.511,9.618 5.416,9.847 5.224,10.038C5.038,10.229 4.814,10.325 4.552,10.325ZM11.303,10.416C10.179,10.411 9.28,10.031 8.608,9.275C7.941,8.514 7.607,7.406 7.607,5.95L7.607,4.417C7.607,2.975 7.948,1.878 8.629,1.127C9.311,0.371 10.223,-0.005 11.366,0C11.88,0 12.314,0.075 12.668,0.224C13.028,0.369 13.333,0.576 13.585,0.847C13.842,1.113 14.019,1.374 14.117,1.631C14.215,1.883 14.222,2.121 14.138,2.345C14.054,2.569 13.91,2.732 13.704,2.835C13.504,2.938 13.308,2.968 13.116,2.926C12.925,2.884 12.776,2.802 12.668,2.681C12.561,2.555 12.451,2.422 12.339,2.282C12.227,2.142 12.087,2.032 11.919,1.953C11.751,1.869 11.551,1.827 11.317,1.827C10.799,1.822 10.384,2.011 10.071,2.394C9.763,2.777 9.609,3.358 9.609,4.137L9.609,6.293C9.609,7.063 9.768,7.644 10.085,8.036C10.407,8.428 10.827,8.624 11.345,8.624C11.849,8.624 12.244,8.477 12.528,8.183C12.813,7.889 12.967,7.474 12.99,6.937L12.99,6.265L12.017,6.265C11.812,6.265 11.635,6.188 11.485,6.034C11.336,5.875 11.261,5.689 11.261,5.474C11.261,5.255 11.338,5.068 11.492,4.914C11.651,4.755 11.84,4.676 12.059,4.676L14.026,4.676C14.26,4.676 14.458,4.755 14.621,4.914C14.785,5.073 14.869,5.269 14.873,5.502L14.873,6.538C14.873,7.77 14.551,8.724 13.907,9.401C13.268,10.078 12.4,10.416 11.303,10.416Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M17.086,4.476C16.907,4.476 16.752,4.412 16.622,4.284C16.494,4.153 16.43,3.997 16.43,3.816L16.43,0.872C16.43,0.691 16.494,0.536 16.622,0.408C16.752,0.277 16.907,0.212 17.086,0.212C17.264,0.212 17.418,0.277 17.546,0.408C17.674,0.536 17.738,0.691 17.738,0.872L17.738,3.816C17.738,3.997 17.674,4.153 17.546,4.284C17.418,4.412 17.264,4.476 17.086,4.476ZM15.662,2.988C15.483,2.988 15.33,2.925 15.202,2.8C15.074,2.672 15.01,2.52 15.01,2.344C15.01,2.168 15.074,2.017 15.202,1.892C15.33,1.764 15.483,1.7 15.662,1.7L18.51,1.7C18.688,1.7 18.842,1.764 18.97,1.892C19.098,2.017 19.162,2.168 19.162,2.344C19.162,2.52 19.098,2.672 18.97,2.8C18.842,2.925 18.688,2.988 18.51,2.988L15.662,2.988Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_5g_e_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_5g_e_mobiledata_updated.xml
new file mode 100644
index 000000000000..c46da66a9183
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_5g_e_mobiledata_updated.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2025 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="22.0dp"
+ android:height="12.57dp"
+ android:viewportHeight="11.21"
+ android:viewportWidth="19.62">
+
+ <path
+ android:fillColor="#000"
+ android:pathData="M2.573,11.206C1.99,11.206 1.502,11.094 1.11,10.87C0.718,10.641 0.436,10.364 0.263,10.037C0.091,9.706 0.002,9.4 -0.003,9.12C-0.007,8.84 0.058,8.616 0.193,8.448C0.333,8.275 0.499,8.168 0.69,8.126C0.882,8.079 1.057,8.089 1.215,8.154C1.379,8.219 1.502,8.315 1.586,8.441C1.675,8.567 1.75,8.716 1.81,8.889C1.871,9.062 1.971,9.202 2.111,9.309C2.251,9.412 2.429,9.463 2.643,9.463C2.947,9.463 3.203,9.363 3.413,9.162C3.623,8.961 3.763,8.663 3.833,8.266L4.008,7.272C4.074,6.899 4.029,6.609 3.875,6.404C3.726,6.199 3.5,6.096 3.196,6.096C3,6.096 2.825,6.143 2.671,6.236C2.522,6.325 2.401,6.43 2.307,6.551C2.181,6.672 2.03,6.752 1.852,6.789C1.675,6.826 1.488,6.81 1.292,6.74C1.045,6.651 0.865,6.497 0.753,6.278C0.641,6.054 0.62,5.804 0.69,5.529L1.593,1.98C1.677,1.672 1.831,1.429 2.055,1.252C2.284,1.075 2.557,0.986 2.874,0.986L5.674,0.986C5.964,0.986 6.195,1.089 6.367,1.294C6.54,1.495 6.601,1.733 6.549,2.008C6.517,2.213 6.412,2.388 6.234,2.533C6.062,2.673 5.875,2.743 5.674,2.743L3.056,2.743L2.433,5.13L2.475,5.137C2.676,4.955 2.905,4.815 3.161,4.717C3.418,4.614 3.7,4.563 4.008,4.563C4.727,4.563 5.268,4.836 5.632,5.382C6.001,5.923 6.111,6.628 5.961,7.496L5.814,8.336C5.656,9.274 5.299,9.988 4.743,10.478C4.188,10.963 3.465,11.206 2.573,11.206ZM10.577,11.206C9.392,11.206 8.515,10.795 7.945,9.974C7.381,9.153 7.229,8.009 7.49,6.544L7.749,5.039C8.006,3.606 8.498,2.54 9.226,1.84C9.959,1.14 10.883,0.79 11.998,0.79C12.535,0.79 12.995,0.879 13.377,1.056C13.76,1.229 14.059,1.46 14.273,1.749C14.488,2.038 14.612,2.314 14.644,2.575C14.677,2.832 14.644,3.053 14.546,3.24C14.453,3.427 14.313,3.567 14.126,3.66C13.94,3.749 13.753,3.774 13.566,3.737C13.384,3.695 13.244,3.606 13.146,3.471C13.048,3.336 12.941,3.2 12.824,3.065C12.708,2.925 12.57,2.815 12.411,2.736C12.257,2.657 12.068,2.617 11.844,2.617C11.35,2.617 10.918,2.808 10.549,3.191C10.185,3.569 9.936,4.141 9.8,4.906L9.422,7.048C9.287,7.813 9.348,8.399 9.604,8.805C9.861,9.211 10.248,9.414 10.766,9.414C11.256,9.414 11.665,9.267 11.991,8.973C12.318,8.679 12.54,8.264 12.656,7.727L12.775,7.055L11.893,7.055C11.665,7.055 11.48,6.964 11.34,6.782C11.205,6.6 11.158,6.385 11.2,6.138C11.233,5.951 11.326,5.795 11.48,5.669C11.639,5.538 11.809,5.473 11.991,5.473L13.979,5.473C14.25,5.473 14.462,5.566 14.616,5.753C14.775,5.94 14.831,6.168 14.784,6.439L14.595,7.489C14.376,8.702 13.916,9.626 13.216,10.261C12.521,10.891 11.641,11.206 10.577,11.206ZM16.001,6.01C15.799,6.01 15.637,5.937 15.514,5.792C15.39,5.643 15.346,5.47 15.379,5.271L16.181,0.735C16.218,0.53 16.321,0.357 16.492,0.214C16.666,0.068 16.856,-0.004 17.063,-0.004L18.983,-0.004C19.187,-0.004 19.351,0.068 19.474,0.214C19.597,0.36 19.642,0.529 19.609,0.722C19.581,0.868 19.505,0.992 19.382,1.096C19.259,1.197 19.126,1.247 18.983,1.247L17.462,1.247L16.841,4.758L18.21,4.758C18.414,4.758 18.577,4.831 18.697,4.977C18.82,5.122 18.865,5.292 18.832,5.485C18.806,5.631 18.732,5.755 18.609,5.859C18.486,5.96 18.353,6.01 18.21,6.01L16.001,6.01ZM16.526,3.515L16.732,2.364L18.281,2.364C18.472,2.364 18.623,2.432 18.735,2.566C18.847,2.698 18.888,2.853 18.857,3.032C18.832,3.167 18.762,3.281 18.647,3.377C18.535,3.469 18.413,3.515 18.281,3.515L16.526,3.515Z" />
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_5g_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_5g_mobiledata_updated.xml
new file mode 100644
index 000000000000..66787b0a7594
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_5g_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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="17dp"
+ android:height="12.28dp"
+ android:viewportWidth="14.42"
+ android:viewportHeight="10.42">
+ <path
+ android:pathData="M2.807,10.416C2.247,10.416 1.774,10.325 1.386,10.143C0.999,9.956 0.684,9.704 0.441,9.387C0.199,9.065 0.056,8.745 0.014,8.428C-0.028,8.111 0.014,7.859 0.14,7.672C0.271,7.485 0.439,7.366 0.644,7.315C0.85,7.259 1.036,7.266 1.204,7.336C1.372,7.406 1.494,7.506 1.568,7.637C1.643,7.763 1.727,7.912 1.82,8.085C1.914,8.253 2.03,8.393 2.17,8.505C2.315,8.617 2.504,8.673 2.737,8.673C3.055,8.673 3.309,8.57 3.5,8.365C3.696,8.16 3.794,7.849 3.794,7.434L3.794,6.461C3.794,6.083 3.701,5.796 3.514,5.6C3.332,5.399 3.092,5.299 2.793,5.299C2.593,5.299 2.427,5.341 2.296,5.425C2.166,5.509 2.054,5.605 1.96,5.712C1.858,5.819 1.715,5.901 1.533,5.957C1.351,6.008 1.148,6.001 0.924,5.936C0.682,5.861 0.49,5.714 0.35,5.495C0.215,5.271 0.159,5.035 0.182,4.788L0.455,1.281C0.483,0.987 0.614,0.733 0.847,0.518C1.081,0.303 1.347,0.196 1.645,0.196L4.515,0.196C4.758,0.196 4.966,0.282 5.138,0.455C5.316,0.628 5.404,0.833 5.404,1.071C5.404,1.314 5.316,1.521 5.138,1.694C4.966,1.867 4.758,1.953 4.515,1.953L2.044,1.953L1.841,4.34L1.897,4.354C2.07,4.172 2.285,4.03 2.541,3.927C2.803,3.824 3.094,3.773 3.416,3.773C4.126,3.773 4.697,4.02 5.131,4.515C5.565,5.005 5.782,5.677 5.782,6.531L5.782,7.378C5.782,8.33 5.516,9.074 4.984,9.611C4.452,10.148 3.727,10.416 2.807,10.416ZM10.853,10.416C9.729,10.411 8.83,10.031 8.158,9.275C7.491,8.514 7.157,7.406 7.157,5.95L7.157,4.417C7.157,2.975 7.498,1.878 8.179,1.127C8.861,0.371 9.773,-0.005 10.916,0C11.43,0 11.864,0.075 12.218,0.224C12.578,0.369 12.883,0.576 13.135,0.847C13.392,1.113 13.569,1.374 13.667,1.631C13.765,1.883 13.772,2.121 13.688,2.345C13.604,2.569 13.46,2.732 13.254,2.835C13.054,2.938 12.858,2.968 12.666,2.926C12.475,2.884 12.326,2.802 12.218,2.681C12.111,2.555 12.001,2.422 11.889,2.282C11.777,2.142 11.637,2.032 11.469,1.953C11.301,1.869 11.101,1.827 10.867,1.827C10.349,1.822 9.934,2.011 9.621,2.394C9.313,2.777 9.159,3.358 9.159,4.137L9.159,6.293C9.159,7.063 9.318,7.644 9.635,8.036C9.957,8.428 10.377,8.624 10.895,8.624C11.399,8.624 11.794,8.477 12.078,8.183C12.363,7.889 12.517,7.474 12.54,6.937L12.54,6.265L11.567,6.265C11.362,6.265 11.185,6.188 11.035,6.034C10.886,5.875 10.811,5.689 10.811,5.474C10.811,5.255 10.888,5.068 11.042,4.914C11.201,4.755 11.39,4.676 11.609,4.676L13.576,4.676C13.81,4.676 14.008,4.755 14.171,4.914C14.335,5.073 14.419,5.269 14.423,5.502L14.423,6.538C14.423,7.77 14.101,8.724 13.457,9.401C12.818,10.078 11.95,10.416 10.853,10.416Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_default_updated.xml b/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_default_updated.xml
new file mode 100644
index 000000000000..5ba3c98028a2
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_default_updated.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2025 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="22dp"
+ android:height="11.63dp"
+ android:viewportWidth="19.71"
+ android:viewportHeight="10.42">
+ <path
+ android:pathData="M2.807,10.416C2.247,10.416 1.774,10.325 1.386,10.143C0.999,9.956 0.684,9.704 0.441,9.387C0.199,9.065 0.056,8.745 0.014,8.428C-0.028,8.111 0.014,7.859 0.14,7.672C0.271,7.485 0.439,7.366 0.644,7.315C0.85,7.259 1.036,7.266 1.204,7.336C1.372,7.406 1.494,7.506 1.568,7.637C1.643,7.763 1.727,7.912 1.82,8.085C1.914,8.253 2.03,8.393 2.17,8.505C2.315,8.617 2.504,8.673 2.737,8.673C3.055,8.673 3.309,8.57 3.5,8.365C3.696,8.16 3.794,7.849 3.794,7.434L3.794,6.461C3.794,6.083 3.701,5.796 3.514,5.6C3.332,5.399 3.092,5.299 2.793,5.299C2.593,5.299 2.427,5.341 2.296,5.425C2.166,5.509 2.054,5.605 1.96,5.712C1.858,5.819 1.715,5.901 1.533,5.957C1.351,6.008 1.148,6.001 0.924,5.936C0.682,5.861 0.49,5.714 0.35,5.495C0.215,5.271 0.159,5.035 0.182,4.788L0.455,1.281C0.483,0.987 0.614,0.733 0.847,0.518C1.081,0.303 1.347,0.196 1.645,0.196L4.515,0.196C4.758,0.196 4.966,0.282 5.138,0.455C5.316,0.628 5.404,0.833 5.404,1.071C5.404,1.314 5.316,1.521 5.138,1.694C4.966,1.867 4.758,1.953 4.515,1.953L2.044,1.953L1.841,4.34L1.897,4.354C2.07,4.172 2.285,4.03 2.541,3.927C2.803,3.824 3.094,3.773 3.416,3.773C4.126,3.773 4.697,4.02 5.131,4.515C5.565,5.005 5.782,5.677 5.782,6.531L5.782,7.378C5.782,8.33 5.516,9.074 4.984,9.611C4.452,10.148 3.727,10.416 2.807,10.416ZM10.853,10.416C9.729,10.411 8.83,10.031 8.158,9.275C7.491,8.514 7.157,7.406 7.157,5.95L7.157,4.417C7.157,2.975 7.498,1.878 8.179,1.127C8.861,0.371 9.773,-0.005 10.916,0C11.43,0 11.864,0.075 12.218,0.224C12.578,0.369 12.883,0.576 13.135,0.847C13.392,1.113 13.569,1.374 13.667,1.631C13.765,1.883 13.772,2.121 13.688,2.345C13.604,2.569 13.46,2.732 13.254,2.835C13.054,2.938 12.858,2.968 12.666,2.926C12.475,2.884 12.326,2.802 12.218,2.681C12.111,2.555 12.001,2.422 11.889,2.282C11.777,2.142 11.637,2.032 11.469,1.953C11.301,1.869 11.101,1.827 10.867,1.827C10.349,1.822 9.934,2.011 9.621,2.394C9.313,2.777 9.159,3.358 9.159,4.137L9.159,6.293C9.159,7.063 9.318,7.644 9.635,8.036C9.957,8.428 10.377,8.624 10.895,8.624C11.399,8.624 11.794,8.477 12.078,8.183C12.363,7.889 12.517,7.474 12.54,6.937L12.54,6.265L11.567,6.265C11.362,6.265 11.185,6.188 11.035,6.034C10.886,5.875 10.811,5.689 10.811,5.474C10.811,5.255 10.888,5.068 11.042,4.914C11.201,4.755 11.39,4.676 11.609,4.676L13.576,4.676C13.81,4.676 14.008,4.755 14.171,4.914C14.335,5.073 14.419,5.269 14.423,5.502L14.423,6.538C14.423,7.77 14.101,8.724 13.457,9.401C12.818,10.078 11.95,10.416 10.853,10.416Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M17.636,4.476C17.457,4.476 17.302,4.412 17.172,4.284C17.044,4.153 16.98,3.997 16.98,3.816L16.98,0.872C16.98,0.691 17.044,0.536 17.172,0.408C17.302,0.277 17.457,0.212 17.636,0.212C17.814,0.212 17.968,0.277 18.096,0.408C18.224,0.536 18.288,0.691 18.288,0.872L18.288,3.816C18.288,3.997 18.224,4.153 18.096,4.284C17.968,4.412 17.814,4.476 17.636,4.476ZM16.212,2.988C16.033,2.988 15.88,2.925 15.752,2.8C15.624,2.672 15.56,2.52 15.56,2.344C15.56,2.168 15.624,2.017 15.752,1.892C15.88,1.764 16.033,1.7 16.212,1.7L19.06,1.7C19.238,1.7 19.392,1.764 19.52,1.892C19.648,2.017 19.712,2.168 19.712,2.344C19.712,2.52 19.648,2.672 19.52,2.8C19.392,2.925 19.238,2.988 19.06,2.988L16.212,2.988Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_updated.xml
new file mode 100644
index 000000000000..5ba3c98028a2
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_updated.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2025 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="22dp"
+ android:height="11.63dp"
+ android:viewportWidth="19.71"
+ android:viewportHeight="10.42">
+ <path
+ android:pathData="M2.807,10.416C2.247,10.416 1.774,10.325 1.386,10.143C0.999,9.956 0.684,9.704 0.441,9.387C0.199,9.065 0.056,8.745 0.014,8.428C-0.028,8.111 0.014,7.859 0.14,7.672C0.271,7.485 0.439,7.366 0.644,7.315C0.85,7.259 1.036,7.266 1.204,7.336C1.372,7.406 1.494,7.506 1.568,7.637C1.643,7.763 1.727,7.912 1.82,8.085C1.914,8.253 2.03,8.393 2.17,8.505C2.315,8.617 2.504,8.673 2.737,8.673C3.055,8.673 3.309,8.57 3.5,8.365C3.696,8.16 3.794,7.849 3.794,7.434L3.794,6.461C3.794,6.083 3.701,5.796 3.514,5.6C3.332,5.399 3.092,5.299 2.793,5.299C2.593,5.299 2.427,5.341 2.296,5.425C2.166,5.509 2.054,5.605 1.96,5.712C1.858,5.819 1.715,5.901 1.533,5.957C1.351,6.008 1.148,6.001 0.924,5.936C0.682,5.861 0.49,5.714 0.35,5.495C0.215,5.271 0.159,5.035 0.182,4.788L0.455,1.281C0.483,0.987 0.614,0.733 0.847,0.518C1.081,0.303 1.347,0.196 1.645,0.196L4.515,0.196C4.758,0.196 4.966,0.282 5.138,0.455C5.316,0.628 5.404,0.833 5.404,1.071C5.404,1.314 5.316,1.521 5.138,1.694C4.966,1.867 4.758,1.953 4.515,1.953L2.044,1.953L1.841,4.34L1.897,4.354C2.07,4.172 2.285,4.03 2.541,3.927C2.803,3.824 3.094,3.773 3.416,3.773C4.126,3.773 4.697,4.02 5.131,4.515C5.565,5.005 5.782,5.677 5.782,6.531L5.782,7.378C5.782,8.33 5.516,9.074 4.984,9.611C4.452,10.148 3.727,10.416 2.807,10.416ZM10.853,10.416C9.729,10.411 8.83,10.031 8.158,9.275C7.491,8.514 7.157,7.406 7.157,5.95L7.157,4.417C7.157,2.975 7.498,1.878 8.179,1.127C8.861,0.371 9.773,-0.005 10.916,0C11.43,0 11.864,0.075 12.218,0.224C12.578,0.369 12.883,0.576 13.135,0.847C13.392,1.113 13.569,1.374 13.667,1.631C13.765,1.883 13.772,2.121 13.688,2.345C13.604,2.569 13.46,2.732 13.254,2.835C13.054,2.938 12.858,2.968 12.666,2.926C12.475,2.884 12.326,2.802 12.218,2.681C12.111,2.555 12.001,2.422 11.889,2.282C11.777,2.142 11.637,2.032 11.469,1.953C11.301,1.869 11.101,1.827 10.867,1.827C10.349,1.822 9.934,2.011 9.621,2.394C9.313,2.777 9.159,3.358 9.159,4.137L9.159,6.293C9.159,7.063 9.318,7.644 9.635,8.036C9.957,8.428 10.377,8.624 10.895,8.624C11.399,8.624 11.794,8.477 12.078,8.183C12.363,7.889 12.517,7.474 12.54,6.937L12.54,6.265L11.567,6.265C11.362,6.265 11.185,6.188 11.035,6.034C10.886,5.875 10.811,5.689 10.811,5.474C10.811,5.255 10.888,5.068 11.042,4.914C11.201,4.755 11.39,4.676 11.609,4.676L13.576,4.676C13.81,4.676 14.008,4.755 14.171,4.914C14.335,5.073 14.419,5.269 14.423,5.502L14.423,6.538C14.423,7.77 14.101,8.724 13.457,9.401C12.818,10.078 11.95,10.416 10.853,10.416Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M17.636,4.476C17.457,4.476 17.302,4.412 17.172,4.284C17.044,4.153 16.98,3.997 16.98,3.816L16.98,0.872C16.98,0.691 17.044,0.536 17.172,0.408C17.302,0.277 17.457,0.212 17.636,0.212C17.814,0.212 17.968,0.277 18.096,0.408C18.224,0.536 18.288,0.691 18.288,0.872L18.288,3.816C18.288,3.997 18.224,4.153 18.096,4.284C17.968,4.412 17.814,4.476 17.636,4.476ZM16.212,2.988C16.033,2.988 15.88,2.925 15.752,2.8C15.624,2.672 15.56,2.52 15.56,2.344C15.56,2.168 15.624,2.017 15.752,1.892C15.88,1.764 16.033,1.7 16.212,1.7L19.06,1.7C19.238,1.7 19.392,1.764 19.52,1.892C19.648,2.017 19.712,2.168 19.712,2.344C19.712,2.52 19.648,2.672 19.52,2.8C19.392,2.925 19.238,2.988 19.06,2.988L16.212,2.988Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_carrier_wifi_updated.xml b/packages/SettingsLib/res/drawable/ic_carrier_wifi_updated.xml
new file mode 100644
index 000000000000..14db82614ad1
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_carrier_wifi_updated.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2025 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="19.0dp"
+ android:height="12.38dp"
+ android:viewportHeight="10.26"
+ android:viewportWidth="15.75">
+
+ <path
+ android:fillColor="#000"
+ android:pathData="M2.864,10.259C2.598,10.259 2.358,10.168 2.143,9.986C1.929,9.804 1.793,9.589 1.737,9.342L0.036,1.208C-0.043,0.877 0.013,0.594 0.204,0.361C0.4,0.128 0.657,0.011 0.974,0.011C1.208,0.011 1.418,0.093 1.604,0.256C1.791,0.419 1.908,0.611 1.954,0.83L2.885,5.828L3.039,6.92L3.088,6.92L3.249,5.828L4.278,0.851C4.325,0.622 4.446,0.424 4.642,0.256C4.843,0.088 5.065,0.004 5.307,0.004C5.55,0.004 5.769,0.088 5.965,0.256C6.166,0.424 6.292,0.625 6.343,0.858L7.358,5.814L7.526,6.913L7.575,6.913L7.729,5.814L8.653,0.781C8.695,0.571 8.805,0.391 8.982,0.242C9.16,0.093 9.356,0.018 9.57,0.018C9.874,0.018 10.114,0.128 10.291,0.347C10.473,0.566 10.529,0.828 10.459,1.131L8.765,9.342C8.709,9.594 8.574,9.811 8.359,9.993C8.145,10.17 7.902,10.259 7.631,10.259C7.37,10.259 7.132,10.17 6.917,9.993C6.703,9.811 6.57,9.594 6.518,9.342L5.44,4.19L5.279,3.133L5.23,3.133L5.069,4.183L3.977,9.342C3.926,9.589 3.793,9.804 3.578,9.986C3.364,10.168 3.126,10.259 2.864,10.259Z" />
+
+ <path
+ android:fillColor="#000"
+ android:pathData="M13.676,4.396C13.497,4.396 13.342,4.332 13.212,4.204C13.084,4.073 13.02,3.917 13.02,3.736L13.02,0.792C13.02,0.611 13.084,0.456 13.212,0.328C13.342,0.197 13.497,0.132 13.676,0.132C13.854,0.132 14.008,0.197 14.136,0.328C14.264,0.456 14.328,0.611 14.328,0.792L14.328,3.736C14.328,3.917 14.264,4.073 14.136,4.204C14.008,4.332 13.854,4.396 13.676,4.396ZM12.252,2.908C12.073,2.908 11.92,2.845 11.792,2.72C11.664,2.592 11.6,2.44 11.6,2.264C11.6,2.088 11.664,1.937 11.792,1.812C11.92,1.684 12.073,1.62 12.252,1.62L15.1,1.62C15.278,1.62 15.432,1.684 15.56,1.812C15.688,1.937 15.752,2.088 15.752,2.264C15.752,2.44 15.688,2.592 15.56,2.72C15.432,2.845 15.278,2.908 15.1,2.908L12.252,2.908Z" />
+
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_e_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_e_mobiledata_updated.xml
new file mode 100644
index 000000000000..febcd87efbc3
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_e_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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="17dp"
+ android:height="31.08dp"
+ android:viewportWidth="5.48"
+ android:viewportHeight="10.02">
+ <path
+ android:pathData="M1.081,10.02C0.787,10.02 0.533,9.913 0.318,9.698C0.104,9.483 -0.004,9.229 -0.004,8.935L-0.004,1.081C-0.004,0.787 0.104,0.533 0.318,0.318C0.533,0.103 0.787,-0.004 1.081,-0.004L4.455,-0.004C4.707,-0.004 4.922,0.087 5.099,0.269C5.281,0.446 5.372,0.659 5.372,0.906C5.372,1.153 5.281,1.368 5.099,1.55C4.922,1.727 4.707,1.816 4.455,1.816L1.963,1.816L1.963,8.2L4.56,8.2C4.812,8.2 5.027,8.291 5.204,8.473C5.386,8.65 5.477,8.863 5.477,9.11C5.477,9.357 5.386,9.572 5.204,9.754C5.027,9.931 4.812,10.02 4.56,10.02L1.081,10.02ZM1.186,5.736L1.186,4.042L3.951,4.042C4.185,4.042 4.385,4.126 4.553,4.294C4.721,4.457 4.805,4.656 4.805,4.889C4.805,5.118 4.721,5.316 4.553,5.484C4.385,5.652 4.185,5.736 3.951,5.736L1.186,5.736Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_g_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_g_mobiledata_updated.xml
new file mode 100644
index 000000000000..d719f7a05aa0
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_g_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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="17dp"
+ android:height="24.37dp"
+ android:viewportWidth="7.27"
+ android:viewportHeight="10.42">
+ <path
+ android:pathData="M3.696,10.416C2.571,10.411 1.673,10.031 1.001,9.275C0.333,8.514 -0,7.406 -0,5.95L-0,4.417C-0,2.975 0.34,1.878 1.022,1.127C1.703,0.371 2.615,-0.005 3.759,0C4.272,0 4.706,0.075 5.061,0.224C5.42,0.369 5.726,0.576 5.978,0.847C6.235,1.113 6.412,1.374 6.51,1.631C6.608,1.883 6.615,2.121 6.531,2.345C6.447,2.569 6.302,2.732 6.097,2.835C5.896,2.938 5.7,2.968 5.509,2.926C5.317,2.884 5.168,2.802 5.061,2.681C4.953,2.555 4.844,2.422 4.732,2.282C4.62,2.142 4.48,2.032 4.312,1.953C4.144,1.869 3.943,1.827 3.71,1.827C3.192,1.822 2.776,2.011 2.464,2.394C2.156,2.777 2.002,3.358 2.002,4.137L2.002,6.293C2.002,7.063 2.16,7.644 2.478,8.036C2.8,8.428 3.22,8.624 3.738,8.624C4.242,8.624 4.636,8.477 4.921,8.183C5.205,7.889 5.359,7.474 5.383,6.937L5.383,6.265L4.41,6.265C4.204,6.265 4.027,6.188 3.878,6.034C3.728,5.875 3.654,5.689 3.654,5.474C3.654,5.255 3.731,5.068 3.885,4.914C4.043,4.755 4.232,4.676 4.452,4.676L6.419,4.676C6.652,4.676 6.85,4.755 7.014,4.914C7.177,5.073 7.261,5.269 7.266,5.502L7.266,6.538C7.266,7.77 6.944,8.724 6.3,9.401C5.661,10.078 4.792,10.416 3.696,10.416Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_h_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_h_mobiledata_updated.xml
new file mode 100644
index 000000000000..e60ff8cde396
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_h_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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="17dp"
+ android:height="26.68dp"
+ android:viewportWidth="6.53"
+ android:viewportHeight="10.25">
+ <path
+ android:pathData="M5.547,10.252C5.277,10.252 5.043,10.154 4.847,9.958C4.656,9.757 4.56,9.522 4.56,9.251L4.56,1.005C4.56,0.73 4.656,0.494 4.847,0.298C5.043,0.102 5.277,0.004 5.547,0.004C5.818,0.004 6.049,0.102 6.24,0.298C6.436,0.494 6.534,0.73 6.534,1.005L6.534,9.251C6.534,9.522 6.436,9.757 6.24,9.958C6.049,10.154 5.818,10.252 5.547,10.252ZM0.99,10.252C0.72,10.252 0.486,10.154 0.29,9.958C0.099,9.757 0.003,9.522 0.003,9.251L0.003,1.005C0.003,0.73 0.099,0.494 0.29,0.298C0.486,0.102 0.72,0.004 0.99,0.004C1.261,0.004 1.492,0.102 1.683,0.298C1.879,0.494 1.977,0.73 1.977,1.005L1.977,9.251C1.977,9.522 1.879,9.757 1.683,9.958C1.492,10.154 1.261,10.252 0.99,10.252ZM1.151,5.933L1.151,4.106L5.484,4.106L5.484,5.933L1.151,5.933Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_h_plus_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_h_plus_mobiledata_updated.xml
new file mode 100644
index 000000000000..e02df563dfdd
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_h_plus_mobiledata_updated.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2025 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="16dp"
+ android:height="13.52dp"
+ android:viewportWidth="12.13"
+ android:viewportHeight="10.25">
+ <path
+ android:pathData="M5.541,10.252C5.271,10.252 5.037,10.154 4.841,9.958C4.65,9.757 4.554,9.522 4.554,9.251L4.554,1.005C4.554,0.73 4.65,0.494 4.841,0.298C5.037,0.102 5.271,0.004 5.541,0.004C5.812,0.004 6.043,0.102 6.234,0.298C6.43,0.494 6.528,0.73 6.528,1.005L6.528,9.251C6.528,9.522 6.43,9.757 6.234,9.958C6.043,10.154 5.812,10.252 5.541,10.252ZM0.984,10.252C0.714,10.252 0.48,10.154 0.284,9.958C0.093,9.757 -0.003,9.522 -0.003,9.251L-0.003,1.005C-0.003,0.73 0.093,0.494 0.284,0.298C0.48,0.102 0.714,0.004 0.984,0.004C1.255,0.004 1.486,0.102 1.677,0.298C1.873,0.494 1.971,0.73 1.971,1.005L1.971,9.251C1.971,9.522 1.873,9.757 1.677,9.958C1.486,10.154 1.255,10.252 0.984,10.252ZM1.145,5.933L1.145,4.106L5.478,4.106L5.478,5.933L1.145,5.933Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M10.056,4.396C9.877,4.396 9.722,4.332 9.592,4.204C9.464,4.073 9.4,3.917 9.4,3.736L9.4,0.792C9.4,0.611 9.464,0.456 9.592,0.328C9.722,0.197 9.877,0.132 10.056,0.132C10.234,0.132 10.388,0.197 10.516,0.328C10.644,0.456 10.708,0.611 10.708,0.792L10.708,3.736C10.708,3.917 10.644,4.073 10.516,4.204C10.388,4.332 10.234,4.396 10.056,4.396ZM8.632,2.908C8.453,2.908 8.3,2.845 8.172,2.72C8.044,2.592 7.98,2.44 7.98,2.264C7.98,2.088 8.044,1.937 8.172,1.812C8.3,1.684 8.453,1.62 8.632,1.62L11.48,1.62C11.658,1.62 11.812,1.684 11.94,1.812C12.068,1.937 12.132,2.088 12.132,2.264C12.132,2.44 12.068,2.592 11.94,2.72C11.812,2.845 11.658,2.908 11.48,2.908L8.632,2.908Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_lte_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_lte_mobiledata_updated.xml
new file mode 100644
index 000000000000..9d64439cf30b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_lte_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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="20dp"
+ android:height="11.92dp"
+ android:viewportWidth="17.2"
+ android:viewportHeight="10.25">
+ <path
+ android:pathData="M1.082,10.14C0.788,10.14 0.534,10.033 0.319,9.818C0.105,9.603 -0.003,9.349 -0.003,9.055L-0.003,1.005C-0.003,0.73 0.093,0.494 0.284,0.298C0.48,0.102 0.714,0.004 0.984,0.004C1.255,0.004 1.486,0.102 1.677,0.298C1.873,0.494 1.971,0.73 1.971,1.005L1.971,8.313L4.19,8.313C4.442,8.313 4.659,8.404 4.841,8.586C5.023,8.763 5.114,8.976 5.114,9.223C5.114,9.475 5.023,9.692 4.841,9.874C4.659,10.051 4.442,10.14 4.19,10.14L1.082,10.14ZM7.59,10.252C7.32,10.252 7.086,10.154 6.89,9.958C6.694,9.757 6.596,9.522 6.596,9.251L6.596,1.068L8.577,1.068L8.577,9.251C8.577,9.522 8.479,9.757 8.283,9.958C8.087,10.154 7.856,10.252 7.59,10.252ZM5.413,1.936C5.161,1.936 4.944,1.847 4.762,1.67C4.585,1.488 4.496,1.273 4.496,1.026C4.496,0.779 4.585,0.566 4.762,0.389C4.944,0.207 5.161,0.116 5.413,0.116L9.753,0.116C10.005,0.116 10.222,0.207 10.404,0.389C10.586,0.566 10.677,0.779 10.677,1.026C10.677,1.273 10.586,1.488 10.404,1.67C10.222,1.847 10.005,1.936 9.753,1.936L5.413,1.936ZM12.799,10.14C12.505,10.14 12.251,10.033 12.036,9.818C11.821,9.603 11.714,9.349 11.714,9.055L11.714,1.201C11.714,0.907 11.821,0.653 12.036,0.438C12.251,0.223 12.505,0.116 12.799,0.116L16.173,0.116C16.425,0.116 16.64,0.207 16.817,0.389C16.999,0.566 17.09,0.779 17.09,1.026C17.09,1.273 16.999,1.488 16.817,1.67C16.64,1.847 16.425,1.936 16.173,1.936L13.681,1.936L13.681,8.32L16.278,8.32C16.53,8.32 16.745,8.411 16.922,8.593C17.104,8.77 17.195,8.983 17.195,9.23C17.195,9.477 17.104,9.692 16.922,9.874C16.745,10.051 16.53,10.14 16.278,10.14L12.799,10.14ZM12.904,5.856L12.904,4.162L15.669,4.162C15.902,4.162 16.103,4.246 16.271,4.414C16.439,4.577 16.523,4.776 16.523,5.009C16.523,5.238 16.439,5.436 16.271,5.604C16.103,5.772 15.902,5.856 15.669,5.856L12.904,5.856Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_lte_plus_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_lte_plus_mobiledata_updated.xml
new file mode 100644
index 000000000000..7075516e6dd3
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_lte_plus_mobiledata_updated.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2025 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="25dp"
+ android:height="11.85dp"
+ android:viewportWidth="21.63"
+ android:viewportHeight="10.25">
+ <path
+ android:pathData="M1.082,10.14C0.788,10.14 0.534,10.033 0.319,9.818C0.105,9.603 -0.003,9.349 -0.003,9.055L-0.003,1.005C-0.003,0.73 0.093,0.494 0.284,0.298C0.48,0.102 0.714,0.004 0.984,0.004C1.255,0.004 1.486,0.102 1.677,0.298C1.873,0.494 1.971,0.73 1.971,1.005L1.971,8.313L4.19,8.313C4.442,8.313 4.659,8.404 4.841,8.586C5.023,8.763 5.114,8.976 5.114,9.223C5.114,9.475 5.023,9.692 4.841,9.874C4.659,10.051 4.442,10.14 4.19,10.14L1.082,10.14ZM7.59,10.252C7.32,10.252 7.086,10.154 6.89,9.958C6.694,9.757 6.596,9.522 6.596,9.251L6.596,1.068L8.577,1.068L8.577,9.251C8.577,9.522 8.479,9.757 8.283,9.958C8.087,10.154 7.856,10.252 7.59,10.252ZM5.413,1.936C5.161,1.936 4.944,1.847 4.762,1.67C4.585,1.488 4.496,1.273 4.496,1.026C4.496,0.779 4.585,0.566 4.762,0.389C4.944,0.207 5.161,0.116 5.413,0.116L9.753,0.116C10.005,0.116 10.222,0.207 10.404,0.389C10.586,0.566 10.677,0.779 10.677,1.026C10.677,1.273 10.586,1.488 10.404,1.67C10.222,1.847 10.005,1.936 9.753,1.936L5.413,1.936ZM12.799,10.14C12.505,10.14 12.251,10.033 12.036,9.818C11.821,9.603 11.714,9.349 11.714,9.055L11.714,1.201C11.714,0.907 11.821,0.653 12.036,0.438C12.251,0.223 12.505,0.116 12.799,0.116L16.173,0.116C16.425,0.116 16.64,0.207 16.817,0.389C16.999,0.566 17.09,0.779 17.09,1.026C17.09,1.273 16.999,1.488 16.817,1.67C16.64,1.847 16.425,1.936 16.173,1.936L13.681,1.936L13.681,8.32L16.278,8.32C16.53,8.32 16.745,8.411 16.922,8.593C17.104,8.77 17.195,8.983 17.195,9.23C17.195,9.477 17.104,9.692 16.922,9.874C16.745,10.051 16.53,10.14 16.278,10.14L12.799,10.14ZM12.904,5.856L12.904,4.162L15.669,4.162C15.902,4.162 16.103,4.246 16.271,4.414C16.439,4.577 16.523,4.776 16.523,5.009C16.523,5.238 16.439,5.436 16.271,5.604C16.103,5.772 15.902,5.856 15.669,5.856L12.904,5.856Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M19.556,4.396C19.377,4.396 19.222,4.332 19.092,4.204C18.964,4.073 18.9,3.917 18.9,3.736L18.9,0.792C18.9,0.611 18.964,0.456 19.092,0.328C19.222,0.197 19.377,0.132 19.556,0.132C19.734,0.132 19.888,0.197 20.016,0.328C20.144,0.456 20.208,0.611 20.208,0.792L20.208,3.736C20.208,3.917 20.144,4.073 20.016,4.204C19.888,4.332 19.734,4.396 19.556,4.396ZM18.132,2.908C17.953,2.908 17.8,2.845 17.672,2.72C17.544,2.592 17.48,2.44 17.48,2.264C17.48,2.088 17.544,1.937 17.672,1.812C17.8,1.684 17.953,1.62 18.132,1.62L20.98,1.62C21.158,1.62 21.312,1.684 21.44,1.812C21.568,1.937 21.632,2.088 21.632,2.264C21.632,2.44 21.568,2.592 21.44,2.72C21.312,2.845 21.158,2.908 20.98,2.908L18.132,2.908Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index 51259e2f311d..e7887ed26cc3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -295,9 +295,9 @@ public class DreamBackend {
@WhenToDream
public int getWhenToDreamSetting() {
return isActivatedOnDock() && isActivatedOnSleep() ? WHILE_CHARGING_OR_DOCKED
- : isActivatedOnDock() ? WHILE_DOCKED
- : isActivatedOnPostured() ? WHILE_POSTURED
- : isActivatedOnSleep() ? WHILE_CHARGING
+ : isActivatedOnSleep() ? WHILE_CHARGING
+ : isActivatedOnDock() ? WHILE_DOCKED
+ : isActivatedOnPostured() ? WHILE_POSTURED
: NEVER;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java b/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java
index 094567c400a3..9ca46238c2ce 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java
@@ -18,6 +18,7 @@ package com.android.settingslib.mobile;
import com.android.settingslib.R;
import com.android.settingslib.SignalIcon.MobileIconGroup;
+import com.android.settingslib.flags.Flags;
import java.util.HashMap;
import java.util.Map;
@@ -29,22 +30,47 @@ public class TelephonyIcons {
//***** Data connection icons
public static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_airplane_mode;
- public static final int ICON_LTE = R.drawable.ic_lte_mobiledata;
- public static final int ICON_LTE_PLUS = R.drawable.ic_lte_plus_mobiledata;
- public static final int ICON_G = R.drawable.ic_g_mobiledata;
- public static final int ICON_E = R.drawable.ic_e_mobiledata;
- public static final int ICON_H = R.drawable.ic_h_mobiledata;
- public static final int ICON_H_PLUS = R.drawable.ic_h_plus_mobiledata;
- public static final int ICON_3G = R.drawable.ic_3g_mobiledata;
- public static final int ICON_4G = R.drawable.ic_4g_mobiledata;
- public static final int ICON_4G_PLUS = R.drawable.ic_4g_plus_mobiledata;
- public static final int ICON_4G_LTE = R.drawable.ic_4g_lte_mobiledata;
- public static final int ICON_4G_LTE_PLUS = R.drawable.ic_4g_lte_plus_mobiledata;
- public static final int ICON_5G_E = R.drawable.ic_5g_e_mobiledata;
- public static final int ICON_1X = R.drawable.ic_1x_mobiledata;
- public static final int ICON_5G = R.drawable.ic_5g_mobiledata;
- public static final int ICON_5G_PLUS = R.drawable.ic_5g_plus_mobiledata;
- public static final int ICON_CWF = R.drawable.ic_carrier_wifi;
+ public static final int ICON_LTE =
+ flagged(R.drawable.ic_lte_mobiledata, R.drawable.ic_lte_mobiledata_updated);
+ public static final int ICON_LTE_PLUS =
+ flagged(R.drawable.ic_lte_plus_mobiledata, R.drawable.ic_lte_plus_mobiledata_updated);
+ public static final int ICON_G =
+ flagged(R.drawable.ic_g_mobiledata, R.drawable.ic_g_mobiledata_updated);
+ public static final int ICON_E =
+ flagged(R.drawable.ic_e_mobiledata, R.drawable.ic_e_mobiledata_updated);
+ public static final int ICON_H =
+ flagged(R.drawable.ic_h_mobiledata, R.drawable.ic_h_mobiledata_updated);
+ public static final int ICON_H_PLUS =
+ flagged(R.drawable.ic_h_plus_mobiledata, R.drawable.ic_h_plus_mobiledata_updated);
+ public static final int ICON_3G =
+ flagged(R.drawable.ic_3g_mobiledata, R.drawable.ic_3g_mobiledata_updated);
+ public static final int ICON_4G =
+ flagged(R.drawable.ic_4g_mobiledata, R.drawable.ic_4g_mobiledata_updated);
+ public static final int ICON_4G_PLUS =
+ flagged(R.drawable.ic_4g_plus_mobiledata, R.drawable.ic_4g_plus_mobiledata_updated);
+ public static final int ICON_4G_LTE =
+ flagged(R.drawable.ic_4g_lte_mobiledata, R.drawable.ic_4g_lte_mobiledata_updated);
+ public static final int ICON_4G_LTE_PLUS =
+ flagged(R.drawable.ic_4g_lte_plus_mobiledata,
+ R.drawable.ic_4g_lte_plus_mobiledata_updated);
+ public static final int ICON_5G_E =
+ flagged(R.drawable.ic_5g_e_mobiledata, R.drawable.ic_5g_e_mobiledata_updated);
+ public static final int ICON_1X =
+ flagged(R.drawable.ic_1x_mobiledata, R.drawable.ic_1x_mobiledata_updated);
+ public static final int ICON_5G =
+ flagged(R.drawable.ic_5g_mobiledata, R.drawable.ic_5g_mobiledata_updated);
+ public static final int ICON_5G_PLUS =
+ flagged(R.drawable.ic_5g_plus_mobiledata, R.drawable.ic_5g_plus_mobiledata_updated);
+ public static final int ICON_CWF =
+ flagged(R.drawable.ic_carrier_wifi, R.drawable.ic_carrier_wifi_updated);
+
+ /** Make it slightly more obvious which resource we are using */
+ private static int flagged(int oldIcon, int newIcon) {
+ if (Flags.newStatusBarIcons()) {
+ return newIcon;
+ }
+ return oldIcon;
+ }
public static final MobileIconGroup CARRIER_NETWORK_CHANGE = new MobileIconGroup(
"CARRIER_NETWORK_CHANGE",
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java
index 00ae96cfab50..c21eb0ce777a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java
@@ -16,6 +16,8 @@
package com.android.settingslib.dream;
+import static android.service.dreams.Flags.FLAG_ALLOW_DREAM_WHEN_POSTURED;
+
import static com.android.settingslib.dream.DreamBackend.COMPLICATION_TYPE_DATE;
import static com.android.settingslib.dream.DreamBackend.COMPLICATION_TYPE_HOME_CONTROLS;
import static com.android.settingslib.dream.DreamBackend.COMPLICATION_TYPE_TIME;
@@ -28,6 +30,7 @@ import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
+import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
import org.junit.After;
@@ -173,6 +176,58 @@ public final class DreamBackendTest {
.containsExactlyElementsIn(enabledComplications);
}
+ @Test
+ @EnableFlags(FLAG_ALLOW_DREAM_WHEN_POSTURED)
+ public void testChargingAndPosturedBothEnabled() {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+ 1
+ );
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED,
+ 1
+ );
+
+ assertThat(mBackend.getWhenToDreamSetting()).isEqualTo(DreamBackend.WHILE_CHARGING);
+ }
+
+ @Test
+ public void testChargingAndDockedBothEnabled() {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+ 1
+ );
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+ 1
+ );
+
+ assertThat(mBackend.getWhenToDreamSetting()).isEqualTo(
+ DreamBackend.WHILE_CHARGING_OR_DOCKED);
+ }
+
+ @Test
+ @EnableFlags(FLAG_ALLOW_DREAM_WHEN_POSTURED)
+ public void testPosturedAndDockedBothEnabled() {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED,
+ 1
+ );
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+ 1
+ );
+
+ assertThat(mBackend.getWhenToDreamSetting()).isEqualTo(
+ DreamBackend.WHILE_DOCKED);
+ }
+
private void setControlsEnabledOnLockscreen(boolean enabled) {
Settings.Secure.putInt(
mContext.getContentResolver(),
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index 0b17a3f71bda..9b76f15b3cd6 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -42,6 +42,7 @@ import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayout
import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.observableTransitionState
import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutState
import com.android.compose.animation.scene.transitions
@@ -87,10 +88,26 @@ val sceneTransitionsV2 = transitions {
spec = tween(durationMillis = TransitionDuration.TO_GLANCEABLE_HUB_DURATION_MS)
fade(AllElements)
}
+ to(CommunalScenes.Communal, key = CommunalTransitionKeys.Swipe) {
+ spec = tween(durationMillis = TransitionDuration.TO_GLANCEABLE_HUB_DURATION_MS)
+ translate(Communal.Elements.Grid, Edge.End)
+ timestampRange(startMillis = 167, endMillis = 334) { fade(AllElements) }
+ }
to(CommunalScenes.Blank) {
spec = tween(durationMillis = TO_GONE_DURATION.toInt(DurationUnit.MILLISECONDS))
fade(AllElements)
}
+ to(CommunalScenes.Blank, key = CommunalTransitionKeys.Swipe) {
+ spec = tween(durationMillis = TransitionDuration.TO_GLANCEABLE_HUB_DURATION_MS)
+ translate(Communal.Elements.Grid, Edge.End)
+ timestampRange(endMillis = 167) {
+ fade(Communal.Elements.Grid)
+ fade(Communal.Elements.IndicationArea)
+ fade(Communal.Elements.LockIcon)
+ fade(Communal.Elements.StatusBar)
+ }
+ timestampRange(startMillis = 167, endMillis = 334) { fade(Communal.Elements.Scrim) }
+ }
}
val sceneTransitions = transitions {
@@ -165,6 +182,7 @@ fun CommunalContainer(
viewModel.communalBackground.collectAsStateWithLifecycle(
initialValue = CommunalBackgroundType.ANIMATED
)
+ val swipeToHubEnabled by viewModel.swipeToHubEnabled.collectAsStateWithLifecycle()
val state: MutableSceneTransitionLayoutState =
rememberMutableSceneTransitionLayoutState(
initialScene = currentSceneKey,
@@ -200,15 +218,27 @@ fun CommunalContainer(
scene(
CommunalScenes.Blank,
userActions =
- if (viewModel.swipeToHubEnabled())
- mapOf(Swipe.Start(fromSource = Edge.End) to CommunalScenes.Communal)
- else emptyMap(),
+ if (swipeToHubEnabled) {
+ mapOf(
+ Swipe.Start(fromSource = Edge.End) to
+ UserActionResult(CommunalScenes.Communal, CommunalTransitionKeys.Swipe)
+ )
+ } else {
+ emptyMap()
+ },
) {
// This scene shows nothing only allowing for transitions to the communal scene.
Box(modifier = Modifier.fillMaxSize())
}
- scene(CommunalScenes.Communal, userActions = mapOf(Swipe.End to CommunalScenes.Blank)) {
+ scene(
+ CommunalScenes.Communal,
+ userActions =
+ mapOf(
+ Swipe.End to
+ UserActionResult(CommunalScenes.Blank, CommunalTransitionKeys.Swipe)
+ ),
+ ) {
CommunalScene(
backgroundType = backgroundType,
colors = colors,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt
index ff5fa3959c6d..7374f181760c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt
@@ -37,7 +37,6 @@ import com.android.systemui.testKosmos
import com.android.systemui.touchpad.data.repository.FakeTouchpadRepository
import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration.Companion.hours
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -51,7 +50,6 @@ import org.mockito.Mockito.times
import org.mockito.junit.MockitoJUnit
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
-import org.mockito.kotlin.firstValue
import org.mockito.kotlin.never
import org.mockito.kotlin.secondValue
import org.mockito.kotlin.verify
@@ -116,7 +114,6 @@ class TutorialNotificationCoordinatorTest : SysuiTestCase() {
fun showTouchpadNotification() = runTestAndClear {
touchpadRepository.setIsAnyTouchpadConnected(true)
testScope.advanceTimeBy(LAUNCH_DELAY)
- mockExistingNotification()
verifyNotification(
R.string.launch_touchpad_tutorial_notification_title,
R.string.launch_touchpad_tutorial_notification_content,
@@ -142,14 +139,10 @@ class TutorialNotificationCoordinatorTest : SysuiTestCase() {
}
@Test
- fun showKeyboardNotificationThenDisconnectKeyboard() = runTestAndClear {
+ fun cancelKeyboardNotificationWhenKeyboardDisconnects() = runTestAndClear {
keyboardRepository.setIsAnyKeyboardConnected(true)
testScope.advanceTimeBy(LAUNCH_DELAY)
- verifyNotification(
- R.string.launch_keyboard_tutorial_notification_title,
- R.string.launch_keyboard_tutorial_notification_content,
- )
- mockExistingNotification()
+ mockNotifications(hasTutorialNotification = true)
// After the keyboard is disconnected, i.e. there is nothing connected, the notification
// should be cancelled
@@ -158,22 +151,71 @@ class TutorialNotificationCoordinatorTest : SysuiTestCase() {
}
@Test
- fun showKeyboardTouchpadNotificationThenDisconnectKeyboard() = runTestAndClear {
+ fun updateNotificationToTouchpadOnlyWhenKeyboardDisconnects() = runTestAndClear {
keyboardRepository.setIsAnyKeyboardConnected(true)
touchpadRepository.setIsAnyTouchpadConnected(true)
testScope.advanceTimeBy(LAUNCH_DELAY)
- mockExistingNotification()
+ mockNotifications(hasTutorialNotification = true)
+
keyboardRepository.setIsAnyKeyboardConnected(false)
verify(notificationManager, times(2))
.notifyAsUser(eq(TAG), eq(NOTIFICATION_ID), notificationCaptor.capture(), any())
- // Connect both device and the first notification is for both
- notificationCaptor.firstValue.verify(
+ // Connect both device and the first notification is for both. After the keyboard is
+ // disconnected, i.e. with only the touchpad left, the notification should be update to
+ // touchpad only
+ notificationCaptor.secondValue.verify(
+ R.string.launch_touchpad_tutorial_notification_title,
+ R.string.launch_touchpad_tutorial_notification_content,
+ )
+ }
+
+ @Test
+ fun updateNotificationToBothDevicesWhenTouchpadConnects() = runTestAndClear {
+ keyboardRepository.setIsAnyKeyboardConnected(true)
+ testScope.advanceTimeBy(LAUNCH_DELAY)
+ mockNotifications(hasTutorialNotification = true)
+
+ touchpadRepository.setIsAnyTouchpadConnected(true)
+
+ verify(notificationManager, times(2))
+ .notifyAsUser(eq(TAG), eq(NOTIFICATION_ID), notificationCaptor.capture(), any())
+ // Update the notification from keyboard to both devices
+ notificationCaptor.secondValue.verify(
R.string.launch_keyboard_touchpad_tutorial_notification_title,
R.string.launch_keyboard_touchpad_tutorial_notification_content,
)
- // After the keyboard is disconnected, i.e. with only the touchpad left, the notification
- // should be update to the one for only touchpad
+ }
+
+ @Test
+ fun doNotShowUpdateNotificationWhenInitialNotificationIsDismissed() = runTestAndClear {
+ keyboardRepository.setIsAnyKeyboardConnected(true)
+ testScope.advanceTimeBy(LAUNCH_DELAY)
+ mockNotifications(hasTutorialNotification = false)
+
+ touchpadRepository.setIsAnyTouchpadConnected(true)
+
+ // There's only one notification being shown throughout this scenario. We don't update the
+ // notification because it has been dismissed when the touchpad connects
+ verifyNotification(
+ R.string.launch_keyboard_tutorial_notification_title,
+ R.string.launch_keyboard_tutorial_notification_content,
+ )
+ }
+
+ @Test
+ fun showTouchpadNotificationAfterDelayAndKeyboardNotificationIsDismissed() = runTestAndClear {
+ keyboardRepository.setIsAnyKeyboardConnected(true)
+ testScope.advanceTimeBy(LAUNCH_DELAY)
+ mockNotifications(hasTutorialNotification = false)
+
+ touchpadRepository.setIsAnyTouchpadConnected(true)
+ testScope.advanceTimeBy(LAUNCH_DELAY)
+
+ verify(notificationManager, times(2))
+ .notifyAsUser(eq(TAG), eq(NOTIFICATION_ID), notificationCaptor.capture(), any())
+ // The keyboard notification was shown and dismissed; the touchpad notification is scheduled
+ // independently
notificationCaptor.secondValue.verify(
R.string.launch_touchpad_tutorial_notification_title,
R.string.launch_touchpad_tutorial_notification_content,
@@ -189,10 +231,12 @@ class TutorialNotificationCoordinatorTest : SysuiTestCase() {
}
}
- // Assume that there's an existing notification when the updater checks activeNotifications
- private fun mockExistingNotification() {
+ // Mock an active notification, so when the updater checks activeNotifications, it returns one
+ // with the given id. Otherwise, return an empty array (i.e. no active notifications)
+ private fun mockNotifications(hasTutorialNotification: Boolean) {
whenever(notification.id).thenReturn(NOTIFICATION_ID)
- whenever(notificationManager.activeNotifications).thenReturn(arrayOf(notification))
+ val notifications = if (hasTutorialNotification) arrayOf(notification) else emptyArray()
+ whenever(notificationManager.activeNotifications).thenReturn(notifications)
}
private fun verifyNotification(@StringRes titleResId: Int, @StringRes contentResId: Int) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt
index 183cd8f1ae8b..eb961bd5f4ae 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt
@@ -57,7 +57,7 @@ class FakeHomeStatusBarViewModel(
override val ongoingActivityChipsLegacy =
MutableStateFlow(MultipleOngoingActivityChipsModelLegacy())
- override val statusBarPopupChips = MutableStateFlow(emptyList<PopupChipModel.Shown>())
+ override val popupChips = emptyList<PopupChipModel.Shown>()
override val mediaProjectionStopDialogDueToCallEndedState =
MutableStateFlow(MediaProjectionStopDialogModel.Hidden)
diff --git a/packages/SystemUI/res/drawable/ic_legacy_speaker_mute.xml b/packages/SystemUI/res/drawable/ic_legacy_speaker_mute.xml
new file mode 100644
index 000000000000..4e402cf530e4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_legacy_speaker_mute.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2022 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="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/textColorPrimary"
+ android:autoMirrored="true">
+ <path android:fillColor="#FFFFFFFF"
+ android:pathData="M19.8,22.6 L16.775,19.575Q16.15,19.975 15.45,20.263Q14.75,20.55 14,20.725V18.675Q14.35,18.55 14.688,18.425Q15.025,18.3 15.325,18.125L12,14.8V20L7,15H3V9H6.2L1.4,4.2L2.8,2.8L21.2,21.2ZM19.6,16.8 L18.15,15.35Q18.575,14.575 18.788,13.725Q19,12.875 19,11.975Q19,9.625 17.625,7.775Q16.25,5.925 14,5.275V3.225Q17.1,3.925 19.05,6.362Q21,8.8 21,11.975Q21,13.3 20.638,14.525Q20.275,15.75 19.6,16.8ZM16.25,13.45 L14,11.2V7.95Q15.175,8.5 15.838,9.6Q16.5,10.7 16.5,12Q16.5,12.375 16.438,12.738Q16.375,13.1 16.25,13.45ZM12,9.2 L9.4,6.6 12,4ZM10,15.15V12.8L8.2,11H5V13H7.85ZM9.1,11.9Z"/>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_legacy_speaker_on.xml b/packages/SystemUI/res/drawable/ic_legacy_speaker_on.xml
new file mode 100644
index 000000000000..2a90e051b83b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_legacy_speaker_on.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2022 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="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/textColorPrimary"
+ android:autoMirrored="true">
+ <path android:fillColor="#FFFFFFFF"
+ android:pathData="M14,20.725V18.675Q16.25,18.025 17.625,16.175Q19,14.325 19,11.975Q19,9.625 17.625,7.775Q16.25,5.925 14,5.275V3.225Q17.1,3.925 19.05,6.362Q21,8.8 21,11.975Q21,15.15 19.05,17.587Q17.1,20.025 14,20.725ZM3,15V9H7L12,4V20L7,15ZM14,16V7.95Q15.175,8.5 15.838,9.6Q16.5,10.7 16.5,12Q16.5,13.275 15.838,14.362Q15.175,15.45 14,16ZM10,8.85 L7.85,11H5V13H7.85L10,15.15ZM7.5,12Z"/>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_legacy_volume_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_legacy_volume_ringer_vibrate.xml
new file mode 100644
index 000000000000..b18e0a7aae60
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_legacy_volume_ringer_vibrate.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2017 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:height="19dp"
+ android:width="19dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0"
+ android:tint="?android:attr/textColorPrimary">
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M1,9h2v6H1V9zM4,17h2V7H4V17zM21,9v6h2V9H21zM18,17h2V7h-2V17zM17,5.5v13c0,0.83 -0.67,1.5 -1.5,1.5h-7C7.67,20 7,19.33 7,18.5v-13C7,4.67 7.67,4 8.5,4h7C16.33,4 17,4.67 17,5.5zM15,6H9v12h6V6z"/>
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_speaker_mute.xml b/packages/SystemUI/res/drawable/ic_speaker_mute.xml
index 4e402cf530e4..bf31580f3bb0 100644
--- a/packages/SystemUI/res/drawable/ic_speaker_mute.xml
+++ b/packages/SystemUI/res/drawable/ic_speaker_mute.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright (C) 2022 The Android Open Source Project
+ ~ Copyright (C) 2025 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.
@@ -14,12 +14,15 @@
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24"
- android:tint="?android:attr/textColorPrimary"
- android:autoMirrored="true">
- <path android:fillColor="#FFFFFFFF"
- android:pathData="M19.8,22.6 L16.775,19.575Q16.15,19.975 15.45,20.263Q14.75,20.55 14,20.725V18.675Q14.35,18.55 14.688,18.425Q15.025,18.3 15.325,18.125L12,14.8V20L7,15H3V9H6.2L1.4,4.2L2.8,2.8L21.2,21.2ZM19.6,16.8 L18.15,15.35Q18.575,14.575 18.788,13.725Q19,12.875 19,11.975Q19,9.625 17.625,7.775Q16.25,5.925 14,5.275V3.225Q17.1,3.925 19.05,6.362Q21,8.8 21,11.975Q21,13.3 20.638,14.525Q20.275,15.75 19.6,16.8ZM16.25,13.45 L14,11.2V7.95Q15.175,8.5 15.838,9.6Q16.5,10.7 16.5,12Q16.5,12.375 16.438,12.738Q16.375,13.1 16.25,13.45ZM12,9.2 L9.4,6.6 12,4ZM10,15.15V12.8L8.2,11H5V13H7.85ZM9.1,11.9Z"/>
-</vector> \ No newline at end of file
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <group>
+ <clip-path
+ android:pathData="M0,0h20v20h-20z"/>
+ <path
+ android:pathData="M16,18.125L13.771,15.896C13.465,16.09 13.097,16.278 12.667,16.458C12.25,16.625 11.861,16.75 11.5,16.833V15.292C11.667,15.222 11.861,15.146 12.083,15.063C12.319,14.965 12.514,14.875 12.667,14.792L10,12.125V16.021L6,12.021H3V8.021H5.875L1.875,4L2.938,2.938L17.063,17.063L16,18.125ZM15.875,13.771L14.792,12.688C15.014,12.285 15.188,11.861 15.313,11.417C15.438,10.958 15.5,10.493 15.5,10.021C15.5,8.785 15.125,7.688 14.375,6.729C13.639,5.757 12.681,5.09 11.5,4.729V3.188C13.125,3.507 14.444,4.313 15.458,5.604C16.486,6.896 17,8.368 17,10.021C17,10.688 16.903,11.34 16.708,11.979C16.514,12.604 16.236,13.201 15.875,13.771ZM13.292,11.188L11.5,9.396V6.854C12.125,7.132 12.611,7.563 12.958,8.146C13.319,8.715 13.5,9.34 13.5,10.021C13.5,10.215 13.486,10.41 13.458,10.604C13.431,10.799 13.375,10.993 13.292,11.188ZM10,7.896L8.063,5.958L10,4.021V7.896Z"
+ android:fillColor="#ECDFE5"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_speaker_on.xml b/packages/SystemUI/res/drawable/ic_speaker_on.xml
index 2a90e051b83b..f0d057e1b093 100644
--- a/packages/SystemUI/res/drawable/ic_speaker_on.xml
+++ b/packages/SystemUI/res/drawable/ic_speaker_on.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright (C) 2022 The Android Open Source Project
+ ~ Copyright (C) 2025 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.
@@ -14,12 +14,15 @@
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24"
- android:tint="?android:attr/textColorPrimary"
- android:autoMirrored="true">
- <path android:fillColor="#FFFFFFFF"
- android:pathData="M14,20.725V18.675Q16.25,18.025 17.625,16.175Q19,14.325 19,11.975Q19,9.625 17.625,7.775Q16.25,5.925 14,5.275V3.225Q17.1,3.925 19.05,6.362Q21,8.8 21,11.975Q21,15.15 19.05,17.587Q17.1,20.025 14,20.725ZM3,15V9H7L12,4V20L7,15ZM14,16V7.95Q15.175,8.5 15.838,9.6Q16.5,10.7 16.5,12Q16.5,13.275 15.838,14.362Q15.175,15.45 14,16ZM10,8.85 L7.85,11H5V13H7.85L10,15.15ZM7.5,12Z"/>
-</vector> \ No newline at end of file
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <group>
+ <clip-path
+ android:pathData="M0,0h20v20h-20z"/>
+ <path
+ android:pathData="M11.5,16.833V15.271C12.694,14.951 13.66,14.306 14.396,13.333C15.132,12.347 15.5,11.236 15.5,10C15.5,8.764 15.125,7.667 14.375,6.708C13.639,5.736 12.681,5.069 11.5,4.708V3.146C13.111,3.493 14.431,4.306 15.458,5.583C16.486,6.861 17,8.326 17,9.979C17,11.632 16.486,13.104 15.458,14.396C14.444,15.674 13.125,16.486 11.5,16.833ZM3,11.979V7.979H6L10,3.979V15.979L6,11.979H3ZM11.5,13.125V6.833C12.125,7.111 12.611,7.535 12.958,8.104C13.319,8.674 13.5,9.299 13.5,9.979C13.5,10.66 13.319,11.285 12.958,11.854C12.611,12.41 12.125,12.833 11.5,13.125Z"
+ android:fillColor="#ECDFE5"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
index b18e0a7aae60..2cbbb0da8de7 100644
--- a/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
+++ b/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
@@ -1,27 +1,28 @@
<!--
- Copyright (C) 2017 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.
--->
+ ~ Copyright (C) 2025 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:height="19dp"
- android:width="19dp"
- android:viewportHeight="24.0"
- android:viewportWidth="24.0"
- android:tint="?android:attr/textColorPrimary">
-
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <group>
+ <clip-path
+ android:pathData="M0,0h20v20h-20z"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M1,9h2v6H1V9zM4,17h2V7H4V17zM21,9v6h2V9H21zM18,17h2V7h-2V17zM17,5.5v13c0,0.83 -0.67,1.5 -1.5,1.5h-7C7.67,20 7,19.33 7,18.5v-13C7,4.67 7.67,4 8.5,4h7C16.33,4 17,4.67 17,5.5zM15,6H9v12h6V6z"/>
-
+ android:pathData="M0,12.5V7.5H1.5V12.5H0ZM2.5,14V6H4V14H2.5ZM18.5,12.5V7.5H20V12.5H18.5ZM16,14V6H17.5V14H16ZM6.5,17C6.083,17 5.729,16.854 5.438,16.563C5.146,16.271 5,15.917 5,15.5V4.5C5,4.083 5.146,3.729 5.438,3.438C5.729,3.146 6.083,3 6.5,3H13.5C13.917,3 14.271,3.146 14.563,3.438C14.854,3.729 15,4.083 15,4.5V15.5C15,15.917 14.854,16.271 14.563,16.563C14.271,16.854 13.917,17 13.5,17H6.5Z"
+ android:fillColor="#ECDFE5"/>
+ </group>
</vector>
diff --git a/packages/SystemUI/res/drawable/mobile_network_type_background_updated.xml b/packages/SystemUI/res/drawable/mobile_network_type_background_updated.xml
new file mode 100644
index 000000000000..7b55b3c6fb56
--- /dev/null
+++ b/packages/SystemUI/res/drawable/mobile_network_type_background_updated.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle"
+ >
+ <corners
+ android:topLeftRadius="0dp"
+ android:topRightRadius="@dimen/status_bar_mobile_container_corner_radius_updated"
+ android:bottomRightRadius="0dp"
+ android:bottomLeftRadius="@dimen/status_bar_mobile_container_corner_radius_updated"/>
+ <solid android:color="#FFF" />
+ <padding
+ android:left="2sp"
+ android:right="2sp"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
index b83f15a1a247..c0cb5ef61ca8 100644
--- a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
@@ -14,4 +14,4 @@ Copyright (C) 2015 The Android Open Source Project
limitations under the License.
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_speaker_mute" />
+ android:drawable="@drawable/ic_legacy_speaker_mute" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
index 21a4c1703d31..4d68d674c259 100644
--- a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
@@ -16,4 +16,4 @@
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="2.5dp"
android:insetRight="2.5dp"
- android:drawable="@drawable/ic_volume_ringer_vibrate" /> \ No newline at end of file
+ android:drawable="@drawable/ic_legacy_volume_ringer_vibrate" /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index 5922a7dcdcf0..67e97010ff22 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -131,7 +131,7 @@
style="@style/InternetDialog.Network">
<FrameLayout
- android:layout_width="24dp"
+ android:layout_width="wrap_content"
android:layout_height="24dp"
android:clickable="false"
android:layout_gravity="center_vertical|start">
diff --git a/packages/SystemUI/res/layout/volume_ringer_drawer_legacy.xml b/packages/SystemUI/res/layout/volume_ringer_drawer_legacy.xml
index 0efbc6d651dc..c7e0f7d337c0 100644
--- a/packages/SystemUI/res/layout/volume_ringer_drawer_legacy.xml
+++ b/packages/SystemUI/res/layout/volume_ringer_drawer_legacy.xml
@@ -67,7 +67,7 @@
android:layout_width="@dimen/volume_ringer_drawer_icon_size"
android:layout_height="@dimen/volume_ringer_drawer_icon_size"
android:layout_gravity="center"
- android:src="@drawable/ic_volume_ringer_vibrate"
+ android:src="@drawable/ic_legacy_volume_ringer_vibrate"
android:tint="?android:attr/textColorPrimary" />
</FrameLayout>
@@ -85,7 +85,7 @@
android:layout_width="@dimen/volume_ringer_drawer_icon_size"
android:layout_height="@dimen/volume_ringer_drawer_icon_size"
android:layout_gravity="center"
- android:src="@drawable/ic_speaker_mute"
+ android:src="@drawable/ic_legacy_speaker_mute"
android:tint="?android:attr/textColorPrimary" />
</FrameLayout>
@@ -103,7 +103,7 @@
android:layout_width="@dimen/volume_ringer_drawer_icon_size"
android:layout_height="@dimen/volume_ringer_drawer_icon_size"
android:layout_gravity="center"
- android:src="@drawable/ic_speaker_on"
+ android:src="@drawable/ic_legacy_speaker_on"
android:tint="?android:attr/textColorPrimary" />
</FrameLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 8cd4c1bb3533..7d0c393f53b5 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -204,15 +204,31 @@
match the core/status_bar_system_icon_size and change to sp unit -->
<dimen name="status_bar_mobile_signal_size">15sp</dimen>
<dimen name="status_bar_mobile_signal_size_updated">12sp</dimen>
+
<!-- Size of the view displaying the mobile signal icon in the status bar. This value should
- match the viewport height of mobile signal drawables such as ic_lte_mobiledata -->
+ match the viewport height of mobile signal drawables such as ic_lte_mobiledata
+ Note: can be removed once new_status_bar_icons is rolled out -->
<dimen name="status_bar_mobile_type_size">16sp</dimen>
<!-- Size of the view that contains the network type. Should be equal to
- status_bar_mobile_type_size + 2, to account for 1sp top and bottom padding -->
+ status_bar_mobile_type_size + 2, to account for 1sp top and bottom padding
+ Note: can be removed once new_status_bar_icons is rolled out -->
<dimen name="status_bar_mobile_container_height">18sp</dimen>
<!-- Corner radius for the background of the network type indicator. Should be equal to
- status_bar_mobile_container_height / 2 -->
+ status_bar_mobile_container_height / 2
+ Note: can be removed once new_status_bar_icons is rolled out -->
<dimen name="status_bar_mobile_container_corner_radius">9sp</dimen>
+
+ <!-- Size of the view displaying the mobile signal icon in the status bar. This value should
+ match the viewport height of mobile signal drawables such as ic_lte_mobiledata -->
+ <dimen name="status_bar_mobile_type_size_updated">12sp</dimen>
+ <!-- Size of the view that contains the network type. Should be equal to
+ status_bar_mobile_type_size + 2, to account for 1sp top and bottom padding -->
+ <dimen name="status_bar_mobile_container_height_updated">14sp</dimen>
+ <dimen name="status_bar_mobile_container_margin_end">2sp</dimen>
+ <!-- Corner radius for the background of the network type indicator. Should be equal to
+ status_bar_mobile_container_height / 2 -->
+ <dimen name="status_bar_mobile_container_corner_radius_updated">7sp</dimen>
+
<!-- Size of the view displaying the mobile roam icon in the status bar. This value should
match the viewport size of drawable stat_sys_roaming -->
<dimen name="status_bar_mobile_roam_size">8sp</dimen>
@@ -1806,7 +1822,8 @@
<!-- The activity chip side padding, used with the default phone icon. -->
<dimen name="ongoing_activity_chip_side_padding">12dp</dimen>
<!-- The activity chip side padding, used with an icon that has embedded padding (e.g. if the icon comes from the notification's smallIcon field). If the icon has padding, the chip itself can have less padding. -->
- <dimen name="ongoing_activity_chip_side_padding_for_embedded_padding_icon">6dp</dimen>
+ <dimen name="ongoing_activity_chip_side_padding_for_embedded_padding_icon">2dp</dimen>
+ <dimen name="ongoing_activity_chip_side_padding_for_embedded_padding_icon_legacy">6dp</dimen>
<!-- The icon size, used with the default phone icon. -->
<dimen name="ongoing_activity_chip_icon_size">16dp</dimen>
<!-- The icon size, used with an icon that has embedded padding. (If the icon has embedded padding, we need to make the whole icon larger so the icon itself doesn't look small.) -->
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
index ca49de3b1510..a84c45732169 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
@@ -31,4 +31,6 @@ object CommunalTransitionKeys {
val ToEditMode = TransitionKey("ToEditMode")
/** Transition to the glanceable hub after exiting edit mode */
val FromEditMode = TransitionKey("FromEditMode")
+ /** Swipes the glanceable hub in/out of view */
+ val Swipe = TransitionKey("Swipe")
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index 2169881d11c5..cce1ae1a2947 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -359,7 +359,13 @@ constructor(
/** See [CommunalSettingsInteractor.isV2FlagEnabled] */
fun v2FlagEnabled(): Boolean = communalSettingsInteractor.isV2FlagEnabled()
- fun swipeToHubEnabled(): Boolean = swipeToHub
+ val swipeToHubEnabled: StateFlow<Boolean> by lazy {
+ if (v2FlagEnabled()) {
+ communalInteractor.shouldShowCommunal
+ } else {
+ MutableStateFlow(swipeToHub)
+ }
+ }
companion object {
const val POPUP_AUTO_HIDE_TIMEOUT_MS = 12000L
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt
index b712fdeaf623..0d57a57c3416 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt
@@ -102,10 +102,9 @@ constructor(
}
// This flow is used by the notification updater once an initial notification is launched. It
- // listens to the device connection changes for both keyboard and touchpad. When either of the
- // device is disconnected, resolve the tutorial type base on the latest connection state.
- // Dropping the initial state because it's the existing notification. Filtering out BOTH because
- // we only care about disconnections.
+ // listens to the changes of keyboard and touchpad connection and resolve the tutorial type base
+ // on the latest connection state.
+ // Dropping the initial state because it represents the existing notification.
val tutorialTypeUpdates: Flow<TutorialType> =
keyboardRepository.isAnyKeyboardConnected
.combine(touchpadRepository.isAnyTouchpadConnected, ::Pair)
@@ -118,7 +117,6 @@ constructor(
}
}
.drop(1)
- .filter { it != TutorialType.BOTH }
private suspend fun waitForDeviceConnection(deviceType: DeviceType) =
isAnyDeviceConnected[deviceType]!!.filter { it }.first()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index 305e71e48702..3be2f1b7b957 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -231,6 +231,9 @@ constructor(
*/
private var isDreaming = false
+ /** True if we should allow swiping open the glanceable hub. */
+ private var swipeToHubEnabled = false
+
/** Observes and logs state when the lifecycle that controls the [touchMonitor] updates. */
private val touchLifecycleLogger: LifecycleObserver = LifecycleEventObserver { _, event ->
logger.d({
@@ -438,6 +441,7 @@ constructor(
},
)
collectFlow(containerView, keyguardInteractor.isDreaming, { isDreaming = it })
+ collectFlow(containerView, communalViewModel.swipeToHubEnabled, { swipeToHubEnabled = it })
communalContainerWrapper = CommunalWrapper(containerView.context)
communalContainerWrapper?.addView(communalContainerView)
@@ -520,10 +524,7 @@ constructor(
val glanceableHubV2 = communalSettingsInteractor.isV2FlagEnabled()
if (
!hubShowing &&
- (touchOnNotifications ||
- touchOnUmo ||
- touchOnSmartspace ||
- !communalViewModel.swipeToHubEnabled())
+ (touchOnNotifications || touchOnUmo || touchOnSmartspace || !swipeToHubEnabled)
) {
logger.d({
"Lockscreen touch ignored: touchOnNotifications: $bool1, touchOnUmo: $bool2, " +
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 5746cef41d6b..131efaac3d6a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -2201,7 +2201,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
@Override
@Deprecated
public void onStatusBarLongPress(MotionEvent event) {
- mShadeLog.d("Status Bar was long pressed.");
+ Log.i(TAG, "Status Bar was long pressed.");
ShadeExpandsOnStatusBarLongPress.assertInNewMode();
mStatusBarLongPressDowntime = event.getDownTime();
if (isTracking()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
index d41353b2c176..20dec11577df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
@@ -408,11 +408,13 @@ object OngoingActivityChipBinder {
private fun View.setBackgroundPaddingForEmbeddedPaddingIcon() {
val sidePadding =
if (StatusBarNotifChips.isEnabled) {
- 0
- } else {
context.resources.getDimensionPixelSize(
R.dimen.ongoing_activity_chip_side_padding_for_embedded_padding_icon
)
+ } else {
+ context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_activity_chip_side_padding_for_embedded_padding_icon_legacy
+ )
}
setPaddingRelative(sidePadding, paddingTop, sidePadding, paddingBottom)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt
index 4a999d5f5e0e..efd402ead979 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt
@@ -41,7 +41,6 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
-import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.android.compose.animation.Expandable
import com.android.compose.modifiers.thenIf
@@ -160,7 +159,10 @@ private fun ChipBody(
.padding(
horizontal =
if (hasEmbeddedIcon) {
- 0.dp
+ dimensionResource(
+ R.dimen
+ .ongoing_activity_chip_side_padding_for_embedded_padding_icon
+ )
} else {
dimensionResource(id = R.dimen.ongoing_activity_chip_side_padding)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt
index 4017c436151e..3b8c0f48e40e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt
@@ -24,7 +24,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.key
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
+import androidx.compose.ui.res.dimensionResource
+import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder
@@ -35,10 +36,13 @@ fun OngoingActivityChips(
modifier: Modifier = Modifier,
) {
Row(
- // TODO(b/372657935): Remove magic numbers for padding and spacing.
- modifier = modifier.fillMaxHeight().padding(horizontal = 6.dp),
+ modifier =
+ modifier
+ .fillMaxHeight()
+ .padding(start = dimensionResource(R.dimen.ongoing_activity_chip_margin_start)),
verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.spacedBy(8.dp),
+ horizontalArrangement =
+ Arrangement.spacedBy(dimensionResource(R.dimen.ongoing_activity_chip_margin_start)),
) {
chips.active
.filter { !it.isHidden }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt
index 7f0f6078f391..90f97df295f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt
@@ -82,10 +82,6 @@ constructor(
chipId = PopupChipId.MediaControl,
icon = defaultIcon,
chipText = model.songName.toString(),
- isToggled = false,
- // TODO(b/385202114): Show a popup containing the media carousal when the chip is
- // toggled.
- onToggle = {},
hoverBehavior = createHoverBehavior(model),
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt
index 683b97166f3e..60615536ab67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt
@@ -53,10 +53,11 @@ sealed class PopupChipModel {
/** Default icon displayed on the chip */
val icon: Icon,
val chipText: String,
- val isToggled: Boolean = false,
- val onToggle: () -> Unit,
+ val isPopupShown: Boolean = false,
+ val showPopup: () -> Unit = {},
+ val hidePopup: () -> Unit = {},
val hoverBehavior: HoverBehavior = HoverBehavior.None,
) : PopupChipModel() {
- override val logName = "Shown(id=$chipId, toggled=$isToggled)"
+ override val logName = "Shown(id=$chipId, toggled=$isPopupShown)"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopup.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopup.kt
new file mode 100644
index 000000000000..8a66904ea59b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopup.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.featurepods.popups.ui.compose
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Popup
+import androidx.compose.ui.window.PopupProperties
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId
+import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel
+
+/**
+ * Displays a popup in the status bar area. The offset is calculated to draw the popup below the
+ * status bar.
+ */
+@Composable
+fun StatusBarPopup(viewModel: PopupChipModel.Shown) {
+ val density = Density(LocalContext.current)
+ Popup(
+ properties =
+ PopupProperties(
+ focusable = false,
+ dismissOnBackPress = true,
+ dismissOnClickOutside = true,
+ ),
+ offset =
+ IntOffset(
+ x = 0,
+ y = with(density) { dimensionResource(R.dimen.status_bar_height).roundToPx() },
+ ),
+ onDismissRequest = { viewModel.hidePopup() },
+ ) {
+ Box(modifier = Modifier.padding(8.dp).wrapContentSize()) {
+ when (viewModel.chipId) {
+ is PopupChipId.MediaControl -> {
+ // TODO(b/385202114): Populate MediaControlPopup contents.
+ }
+ }
+ // Future popup types will be handled here.
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt
index 34bef9d3ca3a..eb85d2f32f29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt
@@ -52,14 +52,14 @@ import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipM
* the chip can show text containing contextual information.
*/
@Composable
-fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifier) {
- val hasHoverBehavior = model.hoverBehavior !is HoverBehavior.None
+fun StatusBarPopupChip(viewModel: PopupChipModel.Shown, modifier: Modifier = Modifier) {
+ val hasHoverBehavior = viewModel.hoverBehavior !is HoverBehavior.None
val hoverInteractionSource = remember { MutableInteractionSource() }
val isHovered by hoverInteractionSource.collectIsHoveredAsState()
- val isToggled = model.isToggled
+ val isPopupShown = viewModel.isPopupShown
val chipBackgroundColor =
- if (isToggled) {
+ if (isPopupShown) {
MaterialTheme.colorScheme.primaryContainer
} else {
MaterialTheme.colorScheme.surfaceContainerHighest
@@ -72,7 +72,7 @@ fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifie
.padding(vertical = 4.dp)
.animateContentSize()
.thenIf(hasHoverBehavior) { Modifier.hoverable(hoverInteractionSource) }
- .clickable { model.onToggle() },
+ .thenIf(!isPopupShown) { Modifier.clickable { viewModel.showPopup() } },
color = chipBackgroundColor,
) {
Row(
@@ -82,14 +82,14 @@ fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifie
) {
val iconColor =
if (isHovered) chipBackgroundColor else contentColorFor(chipBackgroundColor)
- val hoverBehavior = model.hoverBehavior
+ val hoverBehavior = viewModel.hoverBehavior
val iconBackgroundColor = contentColorFor(chipBackgroundColor)
val iconInteractionSource = remember { MutableInteractionSource() }
Icon(
icon =
when {
isHovered && hoverBehavior is HoverBehavior.Button -> hoverBehavior.icon
- else -> model.icon
+ else -> viewModel.icon
},
modifier =
Modifier.thenIf(isHovered) {
@@ -109,7 +109,7 @@ fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifie
)
Text(
- text = model.chipText,
+ text = viewModel.chipText,
style = MaterialTheme.typography.labelLarge,
softWrap = false,
overflow = TextOverflow.Ellipsis,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt
index d35674d8dd9f..16538c93cf35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt
@@ -31,10 +31,15 @@ fun StatusBarPopupChipsContainer(chips: List<PopupChipModel.Shown>, modifier: Mo
// TODO(b/385353140): Add padding and spacing for this container according to UX specs.
Box {
Row(
- modifier = Modifier.padding(horizontal = 8.dp),
+ modifier = modifier.padding(horizontal = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
- chips.forEach { chip -> StatusBarPopupChip(chip) }
+ chips.forEach { chip ->
+ StatusBarPopupChip(chip)
+ if (chip.isPopupShown) {
+ StatusBarPopup(chip)
+ }
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt
index caa8e6cc02c3..33bf90defb48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt
@@ -16,49 +16,65 @@
package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.statusbar.featurepods.media.ui.viewmodel.MediaControlChipViewModel
import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips
import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId
import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
/**
* View model deciding which system process chips to show in the status bar. Emits a list of
* PopupChipModels.
*/
-@SysUISingleton
class StatusBarPopupChipsViewModel
-@Inject
-constructor(
- @Background scope: CoroutineScope,
- mediaControlChipViewModel: MediaControlChipViewModel,
-) {
- private data class PopupChipBundle(
- val media: PopupChipModel = PopupChipModel.Hidden(chipId = PopupChipId.MediaControl)
- )
+@AssistedInject
+constructor(mediaControlChip: MediaControlChipViewModel) : ExclusiveActivatable() {
+ private val hydrator: Hydrator = Hydrator("StatusBarPopupChipsViewModel.hydrator")
- private val incomingPopupChipBundle: StateFlow<PopupChipBundle?> =
- mediaControlChipViewModel.chip
- .map { chip -> PopupChipBundle(media = chip) }
- .stateIn(scope, SharingStarted.WhileSubscribed(), PopupChipBundle())
+ /** The ID of the current chip that is showing its popup, or `null` if no chip is shown. */
+ private var currentShownPopupChipId by mutableStateOf<PopupChipId?>(null)
- val shownPopupChips: StateFlow<List<PopupChipModel.Shown>> =
+ private val incomingPopupChipBundle: PopupChipBundle by
+ hydrator.hydratedStateOf(
+ traceName = "incomingPopupChipBundle",
+ initialValue = PopupChipBundle(),
+ source = mediaControlChip.chip.map { chip -> PopupChipBundle(media = chip) },
+ )
+
+ val shownPopupChips: List<PopupChipModel.Shown> by derivedStateOf {
if (StatusBarPopupChips.isEnabled) {
- incomingPopupChipBundle
- .map { bundle ->
- listOfNotNull(bundle?.media).filterIsInstance<PopupChipModel.Shown>()
- }
- .stateIn(scope, SharingStarted.WhileSubscribed(), emptyList())
+ val bundle = incomingPopupChipBundle
+
+ listOfNotNull(bundle.media).filterIsInstance<PopupChipModel.Shown>().map { chip ->
+ chip.copy(
+ isPopupShown = chip.chipId == currentShownPopupChipId,
+ showPopup = { currentShownPopupChipId = chip.chipId },
+ hidePopup = { currentShownPopupChipId = null },
+ )
+ }
} else {
- MutableStateFlow(emptyList<PopupChipModel.Shown>()).asStateFlow()
+ emptyList()
}
+ }
+
+ override suspend fun onActivated(): Nothing {
+ hydrator.activate()
+ }
+
+ private data class PopupChipBundle(
+ val media: PopupChipModel = PopupChipModel.Hidden(chipId = PopupChipId.MediaControl)
+ )
+
+ @AssistedFactory
+ interface Factory {
+ fun create(): StatusBarPopupChipsViewModel
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
index 4458b224913b..7eda87f8418d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.view
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
+import android.widget.FrameLayout
import android.widget.ImageView
import com.android.systemui.res.R
import com.android.systemui.statusbar.StatusBarIconView.getVisibleStateString
@@ -61,12 +62,33 @@ class ModernStatusBarMobileView(context: Context, attrs: AttributeSet?) :
.also {
// Flag-specific configuration
if (NewStatusBarIcons.isEnabled) {
- val iconView = it.requireViewById<ImageView>(R.id.mobile_signal)
- val lp = iconView.layoutParams
- lp.height =
- context.resources.getDimensionPixelSize(
- R.dimen.status_bar_mobile_signal_size_updated
- )
+ // triangle
+ it.requireViewById<ImageView>(R.id.mobile_signal).apply {
+ layoutParams.height =
+ context.resources.getDimensionPixelSize(
+ R.dimen.status_bar_mobile_signal_size_updated
+ )
+ }
+
+ // RAT indicator container
+ it.requireViewById<FrameLayout>(R.id.mobile_type_container).apply {
+ (layoutParams as MarginLayoutParams).marginEnd =
+ context.resources.getDimensionPixelSize(
+ R.dimen.status_bar_mobile_container_margin_end
+ )
+ layoutParams.height =
+ context.resources.getDimensionPixelSize(
+ R.dimen.status_bar_mobile_container_height_updated
+ )
+ }
+
+ // RAT indicator
+ it.requireViewById<ImageView>(R.id.mobile_type).apply {
+ layoutParams.height =
+ context.resources.getDimensionPixelSize(
+ R.dimen.status_bar_mobile_type_size_updated
+ )
+ }
}
it.subId = viewModel.subscriptionId
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
index 171e4f59b0e5..e37c3f10cfcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
@@ -23,6 +23,7 @@ import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags.NEW_NETWORK_SLICE_UI
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.res.R
+import com.android.systemui.statusbar.core.NewStatusBarIcons
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
@@ -278,10 +279,11 @@ private class CellularIconViewModel(
flowOf(null)
} else {
iconInteractor.showSliceAttribution.map {
- if (it) {
- Icon.Resource(R.drawable.mobile_network_type_background, null)
- } else {
- null
+ when {
+ it && NewStatusBarIcons.isEnabled ->
+ Icon.Resource(R.drawable.mobile_network_type_background_updated, null)
+ it -> Icon.Resource(R.drawable.mobile_network_type_background, null)
+ else -> null
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
index a961713230c8..39a1b46292b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
@@ -255,10 +255,9 @@ fun StatusBarRoot(
)
setContent {
- val chips =
- statusBarViewModel.statusBarPopupChips
- .collectAsStateWithLifecycle()
- StatusBarPopupChipsContainer(chips = chips.value)
+ StatusBarPopupChipsContainer(
+ chips = statusBarViewModel.popupChips
+ )
}
}
endSideContent.addView(composeView, 0)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
index f396cbfc8000..9ae2cb203d91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
@@ -20,6 +20,7 @@ import android.annotation.ColorInt
import android.graphics.Rect
import android.view.View
import androidx.compose.runtime.getValue
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -29,6 +30,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.lifecycle.Activatable
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.log.table.TableLogBufferFactory
@@ -49,6 +51,7 @@ import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel
import com.android.systemui.statusbar.events.domain.interactor.SystemStatusEventAnimationInteractor
import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.Idle
+import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips
import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel
import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.StatusBarPopupChipsViewModel
import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior
@@ -71,6 +74,8 @@ import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -94,7 +99,7 @@ import kotlinx.coroutines.flow.stateIn
* [StatusBarHideIconsForBouncerManager]. We should move those pieces of logic to this class instead
* so that it's all in one place and easily testable outside of the fragment.
*/
-interface HomeStatusBarViewModel {
+interface HomeStatusBarViewModel : Activatable {
/** Factory to create the view model for the battery icon */
val batteryViewModelFactory: BatteryViewModel.Factory
@@ -133,7 +138,7 @@ interface HomeStatusBarViewModel {
val operatorNameViewModel: StatusBarOperatorNameViewModel
/** The popup chips that should be shown on the right-hand side of the status bar. */
- val statusBarPopupChips: StateFlow<List<PopupChipModel.Shown>>
+ val popupChips: List<PopupChipModel.Shown>
/**
* True if the current scene can show the home status bar (aka this status bar), and false if
@@ -208,7 +213,7 @@ constructor(
shadeInteractor: ShadeInteractor,
shareToAppChipViewModel: ShareToAppChipViewModel,
ongoingActivityChipsViewModel: OngoingActivityChipsViewModel,
- statusBarPopupChipsViewModel: StatusBarPopupChipsViewModel,
+ statusBarPopupChipsViewModelFactory: StatusBarPopupChipsViewModel.Factory,
animations: SystemStatusEventAnimationInteractor,
statusBarContentInsetsViewModelStore: StatusBarContentInsetsViewModelStore,
@Background bgScope: CoroutineScope,
@@ -219,6 +224,8 @@ constructor(
val tableLogger = tableLoggerFactory.getOrCreate(tableLogBufferName(thisDisplayId), 200)
+ private val statusBarPopupChips by lazy { statusBarPopupChipsViewModelFactory.create() }
+
override val isTransitioningFromLockscreenToOccluded: StateFlow<Boolean> =
keyguardTransitionInteractor
.isInTransition(Edge.create(from = LOCKSCREEN, to = OCCLUDED))
@@ -246,7 +253,8 @@ constructor(
override val ongoingActivityChipsLegacy = ongoingActivityChipsViewModel.chipsLegacy
- override val statusBarPopupChips = statusBarPopupChipsViewModel.shownPopupChips
+ override val popupChips
+ get() = statusBarPopupChips.shownPopupChips
override val isHomeStatusBarAllowedByScene: StateFlow<Boolean> =
combine(
@@ -495,7 +503,13 @@ constructor(
private fun Boolean.toVisibleOrInvisible(): Int = if (this) View.VISIBLE else View.INVISIBLE
override suspend fun onActivated(): Nothing {
- hydrator.activate()
+ coroutineScope {
+ launch { hydrator.activate() }
+ if (StatusBarPopupChips.isEnabled) {
+ launch { statusBarPopupChips.activate() }
+ }
+ awaitCancellation()
+ }
}
/** Inject this to create the display-dependent view model */
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index ae3756d390af..6fc95610159a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -308,9 +308,9 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
private int mWindowGravity;
@VisibleForTesting
- final int mVolumeRingerIconDrawableId = R.drawable.ic_speaker_on;
+ final int mVolumeRingerIconDrawableId = R.drawable.ic_legacy_speaker_on;
@VisibleForTesting
- final int mVolumeRingerMuteIconDrawableId = R.drawable.ic_speaker_mute;
+ final int mVolumeRingerMuteIconDrawableId = R.drawable.ic_legacy_speaker_mute;
private int mOriginalGravity;
private final DevicePostureController.Callback mDevicePostureControllerCallback;
@@ -1791,8 +1791,9 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
enableRingerViewsH(!isZenMuted);
switch (mState.ringerModeInternal) {
case AudioManager.RINGER_MODE_VIBRATE:
- mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
- mSelectedRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
+ mRingerIcon.setImageResource(R.drawable.ic_legacy_volume_ringer_vibrate);
+ mSelectedRingerIcon.setImageResource(
+ R.drawable.ic_legacy_volume_ringer_vibrate);
addAccessibilityDescription(mRingerIcon, RINGER_MODE_VIBRATE,
mContext.getString(R.string.volume_ringer_hint_mute));
mRingerIcon.setTag(Events.ICON_STATE_VIBRATE);
@@ -1990,7 +1991,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
if (zenMuted) {
iconRes = com.android.internal.R.drawable.ic_qs_dnd;
} else if (isRingVibrate) {
- iconRes = R.drawable.ic_volume_ringer_vibrate;
+ iconRes = R.drawable.ic_legacy_volume_ringer_vibrate;
} else if (isRingSilent) {
iconRes = row.iconMuteRes;
} else if (ss.routedToBluetooth) {
@@ -2009,7 +2010,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
row.setIcon(iconRes, mContext.getTheme());
row.iconState =
- iconRes == R.drawable.ic_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE
+ iconRes == R.drawable.ic_legacy_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE
: (iconRes == R.drawable.ic_volume_media_bt_mute || iconRes == row.iconMuteRes)
? Events.ICON_STATE_MUTE
: (iconRes == R.drawable.ic_volume_media_bt || iconRes == row.iconRes
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
index 944604f94ce4..ae8b52aa6553 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -18,7 +18,7 @@ package com.android.systemui.shade
import android.graphics.Insets
import android.graphics.Rect
-import android.os.PowerManager
+import android.os.powerManager
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.testing.AndroidTestingRunner
@@ -32,7 +32,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.SceneKey
-import com.android.systemui.Flags
+import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
import com.android.systemui.Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX
import com.android.systemui.SysuiTestCase
@@ -40,7 +40,6 @@ import com.android.systemui.ambient.touch.TouchHandler
import com.android.systemui.ambient.touch.TouchMonitor
import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
-import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
@@ -58,8 +57,10 @@ import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.media.controls.controller.keyguardMediaController
import com.android.systemui.res.R
@@ -69,8 +70,8 @@ import com.android.systemui.statusbar.lockscreen.lockscreenSmartspaceController
import com.android.systemui.statusbar.notification.stack.notificationStackScrollLayoutController
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Assert.assertThrows
@@ -89,33 +90,23 @@ import org.mockito.kotlin.whenever
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
+@EnableFlags(FLAG_COMMUNAL_HUB)
class GlanceableHubContainerControllerTest : SysuiTestCase() {
- private val kosmos: Kosmos =
- testKosmos().apply {
- // UnconfinedTestDispatcher makes testing simpler due to CommunalInteractor flows using
- // SharedFlow
- testDispatcher = UnconfinedTestDispatcher()
- }
+ private val kosmos: Kosmos = testKosmos().useUnconfinedTestDispatcher()
- private var communalViewModel = mock<CommunalViewModel>()
- private var powerManager = mock<PowerManager>()
- private var touchMonitor = mock<TouchMonitor>()
- private var communalColors = mock<CommunalColors>()
- private var communalContent = mock<CommunalContent>()
- private lateinit var ambientTouchComponentFactory: AmbientTouchComponent.Factory
+ private val swipeToHubEnabled = MutableStateFlow(false)
+ private val mockCommunalViewModel =
+ mock<CommunalViewModel> { on { swipeToHubEnabled } doReturn swipeToHubEnabled }
+ private val touchMonitor = mock<TouchMonitor>()
private lateinit var parentView: FrameLayout
private lateinit var containerView: View
- private lateinit var testableLooper: TestableLooper
-
- private lateinit var communalRepository: FakeCommunalSceneRepository
- private lateinit var underTest: GlanceableHubContainerController
- @Before
- fun setUp() {
- communalRepository = kosmos.fakeCommunalSceneRepository
+ private val Kosmos.testableLooper by
+ Kosmos.Fixture { TestableLooper.get(this@GlanceableHubContainerControllerTest) }
- ambientTouchComponentFactory =
+ private val Kosmos.ambientTouchComponentFactory by
+ Kosmos.Fixture {
object : AmbientTouchComponent.Factory {
override fun create(
lifecycleOwner: LifecycleOwner,
@@ -126,50 +117,39 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
override fun getTouchMonitor(): TouchMonitor = touchMonitor
}
}
+ }
- with(kosmos) {
- underTest =
- GlanceableHubContainerController(
- communalInteractor,
- communalSettingsInteractor,
- communalViewModel,
- keyguardInteractor,
- keyguardTransitionInteractor,
- shadeInteractor,
- powerManager,
- communalColors,
- ambientTouchComponentFactory,
- communalContent,
- sceneDataSourceDelegator,
- notificationStackScrollLayoutController,
- keyguardMediaController,
- lockscreenSmartspaceController,
- logcatLogBuffer("GlanceableHubContainerControllerTest"),
- )
-
- // Make below last notification true by default or else touches will be ignored by
- // default when the hub is not showing.
- whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any()))
- .thenReturn(true)
+ private val Kosmos.underTest by
+ Kosmos.Fixture {
+ GlanceableHubContainerController(
+ communalInteractor,
+ communalSettingsInteractor,
+ mockCommunalViewModel,
+ keyguardInteractor,
+ keyguardTransitionInteractor,
+ shadeInteractor,
+ powerManager,
+ mock<CommunalColors>(),
+ ambientTouchComponentFactory,
+ mock<CommunalContent>(),
+ sceneDataSourceDelegator,
+ notificationStackScrollLayoutController,
+ keyguardMediaController,
+ lockscreenSmartspaceController,
+ logcatLogBuffer("GlanceableHubContainerControllerTest"),
+ )
}
- testableLooper = TestableLooper.get(this)
+ @Before
+ fun setUp() {
overrideResource(R.dimen.communal_right_edge_swipe_region_width, RIGHT_SWIPE_REGION_WIDTH)
overrideResource(R.dimen.communal_top_edge_swipe_region_height, TOP_SWIPE_REGION_WIDTH)
overrideResource(
R.dimen.communal_bottom_edge_swipe_region_height,
BOTTOM_SWIPE_REGION_WIDTH,
)
-
- // Make communal available so that communalInteractor.desiredScene accurately reflects
- // scene changes instead of just returning Blank.
- mSetFlagsRule.enableFlags(Flags.FLAG_COMMUNAL_HUB)
- with(kosmos.testScope) {
- launch { kosmos.setCommunalAvailable(true) }
- testScheduler.runCurrent()
- }
-
- initAndAttachContainerView()
+ runBlocking { kosmos.setCommunalAvailable(true) }
+ kosmos.initAndAttachContainerView()
}
@After
@@ -179,606 +159,531 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
@Test
fun initView_calledTwice_throwsException() =
- with(kosmos) {
- testScope.runTest {
- underTest =
- GlanceableHubContainerController(
- communalInteractor,
- kosmos.communalSettingsInteractor,
- communalViewModel,
- keyguardInteractor,
- kosmos.keyguardTransitionInteractor,
- shadeInteractor,
- powerManager,
- communalColors,
- ambientTouchComponentFactory,
- communalContent,
- kosmos.sceneDataSourceDelegator,
- kosmos.notificationStackScrollLayoutController,
- kosmos.keyguardMediaController,
- kosmos.lockscreenSmartspaceController,
- logcatLogBuffer("GlanceableHubContainerControllerTest"),
- )
+ kosmos.runTest {
+ val controller =
+ GlanceableHubContainerController(
+ communalInteractor,
+ communalSettingsInteractor,
+ mockCommunalViewModel,
+ keyguardInteractor,
+ keyguardTransitionInteractor,
+ shadeInteractor,
+ powerManager,
+ mock<CommunalColors>(),
+ ambientTouchComponentFactory,
+ mock<CommunalContent>(),
+ sceneDataSourceDelegator,
+ notificationStackScrollLayoutController,
+ keyguardMediaController,
+ lockscreenSmartspaceController,
+ logcatLogBuffer("GlanceableHubContainerControllerTest"),
+ )
- // First call succeeds.
- underTest.initView(context)
+ // First call succeeds.
+ controller.initView(context)
- // Second call throws.
- assertThrows(RuntimeException::class.java) { underTest.initView(context) }
- }
+ // Second call throws.
+ assertThrows(RuntimeException::class.java) { controller.initView(context) }
}
@Test
fun lifecycle_initializedAfterConstruction() =
- with(kosmos) {
- val underTest =
+ kosmos.runTest {
+ val controller =
GlanceableHubContainerController(
communalInteractor,
- kosmos.communalSettingsInteractor,
- communalViewModel,
+ communalSettingsInteractor,
+ mockCommunalViewModel,
keyguardInteractor,
- kosmos.keyguardTransitionInteractor,
+ keyguardTransitionInteractor,
shadeInteractor,
powerManager,
- communalColors,
+ mock<CommunalColors>(),
ambientTouchComponentFactory,
- communalContent,
- kosmos.sceneDataSourceDelegator,
- kosmos.notificationStackScrollLayoutController,
- kosmos.keyguardMediaController,
- kosmos.lockscreenSmartspaceController,
+ mock<CommunalContent>(),
+ sceneDataSourceDelegator,
+ notificationStackScrollLayoutController,
+ keyguardMediaController,
+ lockscreenSmartspaceController,
logcatLogBuffer("GlanceableHubContainerControllerTest"),
)
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.INITIALIZED)
+ assertThat(controller.lifecycle.currentState).isEqualTo(Lifecycle.State.INITIALIZED)
}
@Test
fun lifecycle_createdAfterViewCreated() =
- with(kosmos) {
- val underTest =
+ kosmos.runTest {
+ val controller =
GlanceableHubContainerController(
communalInteractor,
- kosmos.communalSettingsInteractor,
- communalViewModel,
+ communalSettingsInteractor,
+ mockCommunalViewModel,
keyguardInteractor,
- kosmos.keyguardTransitionInteractor,
+ keyguardTransitionInteractor,
shadeInteractor,
powerManager,
- communalColors,
+ mock<CommunalColors>(),
ambientTouchComponentFactory,
- communalContent,
- kosmos.sceneDataSourceDelegator,
- kosmos.notificationStackScrollLayoutController,
- kosmos.keyguardMediaController,
- kosmos.lockscreenSmartspaceController,
+ mock<CommunalContent>(),
+ sceneDataSourceDelegator,
+ notificationStackScrollLayoutController,
+ keyguardMediaController,
+ lockscreenSmartspaceController,
logcatLogBuffer("GlanceableHubContainerControllerTest"),
)
// Only initView without attaching a view as we don't want the flows to start collecting
// yet.
- underTest.initView(View(context))
+ controller.initView(View(context))
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.CREATED)
+ assertThat(controller.lifecycle.currentState).isEqualTo(Lifecycle.State.CREATED)
}
@Test
- fun lifecycle_startedAfterFlowsUpdate() {
- // Flows start collecting due to test setup, causing the state to advance to STARTED.
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
- }
+ fun lifecycle_startedAfterFlowsUpdate() =
+ kosmos.runTest {
+ // Flows start collecting due to test setup, causing the state to advance to STARTED.
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
+ }
@Test
fun lifecycle_resumedAfterCommunalShows() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
}
@Test
fun lifecycle_startedAfterCommunalCloses() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
- // Communal closes.
- goToScene(CommunalScenes.Blank)
+ // Communal closes.
+ goToScene(CommunalScenes.Blank)
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
}
@Test
fun lifecycle_startedAfterPrimaryBouncerShows() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
- // Bouncer is visible.
- fakeKeyguardBouncerRepository.setPrimaryShow(true)
- testableLooper.processAllMessages()
+ // Bouncer is visible.
+ fakeKeyguardBouncerRepository.setPrimaryShow(true)
+ testableLooper.processAllMessages()
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
}
@Test
fun lifecycle_startedAfterAlternateBouncerShows() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
- // Bouncer is visible.
- fakeKeyguardBouncerRepository.setAlternateVisible(true)
- testableLooper.processAllMessages()
+ // Bouncer is visible.
+ fakeKeyguardBouncerRepository.setAlternateVisible(true)
+ testableLooper.processAllMessages()
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
}
@Test
fun lifecycle_startedWhenEditActivityShowing() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
- // Edit activity is showing.
- communalInteractor.setEditActivityShowing(true)
- testableLooper.processAllMessages()
+ // Edit activity is showing.
+ communalInteractor.setEditActivityShowing(true)
+ testableLooper.processAllMessages()
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
}
@Test
fun lifecycle_startedWhenEditModeTransitionStarted() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
-
- // Leaving edit mode to return to the hub.
- fakeKeyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- from = KeyguardState.GONE,
- to = KeyguardState.GLANCEABLE_HUB,
- value = 1.0f,
- transitionState = TransitionState.RUNNING,
- )
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
+
+ // Leaving edit mode to return to the hub.
+ fakeKeyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.GONE,
+ to = KeyguardState.GLANCEABLE_HUB,
+ value = 1.0f,
+ transitionState = TransitionState.RUNNING,
)
- testableLooper.processAllMessages()
+ )
+ testableLooper.processAllMessages()
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
}
@Test
- fun lifecycle_createdAfterDisposeView() {
- // Container view disposed.
- underTest.disposeView()
+ fun lifecycle_createdAfterDisposeView() =
+ kosmos.runTest {
+ // Container view disposed.
+ underTest.disposeView()
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.CREATED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.CREATED)
+ }
@Test
fun lifecycle_startedAfterShadeShows() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
- // Shade shows up.
- shadeTestUtil.setQsExpansion(1.0f)
- testableLooper.processAllMessages()
+ // Shade shows up.
+ shadeTestUtil.setQsExpansion(1.0f)
+ testableLooper.processAllMessages()
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
}
@Test
fun lifecycle_doesNotResumeOnUserInteractivityOnceExpanded() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
-
- // Shade shows up.
- shadeTestUtil.setShadeExpansion(1.0f)
- testableLooper.processAllMessages()
- underTest.onTouchEvent(DOWN_EVENT)
- testableLooper.processAllMessages()
-
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
-
- // Shade starts collapsing.
- shadeTestUtil.setShadeExpansion(.5f)
- testableLooper.processAllMessages()
- underTest.onTouchEvent(DOWN_EVENT)
- testableLooper.processAllMessages()
-
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
-
- // Shade fully collpase, and then expand should with touch interaction should now
- // be resumed.
- shadeTestUtil.setShadeExpansion(0f)
- testableLooper.processAllMessages()
- shadeTestUtil.setShadeExpansion(.5f)
- testableLooper.processAllMessages()
- underTest.onTouchEvent(DOWN_EVENT)
- testableLooper.processAllMessages()
-
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
- }
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
+
+ // Shade shows up.
+ shadeTestUtil.setShadeExpansion(1.0f)
+ testableLooper.processAllMessages()
+ underTest.onTouchEvent(DOWN_EVENT)
+ testableLooper.processAllMessages()
+
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
+
+ // Shade starts collapsing.
+ shadeTestUtil.setShadeExpansion(.5f)
+ testableLooper.processAllMessages()
+ underTest.onTouchEvent(DOWN_EVENT)
+ testableLooper.processAllMessages()
+
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
+
+ // Shade fully collpase, and then expand should with touch interaction should now
+ // be resumed.
+ shadeTestUtil.setShadeExpansion(0f)
+ testableLooper.processAllMessages()
+ shadeTestUtil.setShadeExpansion(.5f)
+ testableLooper.processAllMessages()
+ underTest.onTouchEvent(DOWN_EVENT)
+ testableLooper.processAllMessages()
+
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
}
@Test
fun touchHandling_moveEventProcessedAfterCancel() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
-
- // Touch starts and ends.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
- assertThat(underTest.onTouchEvent(CANCEL_EVENT)).isTrue()
-
- // Up event is no longer processed
- assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse()
-
- // Move event can still be processed
- assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue()
- assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue()
- assertThat(underTest.onTouchEvent(UP_EVENT)).isTrue()
- }
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
+
+ // Touch starts and ends.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
+ assertThat(underTest.onTouchEvent(CANCEL_EVENT)).isTrue()
+
+ // Up event is no longer processed
+ assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse()
+
+ // Move event can still be processed
+ assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue()
+ assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue()
+ assertThat(underTest.onTouchEvent(UP_EVENT)).isTrue()
}
@Test
fun editMode_communalAvailable() =
- with(kosmos) {
- testScope.runTest {
- val available by collectLastValue(underTest.communalAvailable())
- setCommunalAvailable(false)
-
- assertThat(available).isFalse()
- communalInteractor.setEditModeOpen(true)
- assertThat(available).isTrue()
- }
+ kosmos.runTest {
+ val available by collectLastValue(underTest.communalAvailable())
+ setCommunalAvailable(false)
+
+ assertThat(available).isFalse()
+ communalInteractor.setEditModeOpen(true)
+ assertThat(available).isTrue()
}
@Test
@DisableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
fun gestureExclusionZone_setAfterInit() =
- with(kosmos) {
- testScope.runTest {
- goToScene(CommunalScenes.Communal)
-
- assertThat(containerView.systemGestureExclusionRects)
- .containsExactly(
- Rect(
- /* left= */ 0,
- /* top= */ TOP_SWIPE_REGION_WIDTH,
- /* right= */ CONTAINER_WIDTH,
- /* bottom= */ CONTAINER_HEIGHT - BOTTOM_SWIPE_REGION_WIDTH,
- )
+ kosmos.runTest {
+ goToScene(CommunalScenes.Communal)
+
+ assertThat(containerView.systemGestureExclusionRects)
+ .containsExactly(
+ Rect(
+ /* left= */ 0,
+ /* top= */ TOP_SWIPE_REGION_WIDTH,
+ /* right= */ CONTAINER_WIDTH,
+ /* bottom= */ CONTAINER_HEIGHT - BOTTOM_SWIPE_REGION_WIDTH,
)
- }
+ )
}
@Test
@EnableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
fun gestureExclusionZone_setAfterInit_fullSwipe() =
- with(kosmos) {
- testScope.runTest {
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ goToScene(CommunalScenes.Communal)
- assertThat(containerView.systemGestureExclusionRects).isEmpty()
- }
+ assertThat(containerView.systemGestureExclusionRects).isEmpty()
}
@Test
@DisableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
fun gestureExclusionZone_unsetWhenShadeOpen() =
- with(kosmos) {
- testScope.runTest {
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ goToScene(CommunalScenes.Communal)
- // Exclusion rect is set.
- assertThat(containerView.systemGestureExclusionRects).isNotEmpty()
+ // Exclusion rect is set.
+ assertThat(containerView.systemGestureExclusionRects).isNotEmpty()
- // Shade shows up.
- shadeTestUtil.setQsExpansion(1.0f)
- testableLooper.processAllMessages()
+ // Shade shows up.
+ shadeTestUtil.setQsExpansion(1.0f)
+ testableLooper.processAllMessages()
- // Exclusion rects are unset.
- assertThat(containerView.systemGestureExclusionRects).isEmpty()
- }
+ // Exclusion rects are unset.
+ assertThat(containerView.systemGestureExclusionRects).isEmpty()
}
@Test
@DisableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
fun gestureExclusionZone_unsetWhenBouncerOpen() =
- with(kosmos) {
- testScope.runTest {
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ goToScene(CommunalScenes.Communal)
- // Exclusion rect is set.
- assertThat(containerView.systemGestureExclusionRects).isNotEmpty()
+ // Exclusion rect is set.
+ assertThat(containerView.systemGestureExclusionRects).isNotEmpty()
- // Bouncer is visible.
- fakeKeyguardBouncerRepository.setPrimaryShow(true)
- testableLooper.processAllMessages()
+ // Bouncer is visible.
+ fakeKeyguardBouncerRepository.setPrimaryShow(true)
+ testableLooper.processAllMessages()
- // Exclusion rects are unset.
- assertThat(containerView.systemGestureExclusionRects).isEmpty()
- }
+ // Exclusion rects are unset.
+ assertThat(containerView.systemGestureExclusionRects).isEmpty()
}
@Test
@DisableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
fun gestureExclusionZone_unsetWhenHubClosed() =
- with(kosmos) {
- testScope.runTest {
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ goToScene(CommunalScenes.Communal)
- // Exclusion rect is set.
- assertThat(containerView.systemGestureExclusionRects).isNotEmpty()
+ // Exclusion rect is set.
+ assertThat(containerView.systemGestureExclusionRects).isNotEmpty()
- // Leave the hub.
- goToScene(CommunalScenes.Blank)
+ // Leave the hub.
+ goToScene(CommunalScenes.Blank)
- // Exclusion rect is unset.
- assertThat(containerView.systemGestureExclusionRects).isEmpty()
- }
+ // Exclusion rect is unset.
+ assertThat(containerView.systemGestureExclusionRects).isEmpty()
}
@Test
fun fullScreenSwipeGesture_doNotProcessTouchesInNotificationStack() =
- with(kosmos) {
- testScope.runTest {
- // Communal is closed.
- goToScene(CommunalScenes.Blank)
- whenever(
- notificationStackScrollLayoutController.isBelowLastNotification(
- any(),
- any(),
- )
- )
- .thenReturn(false)
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- }
+ kosmos.runTest {
+ // Communal is closed.
+ goToScene(CommunalScenes.Blank)
+ whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any()))
+ .thenReturn(false)
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
}
@Test
fun fullScreenSwipeGesture_doNotProcessTouchesInUmo() =
- with(kosmos) {
- testScope.runTest {
- // Communal is closed.
- goToScene(CommunalScenes.Blank)
- whenever(keyguardMediaController.isWithinMediaViewBounds(any(), any()))
- .thenReturn(true)
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- }
+ kosmos.runTest {
+ // Communal is closed.
+ goToScene(CommunalScenes.Blank)
+ whenever(keyguardMediaController.isWithinMediaViewBounds(any(), any())).thenReturn(true)
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
}
@Test
fun fullScreenSwipeGesture_doNotProcessTouchesInSmartspace() =
- with(kosmos) {
- testScope.runTest {
- // Communal is closed.
- goToScene(CommunalScenes.Blank)
- whenever(lockscreenSmartspaceController.isWithinSmartspaceBounds(any(), any()))
- .thenReturn(true)
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- }
+ kosmos.runTest {
+ // Communal is closed.
+ goToScene(CommunalScenes.Blank)
+ whenever(lockscreenSmartspaceController.isWithinSmartspaceBounds(any(), any()))
+ .thenReturn(true)
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
}
@Test
fun onTouchEvent_hubOpen_touchesDispatched() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
-
- // Touch event is sent to the container view.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
- verify(containerView).onTouchEvent(DOWN_EVENT)
- assertThat(underTest.onTouchEvent(UP_EVENT)).isTrue()
- verify(containerView).onTouchEvent(UP_EVENT)
- }
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
+
+ // Touch event is sent to the container view.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
+ verify(containerView).onTouchEvent(DOWN_EVENT)
+ assertThat(underTest.onTouchEvent(UP_EVENT)).isTrue()
+ verify(containerView).onTouchEvent(UP_EVENT)
}
@Test
fun onTouchEvent_editActivityShowing_touchesConsumedButNotDispatched() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
-
- // Transitioning to or from edit mode.
- communalInteractor.setEditActivityShowing(true)
- testableLooper.processAllMessages()
-
- // onTouchEvent returns true to consume the touch, but it is not sent to the
- // container view.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
- verify(containerView, never()).onTouchEvent(any())
- }
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
+
+ // Transitioning to or from edit mode.
+ communalInteractor.setEditActivityShowing(true)
+ testableLooper.processAllMessages()
+
+ // onTouchEvent returns true to consume the touch, but it is not sent to the
+ // container view.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
+ verify(containerView, never()).onTouchEvent(any())
}
@Test
fun onTouchEvent_editModeTransitionStarted_touchesConsumedButNotDispatched() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
-
- // Leaving edit mode to return to the hub.
- fakeKeyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- from = KeyguardState.GONE,
- to = KeyguardState.GLANCEABLE_HUB,
- value = 1.0f,
- transitionState = TransitionState.RUNNING,
- )
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
+
+ // Leaving edit mode to return to the hub.
+ fakeKeyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.GONE,
+ to = KeyguardState.GLANCEABLE_HUB,
+ value = 1.0f,
+ transitionState = TransitionState.RUNNING,
)
- testableLooper.processAllMessages()
+ )
+ testableLooper.processAllMessages()
- // onTouchEvent returns true to consume the touch, but it is not sent to the
- // container view.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
- verify(containerView, never()).onTouchEvent(any())
- }
+ // onTouchEvent returns true to consume the touch, but it is not sent to the
+ // container view.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
+ verify(containerView, never()).onTouchEvent(any())
}
@Test
fun onTouchEvent_shadeInteracting_movesNotDispatched() =
- with(kosmos) {
- testScope.runTest {
- `whenever`(communalViewModel.swipeToHubEnabled()).thenReturn(true)
- // On lockscreen.
- goToScene(CommunalScenes.Blank)
- whenever(
- notificationStackScrollLayoutController.isBelowLastNotification(
- any(),
- any(),
- )
- )
- .thenReturn(true)
+ kosmos.runTest {
+ swipeToHubEnabled.value = true
- // Touches not consumed by default but are received by containerView.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- verify(containerView).onTouchEvent(DOWN_EVENT)
+ // On lockscreen.
+ goToScene(CommunalScenes.Blank)
+ whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any()))
+ .thenReturn(true)
- // User is interacting with shade on lockscreen.
- shadeTestUtil.setLockscreenShadeTracking(true)
- testableLooper.processAllMessages()
+ // Touches not consumed by default but are received by containerView.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
+ verify(containerView).onTouchEvent(DOWN_EVENT)
- // A move event is ignored while the user is already interacting.
- assertThat(underTest.onTouchEvent(MOVE_EVENT)).isFalse()
- verify(containerView, never()).onTouchEvent(MOVE_EVENT)
+ // User is interacting with shade on lockscreen.
+ shadeTestUtil.setLockscreenShadeTracking(true)
+ testableLooper.processAllMessages()
- // An up event is still delivered.
- assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse()
- verify(containerView).onTouchEvent(UP_EVENT)
- }
+ // A move event is ignored while the user is already interacting.
+ assertThat(underTest.onTouchEvent(MOVE_EVENT)).isFalse()
+ verify(containerView, never()).onTouchEvent(MOVE_EVENT)
+
+ // An up event is still delivered.
+ assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse()
+ verify(containerView).onTouchEvent(UP_EVENT)
}
@Test
fun onTouchEvent_shadeExpanding_touchesNotDispatched() =
- with(kosmos) {
- testScope.runTest {
- // On lockscreen.
- goToScene(CommunalScenes.Blank)
- whenever(
- notificationStackScrollLayoutController.isBelowLastNotification(
- any(),
- any(),
- )
- )
- .thenReturn(true)
+ kosmos.runTest {
+ // On lockscreen.
+ goToScene(CommunalScenes.Blank)
+ whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any()))
+ .thenReturn(true)
- // Shade is open slightly.
- shadeTestUtil.setShadeExpansion(0.01f)
- testableLooper.processAllMessages()
+ // Shade is open slightly.
+ shadeTestUtil.setShadeExpansion(0.01f)
+ testableLooper.processAllMessages()
- // Touches are not consumed.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- verify(containerView, never()).onTouchEvent(DOWN_EVENT)
- }
+ // Touches are not consumed.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
+ verify(containerView, never()).onTouchEvent(DOWN_EVENT)
}
@Test
fun onTouchEvent_qsExpanding_touchesNotDispatched() =
- with(kosmos) {
- testScope.runTest {
- // On lockscreen.
- goToScene(CommunalScenes.Blank)
- whenever(
- notificationStackScrollLayoutController.isBelowLastNotification(
- any(),
- any(),
- )
- )
- .thenReturn(true)
+ kosmos.runTest {
+ // On lockscreen.
+ goToScene(CommunalScenes.Blank)
+ whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any()))
+ .thenReturn(true)
- // Shade is open slightly.
- shadeTestUtil.setQsExpansion(0.01f)
- testableLooper.processAllMessages()
+ // Shade is open slightly.
+ shadeTestUtil.setQsExpansion(0.01f)
+ testableLooper.processAllMessages()
- // Touches are not consumed.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- verify(containerView, never()).onTouchEvent(DOWN_EVENT)
- }
+ // Touches are not consumed.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
+ verify(containerView, never()).onTouchEvent(DOWN_EVENT)
}
@Test
fun onTouchEvent_bouncerInteracting_movesNotDispatched() =
- with(kosmos) {
- testScope.runTest {
- `whenever`(communalViewModel.swipeToHubEnabled()).thenReturn(true)
- // On lockscreen.
- goToScene(CommunalScenes.Blank)
- whenever(
- notificationStackScrollLayoutController.isBelowLastNotification(
- any(),
- any(),
- )
- )
- .thenReturn(true)
+ kosmos.runTest {
+ swipeToHubEnabled.value = true
+ // On lockscreen.
+ goToScene(CommunalScenes.Blank)
+ whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any()))
+ .thenReturn(true)
- // Touches not consumed by default but are received by containerView.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- verify(containerView).onTouchEvent(DOWN_EVENT)
+ // Touches not consumed by default but are received by containerView.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
+ verify(containerView).onTouchEvent(DOWN_EVENT)
- // User is interacting with bouncer on lockscreen.
- fakeKeyguardBouncerRepository.setPrimaryShow(true)
- testableLooper.processAllMessages()
+ // User is interacting with bouncer on lockscreen.
+ fakeKeyguardBouncerRepository.setPrimaryShow(true)
+ testableLooper.processAllMessages()
- // A move event is ignored while the user is already interacting.
- assertThat(underTest.onTouchEvent(MOVE_EVENT)).isFalse()
- verify(containerView, never()).onTouchEvent(MOVE_EVENT)
+ // A move event is ignored while the user is already interacting.
+ assertThat(underTest.onTouchEvent(MOVE_EVENT)).isFalse()
+ verify(containerView, never()).onTouchEvent(MOVE_EVENT)
- // An up event is still delivered.
- assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse()
- verify(containerView).onTouchEvent(UP_EVENT)
- }
+ // An up event is still delivered.
+ assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse()
+ verify(containerView).onTouchEvent(UP_EVENT)
}
@EnableFlags(FLAG_GLANCEABLE_HUB_V2)
@Test
fun onTouchEvent_onLockscreenAndGlanceableHubV2_touchIgnored() =
- with(kosmos) {
- testScope.runTest {
- kosmos.setCommunalV2ConfigEnabled(true)
+ kosmos.runTest {
+ swipeToHubEnabled.value = false
+ setCommunalV2ConfigEnabled(true)
- // On lockscreen.
- goToScene(CommunalScenes.Blank)
+ // On lockscreen.
+ goToScene(CommunalScenes.Blank)
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- verify(containerView, never()).onTouchEvent(DOWN_EVENT)
- }
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
+ verify(containerView, never()).onTouchEvent(DOWN_EVENT)
}
@Test
- fun disposeView_destroysTouchMonitor() {
- clearInvocations(touchMonitor)
+ fun disposeView_destroysTouchMonitor() =
+ kosmos.runTest {
+ clearInvocations(touchMonitor)
- underTest.disposeView()
+ underTest.disposeView()
- verify(touchMonitor).destroy()
- }
+ verify(touchMonitor).destroy()
+ }
- private fun initAndAttachContainerView() {
+ private fun Kosmos.initAndAttachContainerView() {
val mockInsets =
mock<WindowInsets> {
on { getInsets(WindowInsets.Type.systemGestures()) } doReturn FAKE_INSETS
@@ -802,8 +707,8 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
testableLooper.processAllMessages()
}
- private suspend fun goToScene(scene: SceneKey) {
- communalRepository.changeScene(scene)
+ private suspend fun Kosmos.goToScene(scene: SceneKey) {
+ fakeCommunalSceneRepository.changeScene(scene)
if (scene == CommunalScenes.Communal) {
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt
index fcbf0fe9a37a..510d6fe2b776 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt
@@ -17,19 +17,23 @@
package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel
import android.platform.test.annotations.EnableFlags
+import androidx.compose.runtime.snapshots.Snapshot
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.lifecycle.activateIn
import com.android.systemui.media.controls.data.repository.mediaFilterRepository
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel
-import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId
import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips
+import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -37,22 +41,41 @@ import org.junit.runner.RunWith
@EnableFlags(StatusBarPopupChips.FLAG_NAME)
@RunWith(AndroidJUnit4::class)
class StatusBarPopupChipsViewModelTest : SysuiTestCase() {
- private val kosmos = testKosmos()
- private val testScope = kosmos.testScope
- private val mediaFilterRepository = kosmos.mediaFilterRepository
- private val underTest = kosmos.statusBarPopupChipsViewModel
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+ private val underTest = kosmos.statusBarPopupChipsViewModelFactory.create()
+
+ @Before
+ fun setUp() {
+ underTest.activateIn(kosmos.testScope)
+ }
@Test
fun shownPopupChips_allHidden_empty() =
- testScope.runTest {
- val shownPopupChips by collectLastValue(underTest.shownPopupChips)
+ kosmos.runTest {
+ val shownPopupChips = underTest.shownPopupChips
assertThat(shownPopupChips).isEmpty()
}
@Test
fun shownPopupChips_activeMedia_restHidden_mediaControlChipShown() =
- testScope.runTest {
- val shownPopupChips by collectLastValue(underTest.shownPopupChips)
+ kosmos.runTest {
+ val shownPopupChips = underTest.shownPopupChips
+ val userMedia = MediaData(active = true, song = "test")
+ val instanceId = userMedia.instanceId
+
+ mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
+ mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
+
+ Snapshot.takeSnapshot {
+ assertThat(shownPopupChips).hasSize(1)
+ assertThat(shownPopupChips.first().chipId).isEqualTo(PopupChipId.MediaControl)
+ }
+ }
+
+ @Test
+ fun shownPopupChips_mediaChipToggled_popupShown() =
+ kosmos.runTest {
+ val shownPopupChips = underTest.shownPopupChips
val userMedia = MediaData(active = true, song = "test")
val instanceId = userMedia.instanceId
@@ -60,7 +83,13 @@ class StatusBarPopupChipsViewModelTest : SysuiTestCase() {
mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
- assertThat(shownPopupChips).hasSize(1)
- assertThat(shownPopupChips!!.first().chipId).isEqualTo(PopupChipId.MediaControl)
+ Snapshot.takeSnapshot {
+ assertThat(shownPopupChips).hasSize(1)
+ val mediaChip = shownPopupChips.first()
+ assertThat(mediaChip.isPopupShown).isFalse()
+
+ mediaChip.showPopup.invoke()
+ assertThat(shownPopupChips.first().isPopupShown).isTrue()
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index 8d05ea16cfa6..44392420da49 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -465,9 +465,9 @@ public class VolumeDialogImplTest extends SysuiTestCase {
public void notificationVolumeSeparated_theRingerIconChangesToSpeakerIcon() {
// already separated. assert icon is new based on res id
assertEquals(mDialog.mVolumeRingerIconDrawableId,
- R.drawable.ic_speaker_on);
+ R.drawable.ic_legacy_speaker_on);
assertEquals(mDialog.mVolumeRingerMuteIconDrawableId,
- R.drawable.ic_speaker_mute);
+ R.drawable.ic_legacy_speaker_mute);
}
@Test
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt
index 93502f365202..b876095fefe5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt
@@ -17,13 +17,14 @@
package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.testScope
import com.android.systemui.statusbar.featurepods.media.ui.viewmodel.mediaControlChipViewModel
-val Kosmos.statusBarPopupChipsViewModel: StatusBarPopupChipsViewModel by
+private val Kosmos.statusBarPopupChipsViewModel: StatusBarPopupChipsViewModel by
+ Kosmos.Fixture { StatusBarPopupChipsViewModel(mediaControlChip = mediaControlChipViewModel) }
+
+val Kosmos.statusBarPopupChipsViewModelFactory by
Kosmos.Fixture {
- StatusBarPopupChipsViewModel(
- testScope.backgroundScope,
- mediaControlChipViewModel = mediaControlChipViewModel,
- )
+ object : StatusBarPopupChipsViewModel.Factory {
+ override fun create(): StatusBarPopupChipsViewModel = statusBarPopupChipsViewModel
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
index fbada934c9d4..a97c651ba426 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
@@ -29,7 +29,7 @@ import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.shareToAppChipViewModel
import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
import com.android.systemui.statusbar.events.domain.interactor.systemStatusEventAnimationInteractor
-import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.statusBarPopupChipsViewModel
+import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.statusBarPopupChipsViewModelFactory
import com.android.systemui.statusbar.layout.ui.viewmodel.multiDisplayStatusBarContentInsetsViewModelStore
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
@@ -59,7 +59,7 @@ var Kosmos.homeStatusBarViewModel: HomeStatusBarViewModel by
shadeInteractor,
shareToAppChipViewModel,
ongoingActivityChipsViewModel,
- statusBarPopupChipsViewModel,
+ statusBarPopupChipsViewModelFactory,
systemStatusEventAnimationInteractor,
multiDisplayStatusBarContentInsetsViewModelStore,
backgroundScope,
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodMethodCallLogger.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodMethodCallLogger.java
new file mode 100644
index 000000000000..7ee9d7a8a5c6
--- /dev/null
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodMethodCallLogger.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.platform.test.ravenwood;
+
+import com.android.ravenwood.RavenwoodRuntimeNative;
+
+import java.io.PrintStream;
+import java.util.HashSet;
+import java.util.Objects;
+
+/**
+ * Provides a method call hook that prints almost all (see below) the framework methods being
+ * called with indentation.
+ *
+ * We don't log methods that are trivial, uninteresting, or would be too noisy.
+ * e.g. we don't want to log any logging related methods, or collection APIs.
+ *
+ */
+public class RavenwoodMethodCallLogger {
+ private RavenwoodMethodCallLogger() {
+ }
+
+ /** We don't want to log anything before ravenwood is initialized. This flag controls it.*/
+ private static volatile boolean sEnabled = false;
+
+ private static volatile PrintStream sOut = System.out;
+
+ /** Return the current thread's call nest level. */
+ private static int getNestLevel() {
+ return Thread.currentThread().getStackTrace().length;
+ }
+
+ private static class ThreadInfo {
+ /**
+ * We save the current thread's nest call level here and use that as the initial level.
+ * We do it because otherwise the nest level would be too deep by the time test
+ * starts.
+ */
+ public final int mInitialNestLevel = getNestLevel();
+
+ /**
+ * A nest level where shouldLog() returned false.
+ * Once it's set, we ignore all calls deeper than this.
+ */
+ public int mDisabledNestLevel = Integer.MAX_VALUE;
+ }
+
+ private static final ThreadLocal<ThreadInfo> sThreadInfo = new ThreadLocal<>() {
+ @Override
+ protected ThreadInfo initialValue() {
+ return new ThreadInfo();
+ }
+ };
+
+ /** Classes that should be logged. Uses a map for fast lookup. */
+ private static final HashSet<Class> sIgnoreClasses = new HashSet<>();
+ static {
+ // The following classes are not interesting...
+ sIgnoreClasses.add(android.util.Log.class);
+ sIgnoreClasses.add(android.util.Slog.class);
+ sIgnoreClasses.add(android.util.EventLog.class);
+ sIgnoreClasses.add(android.util.TimingsTraceLog.class);
+
+ sIgnoreClasses.add(android.util.SparseArray.class);
+ sIgnoreClasses.add(android.util.SparseIntArray.class);
+ sIgnoreClasses.add(android.util.SparseLongArray.class);
+ sIgnoreClasses.add(android.util.SparseBooleanArray.class);
+ sIgnoreClasses.add(android.util.SparseDoubleArray.class);
+ sIgnoreClasses.add(android.util.SparseSetArray.class);
+ sIgnoreClasses.add(android.util.SparseArrayMap.class);
+ sIgnoreClasses.add(android.util.LongSparseArray.class);
+ sIgnoreClasses.add(android.util.LongSparseLongArray.class);
+ sIgnoreClasses.add(android.util.LongArray.class);
+
+ sIgnoreClasses.add(android.text.FontConfig.class);
+
+ sIgnoreClasses.add(android.os.SystemClock.class);
+ sIgnoreClasses.add(android.os.Trace.class);
+ sIgnoreClasses.add(android.os.LocaleList.class);
+ sIgnoreClasses.add(android.os.Build.class);
+ sIgnoreClasses.add(android.os.SystemProperties.class);
+
+ sIgnoreClasses.add(com.android.internal.util.Preconditions.class);
+
+ sIgnoreClasses.add(android.graphics.FontListParser.class);
+ sIgnoreClasses.add(android.graphics.ColorSpace.class);
+
+ sIgnoreClasses.add(android.graphics.fonts.FontStyle.class);
+ sIgnoreClasses.add(android.graphics.fonts.FontVariationAxis.class);
+
+ sIgnoreClasses.add(com.android.internal.compat.CompatibilityChangeInfo.class);
+ sIgnoreClasses.add(com.android.internal.os.LoggingPrintStream.class);
+
+ sIgnoreClasses.add(android.os.ThreadLocalWorkSource.class);
+
+ // Following classes *may* be interesting for some purposes, but the initialization is
+ // too noisy...
+ sIgnoreClasses.add(android.graphics.fonts.SystemFonts.class);
+
+ }
+
+ /**
+ * Return if a class should be ignored. Uses {link #sIgnoreCladsses}, but
+ * we ignore more classes.
+ */
+ private static boolean shouldIgnoreClass(Class<?> clazz) {
+ if (sIgnoreClasses.contains(clazz)) {
+ return true;
+ }
+ // Let's also ignore collection-ish classes in android.util.
+ if (java.util.Collection.class.isAssignableFrom(clazz)
+ || java.util.Map.class.isAssignableFrom(clazz)
+ ) {
+ if ("android.util".equals(clazz.getPackageName())) {
+ return true;
+ }
+ return false;
+ }
+
+ switch (clazz.getSimpleName()) {
+ case "EventLogTags":
+ return false;
+ }
+
+ // Following are classes that can't be referred to here directly.
+ // e.g. AndroidPrintStream is package-private, so we can't use its "class" here.
+ switch (clazz.getName()) {
+ case "com.android.internal.os.AndroidPrintStream":
+ return false;
+ }
+ return false;
+ }
+
+ private static boolean shouldLog(
+ Class<?> methodClass,
+ String methodName,
+ @SuppressWarnings("UnusedVariable") String methodDescriptor
+ ) {
+ // Should we ignore this class?
+ if (shouldIgnoreClass(methodClass)) {
+ return false;
+ }
+ // Is it a nested class in a class that should be ignored?
+ var host = methodClass.getNestHost();
+ if (host != methodClass && shouldIgnoreClass(host)) {
+ return false;
+ }
+
+ var className = methodClass.getName();
+
+ // Ad-hoc ignore list. They'd be too noisy.
+ if ("create".equals(methodName)
+ // We may apply jarjar, so use endsWith().
+ && className.endsWith("com.android.server.compat.CompatConfig")) {
+ return false;
+ }
+
+ var pkg = methodClass.getPackageName();
+ if (pkg.startsWith("android.icu")) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Call this to enable logging.
+ */
+ public static void enable(PrintStream out) {
+ sEnabled = true;
+ sOut = Objects.requireNonNull(out);
+
+ // It's called from the test thread (Java's main thread). Because we're already
+ // in deep nest calls, we initialize the initial nest level here.
+ sThreadInfo.get();
+ }
+
+ /** Actual method hook entry point.*/
+ public static void logMethodCall(
+ Class<?> methodClass,
+ String methodName,
+ String methodDescriptor
+ ) {
+ if (!sEnabled) {
+ return;
+ }
+ final var ti = sThreadInfo.get();
+ final int nestLevel = getNestLevel() - ti.mInitialNestLevel;
+
+ // Once shouldLog() returns false, we just ignore all deeper calls.
+ if (ti.mDisabledNestLevel < nestLevel) {
+ return; // Still ignore.
+ }
+ final boolean shouldLog = shouldLog(methodClass, methodName, methodDescriptor);
+
+ if (!shouldLog) {
+ ti.mDisabledNestLevel = nestLevel;
+ return;
+ }
+ ti.mDisabledNestLevel = Integer.MAX_VALUE;
+
+ var out = sOut;
+ out.print("# [");
+ out.print(RavenwoodRuntimeNative.gettid());
+ out.print(": ");
+ out.print(Thread.currentThread().getName());
+ out.print("]: ");
+ out.print("[@");
+ out.printf("%2d", nestLevel);
+ out.print("] ");
+ for (int i = 0; i < nestLevel; i++) {
+ out.print(" ");
+ }
+ out.println(methodClass.getName() + "." + methodName + methodDescriptor);
+ }
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index 7af03ed2e6c8..ae88bb234e9d 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
@@ -23,7 +23,6 @@ import static android.platform.test.ravenwood.RavenwoodSystemServer.ANDROID_PACK
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_EMPTY_RESOURCES_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_INST_RESOURCE_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK;
-import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERSION_JAVA_SYSPROP;
import static com.android.ravenwood.common.RavenwoodCommonUtils.parseNullableInt;
import static com.android.ravenwood.common.RavenwoodCommonUtils.withDefault;
@@ -103,6 +102,10 @@ public class RavenwoodRuntimeEnvironmentController {
private RavenwoodRuntimeEnvironmentController() {
}
+ private static final PrintStream sStdOut = System.out;
+ @SuppressWarnings("UnusedVariable")
+ private static final PrintStream sStdErr = System.err;
+
private static final String MAIN_THREAD_NAME = "RavenwoodMain";
private static final String LIBRAVENWOOD_INITIALIZER_NAME = "ravenwood_initializer";
private static final String RAVENWOOD_NATIVE_RUNTIME_NAME = "ravenwood_runtime";
@@ -212,9 +215,9 @@ public class RavenwoodRuntimeEnvironmentController {
}
private static void globalInitInner() throws IOException {
- if (RAVENWOOD_VERBOSE_LOGGING) {
- Log.v(TAG, "globalInit() called here...", new RuntimeException("NOT A CRASH"));
- }
+ // We haven't initialized liblog yet, so directly write to System.out here.
+ RavenwoodCommonUtils.log(TAG, "globalInitInner()");
+
if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) {
Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler);
}
@@ -234,9 +237,6 @@ public class RavenwoodRuntimeEnvironmentController {
dumpJavaProperties();
dumpOtherInfo();
- // We haven't initialized liblog yet, so directly write to System.out here.
- RavenwoodCommonUtils.log(TAG, "globalInitInner()");
-
// Make sure libravenwood_runtime is loaded.
System.load(RavenwoodCommonUtils.getJniLibraryPath(RAVENWOOD_NATIVE_RUNTIME_NAME));
@@ -261,6 +261,9 @@ public class RavenwoodRuntimeEnvironmentController {
// Make sure libandroid_runtime is loaded.
RavenwoodNativeLoader.loadFrameworkNativeCode();
+ // Start method logging.
+ RavenwoodMethodCallLogger.enable(sStdOut);
+
// Touch some references early to ensure they're <clinit>'ed
Objects.requireNonNull(Build.TYPE);
Objects.requireNonNull(Build.VERSION.SDK);
diff --git a/ravenwood/texts/ravenwood-standard-options.txt b/ravenwood/texts/ravenwood-standard-options.txt
index 91fd9283aff2..0edc348fc7f2 100644
--- a/ravenwood/texts/ravenwood-standard-options.txt
+++ b/ravenwood/texts/ravenwood-standard-options.txt
@@ -9,8 +9,10 @@
# Uncomment below lines to enable each feature.
+# Enable method call hook.
#--default-method-call-hook
-# com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+# android.platform.test.ravenwood.RavenwoodMethodCallLogger.logMethodCall
+
#--default-class-load-hook
# com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
diff --git a/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java b/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
index 78fd8f7f960a..145325ccc809 100644
--- a/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
+++ b/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
@@ -18,6 +18,7 @@ package com.android.hoststubgen.hosthelper;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.Arrays;
/**
* Utilities used in the host side test environment.
@@ -36,9 +37,14 @@ public class HostTestUtils {
public static final String CLASS_INTERNAL_NAME = getInternalName(HostTestUtils.class);
+ /** If true, we skip all method call hooks */
+ private static final boolean SKIP_METHOD_CALL_HOOK = "1".equals(System.getenv(
+ "HOSTTEST_SKIP_METHOD_CALL_HOOK"));
+
/** If true, we won't print method call log. */
- private static final boolean SKIP_METHOD_LOG = "1".equals(System.getenv(
- "HOSTTEST_SKIP_METHOD_LOG"));
+ private static final boolean SKIP_METHOD_LOG =
+ "1".equals(System.getenv("HOSTTEST_SKIP_METHOD_LOG"))
+ || "1".equals(System.getenv("RAVENWOOD_NO_METHOD_LOG"));
/** If true, we won't print class load log. */
private static final boolean SKIP_CLASS_LOG = "1".equals(System.getenv(
@@ -65,6 +71,9 @@ public class HostTestUtils {
+ "consider using Mockito; more details at go/ravenwood-docs");
}
+ private static final Class<?>[] sMethodHookArgTypes =
+ { Class.class, String.class, String.class};
+
/**
* Trampoline method for method-call-hook.
*/
@@ -74,16 +83,22 @@ public class HostTestUtils {
String methodDescriptor,
String callbackMethod
) {
- callStaticMethodByName(callbackMethod, "method call hook", methodClass,
- methodName, methodDescriptor);
+ if (SKIP_METHOD_CALL_HOOK) {
+ return;
+ }
+ callStaticMethodByName(callbackMethod, "method call hook", sMethodHookArgTypes,
+ methodClass, methodName, methodDescriptor);
}
/**
+ * Simple implementation of method call hook, which just prints the information of the
+ * method. This is just for basic testing. We don't use it in Ravenwood, because this would
+ * be way too noisy as it prints every single method, even trivial ones. (iterator methods,
+ * etc..)
+ *
* I can be used as
* {@code --default-method-call-hook
* com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall}.
- *
- * It logs every single methods called.
*/
public static void logMethodCall(
Class<?> methodClass,
@@ -97,6 +112,8 @@ public class HostTestUtils {
+ methodName + methodDescriptor);
}
+ private static final Class<?>[] sClassLoadHookArgTypes = { Class.class };
+
/**
* Called when any top level class (not nested classes) in the impl jar is loaded.
*
@@ -111,11 +128,12 @@ public class HostTestUtils {
logPrintStream.println("! Class loaded: " + loadedClass.getCanonicalName()
+ " calling hook " + callbackMethod);
- callStaticMethodByName(callbackMethod, "class load hook", loadedClass);
+ callStaticMethodByName(
+ callbackMethod, "class load hook", sClassLoadHookArgTypes, loadedClass);
}
private static void callStaticMethodByName(String classAndMethodName,
- String description, Object... args) {
+ String description, Class<?>[] argTypes, Object... args) {
// Forward the call to callbackMethod.
final int lastPeriod = classAndMethodName.lastIndexOf(".");
@@ -145,19 +163,14 @@ public class HostTestUtils {
className));
}
- Class<?>[] argTypes = new Class[args.length];
- for (int i = 0; i < args.length; i++) {
- argTypes[i] = args[i].getClass();
- }
-
Method method = null;
try {
method = clazz.getMethod(methodName, argTypes);
} catch (Exception e) {
throw new HostTestException(String.format(
"Unable to find %s: class %s doesn't have method %s"
- + " (method must take exactly one parameter of type Class,"
- + " and public static)",
+ + " Method must be public static, and arg types must be: "
+ + Arrays.toString(argTypes),
description, className, methodName), e);
}
if (!(Modifier.isPublic(method.getModifiers())
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index 985947575a86..3340990f4765 100644
--- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -145,6 +145,7 @@ class HostStubGen(val options: HostStubGenOptions) {
// Inject default hooks from options.
filter = DefaultHookInjectingFilter(
+ allClasses,
options.defaultClassLoadHook.get,
options.defaultMethodCallHook.get,
filter
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
index d771003a955d..aaf49c154a17 100644
--- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
+++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
@@ -16,8 +16,11 @@
package com.android.hoststubgen.filters
import com.android.hoststubgen.addLists
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.isAnnotation
class DefaultHookInjectingFilter(
+ val classes: ClassNodes,
defaultClassLoadHook: String?,
defaultMethodCallHook: String?,
fallback: OutputFilter
@@ -36,8 +39,30 @@ class DefaultHookInjectingFilter(
private val defaultClassLoadHookAsList: List<String> = toSingleList(defaultClassLoadHook)
private val defaultMethodCallHookAsList: List<String> = toSingleList(defaultMethodCallHook)
+ private fun shouldInject(className: String): Boolean {
+ // Let's not inject default hooks to annotation classes or inner classes of an annotation
+ // class, because these methods could be called at the class load time, which
+ // is very confusing, and usually not useful.
+
+ val cn = classes.findClass(className) ?: return false
+ if (cn.isAnnotation()) {
+ return false
+ }
+ cn.nestHostClass?.let { nestHostClass ->
+ val nestHost = classes.findClass(nestHostClass) ?: return false
+ if (nestHost.isAnnotation()) {
+ return false
+ }
+ }
+ return true
+ }
+
override fun getClassLoadHooks(className: String): List<String> {
- return addLists(super.getClassLoadHooks(className), defaultClassLoadHookAsList)
+ val s = super.getClassLoadHooks(className)
+ if (!shouldInject(className)) {
+ return s
+ }
+ return addLists(s, defaultClassLoadHookAsList)
}
override fun getMethodCallHooks(
@@ -45,9 +70,23 @@ class DefaultHookInjectingFilter(
methodName: String,
descriptor: String
): List<String> {
- return addLists(
- super.getMethodCallHooks(className, methodName, descriptor),
- defaultMethodCallHookAsList,
- )
+ val s = super.getMethodCallHooks(className, methodName, descriptor)
+ if (!shouldInject(className)) {
+ return s
+ }
+ // Don't hook Object methods.
+ if (methodName == "finalize" && descriptor == "()V") {
+ return s
+ }
+ if (methodName == "toString" && descriptor == "()Ljava/lang/String;") {
+ return s
+ }
+ if (methodName == "equals" && descriptor == "(Ljava/lang/Object;)Z") {
+ return s
+ }
+ if (methodName == "hashCode" && descriptor == "()I") {
+ return s
+ }
+ return addLists(s, defaultMethodCallHookAsList)
}
-} \ No newline at end of file
+}
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
index 49769e648bbf..fb225ff1aa21 100644
--- a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
@@ -6,17 +6,9 @@ public interface android.hosttest.annotation.HostSideTestClassLoadHook extends j
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestClassLoadHook
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 2, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestClassLoadHook
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
-
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
public abstract java.lang.String value();
descriptor: ()Ljava/lang/String;
flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
@@ -44,16 +36,9 @@ public interface android.hosttest.annotation.HostSideTestKeep extends java.lang.
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestKeep
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestKeep
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestKeep.java"
RuntimeVisibleAnnotations:
@@ -75,16 +60,9 @@ public interface android.hosttest.annotation.HostSideTestRedirect extends java.l
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestRedirect
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestRedirect
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestRedirect.java"
RuntimeVisibleAnnotations:
@@ -106,17 +84,9 @@ public interface android.hosttest.annotation.HostSideTestRedirectionClass extend
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestRedirectionClass
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 2, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestRedirectionClass
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
-
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
public abstract java.lang.String value();
descriptor: ()Ljava/lang/String;
flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
@@ -144,16 +114,9 @@ public interface android.hosttest.annotation.HostSideTestRemove extends java.lan
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestRemove
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestRemove
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestRemove.java"
RuntimeVisibleAnnotations:
@@ -175,16 +138,9 @@ public interface android.hosttest.annotation.HostSideTestStaticInitializerKeep e
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestStaticInitializerKeep
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestStaticInitializerKeep
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestStaticInitializerKeep.java"
RuntimeVisibleAnnotations:
@@ -206,17 +162,9 @@ public interface android.hosttest.annotation.HostSideTestSubstitute extends java
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestSubstitute
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 2, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestSubstitute
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
-
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
public abstract java.lang.String suffix();
descriptor: ()Ljava/lang/String;
flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
@@ -244,16 +192,9 @@ public interface android.hosttest.annotation.HostSideTestThrow extends java.lang
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestThrow
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestThrow
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestThrow.java"
RuntimeVisibleAnnotations:
@@ -275,16 +216,9 @@ public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestWholeClassKeep
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestWholeClassKeep
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestWholeClassKeep.java"
RuntimeVisibleAnnotations:
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
index 0f8af92dc486..e4b9db2ed6d8 100644
--- a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
@@ -6,17 +6,9 @@ public interface android.hosttest.annotation.HostSideTestClassLoadHook extends j
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestClassLoadHook
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 2, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestClassLoadHook
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
-
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
public abstract java.lang.String value();
descriptor: ()Ljava/lang/String;
flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
@@ -44,16 +36,9 @@ public interface android.hosttest.annotation.HostSideTestKeep extends java.lang.
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestKeep
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestKeep
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestKeep.java"
RuntimeVisibleAnnotations:
@@ -75,16 +60,9 @@ public interface android.hosttest.annotation.HostSideTestRedirect extends java.l
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestRedirect
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestRedirect
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestRedirect.java"
RuntimeVisibleAnnotations:
@@ -106,17 +84,9 @@ public interface android.hosttest.annotation.HostSideTestRedirectionClass extend
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestRedirectionClass
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 2, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestRedirectionClass
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
-
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
public abstract java.lang.String value();
descriptor: ()Ljava/lang/String;
flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
@@ -144,16 +114,9 @@ public interface android.hosttest.annotation.HostSideTestRemove extends java.lan
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestRemove
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestRemove
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestRemove.java"
RuntimeVisibleAnnotations:
@@ -175,16 +138,9 @@ public interface android.hosttest.annotation.HostSideTestStaticInitializerKeep e
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestStaticInitializerKeep
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestStaticInitializerKeep
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestStaticInitializerKeep.java"
RuntimeVisibleAnnotations:
@@ -206,17 +162,9 @@ public interface android.hosttest.annotation.HostSideTestSubstitute extends java
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestSubstitute
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 2, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestSubstitute
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
-
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
public abstract java.lang.String suffix();
descriptor: ()Ljava/lang/String;
flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
@@ -244,16 +192,9 @@ public interface android.hosttest.annotation.HostSideTestThrow extends java.lang
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestThrow
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestThrow
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestThrow.java"
RuntimeVisibleAnnotations:
@@ -275,16 +216,9 @@ public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestWholeClassKeep
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestWholeClassKeep
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestWholeClassKeep.java"
RuntimeVisibleAnnotations:
@@ -307,6 +241,8 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Pro
this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 3, attributes: 4
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -377,6 +313,8 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 3, attributes: 4
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -447,6 +385,8 @@ public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 4
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -476,6 +416,8 @@ public class com.android.hoststubgen.test.tinyframework.R$Nested
this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 2, attributes: 4
+Constant pool:
+{
public static int[] ARRAY;
descriptor: [I
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
@@ -546,6 +488,8 @@ public class com.android.hoststubgen.test.tinyframework.R
this_class: #x // com/android/hoststubgen/test/tinyframework/R
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 2, attributes: 4
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -594,6 +538,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 7, attributes: 3
+Constant pool:
+{
public int keep;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -785,6 +731,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 3, attributes: 3
+Constant pool:
+{
public static final java.util.Set<java.lang.Class<?>> sLoadedClasses;
descriptor: Ljava/util/Set;
flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
@@ -880,6 +828,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAn
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 5, attributes: 3
+Constant pool:
+{
public int keep;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -1010,6 +960,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault
super_class: #x // java/lang/Object
interfaces: 0, fields: 2, methods: 0, attributes: 3
+Constant pool:
+{
public static boolean sInitialized;
descriptor: Z
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
@@ -1047,6 +999,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
super_class: #x // java/lang/Object
interfaces: 0, fields: 2, methods: 1, attributes: 3
+Constant pool:
+{
public static boolean sInitialized;
descriptor: Z
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
@@ -1117,6 +1071,8 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
super_class: #x // java/lang/Enum
interfaces: 0, fields: 6, methods: 7, attributes: 4
+Constant pool:
+{
public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED;
descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
@@ -1400,6 +1356,8 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
super_class: #x // java/lang/Enum
interfaces: 0, fields: 3, methods: 5, attributes: 4
+Constant pool:
+{
public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT;
descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
@@ -1576,6 +1534,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTe
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 3, attributes: 3
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -1659,6 +1619,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 15, attributes: 2
+Constant pool:
+{
public int stub;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -1971,6 +1933,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
super_class: #x // java/lang/Object
interfaces: 0, fields: 2, methods: 8, attributes: 6
+Constant pool:
+{
public final java.util.function.Supplier<java.lang.Integer> mSupplier;
descriptor: Ljava/util/function/Supplier;
flags: (0x0011) ACC_PUBLIC, ACC_FINAL
@@ -2201,6 +2165,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
super_class: #x // java/lang/Object
interfaces: 0, fields: 2, methods: 8, attributes: 6
+Constant pool:
+{
public final java.util.function.Supplier<java.lang.Integer> mSupplier;
descriptor: Ljava/util/function/Supplier;
flags: (0x0011) ACC_PUBLIC, ACC_FINAL
@@ -2432,6 +2398,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 4, attributes: 4
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -2526,6 +2494,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 5, attributes: 6
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -2665,6 +2635,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 15, attributes: 3
+Constant pool:
+{
int value;
descriptor: I
flags: (0x0000)
@@ -2998,6 +2970,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 8, attributes: 3
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -3173,6 +3147,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
super_class: #x // java/lang/Object
interfaces: 1, fields: 1, methods: 4, attributes: 6
+Constant pool:
+{
final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
@@ -3278,6 +3254,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 ex
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 4, attributes: 6
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -3369,6 +3347,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
super_class: #x // java/lang/Object
interfaces: 1, fields: 1, methods: 4, attributes: 6
+Constant pool:
+{
final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
@@ -3474,6 +3454,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 ex
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 4, attributes: 6
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -3565,6 +3547,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 2, attributes: 4
+Constant pool:
+{
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -3623,6 +3607,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
super_class: #x // java/lang/Object
interfaces: 0, fields: 2, methods: 2, attributes: 4
+Constant pool:
+{
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -3694,6 +3680,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$Stat
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 4, attributes: 6
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -3786,6 +3774,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 2, attributes: 4
+Constant pool:
+{
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -3844,6 +3834,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 3, attributes: 4
+Constant pool:
+{
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -3923,6 +3915,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
super_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
interfaces: 0, fields: 0, methods: 2, attributes: 4
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -3973,6 +3967,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
super_class: #x // java/lang/Object
interfaces: 0, fields: 2, methods: 4, attributes: 5
+Constant pool:
+{
public final java.util.function.Supplier<java.lang.Integer> mSupplier;
descriptor: Ljava/util/function/Supplier;
flags: (0x0011) ACC_PUBLIC, ACC_FINAL
@@ -4121,6 +4117,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedi
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 3, attributes: 3
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4192,6 +4190,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClas
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 3, attributes: 3
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4263,6 +4263,8 @@ public class com.android.hoststubgen.test.tinyframework.packagetest.A
this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4286,6 +4288,8 @@ public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A
this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4309,6 +4313,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.C1
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4332,6 +4338,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.C2 extends
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2
super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4355,6 +4363,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.C3 extends
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3
super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4378,6 +4388,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.CA
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CA
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4401,6 +4413,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.CB
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CB
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4424,6 +4438,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C1 ex
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1
super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4447,6 +4463,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C2 ex
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2
super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4470,6 +4488,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C3 ex
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3
super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4493,6 +4513,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1 im
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4516,6 +4538,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1_IA
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA
super_class: #x // java/lang/Object
interfaces: 2, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4539,6 +4563,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I2 im
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4562,6 +4588,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3 im
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4585,6 +4613,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.I1
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I1
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4608,6 +4638,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.I2 exte
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I2
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4631,6 +4663,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.I3 exte
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I3
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4654,6 +4688,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.IA
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IA
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4677,6 +4713,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.IB
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IB
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4700,6 +4738,8 @@ public class com.supported.UnsupportedClass
this_class: #x // com/supported/UnsupportedClass
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 3, attributes: 3
+Constant pool:
+{
private final int mValue;
descriptor: I
flags: (0x0012) ACC_PRIVATE, ACC_FINAL
@@ -4779,6 +4819,8 @@ public class com.unsupported.UnsupportedClass
this_class: #x // com/unsupported/UnsupportedClass
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 3, attributes: 3
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4854,6 +4896,8 @@ public class rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFramew
this_class: #x // rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 3, attributes: 3
+Constant pool:
+{
private final int mValue;
descriptor: I
flags: (0x0012) ACC_PRIVATE, ACC_FINAL
diff --git a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
index 700a1624f7d4..d8e10f842665 100644
--- a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
+++ b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
@@ -38,7 +38,6 @@ import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.AppOpsManager;
-import android.app.admin.DevicePolicyManagerInternal;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.contextualsearch.CallbackToken;
@@ -67,6 +66,7 @@ import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.SystemClock;
+import android.os.UserManager;
import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
@@ -112,8 +112,8 @@ public class ContextualSearchManagerService extends SystemService {
private final ActivityTaskManagerInternal mAtmInternal;
private final PackageManagerInternal mPackageManager;
private final WindowManagerInternal mWmInternal;
- private final DevicePolicyManagerInternal mDpmInternal;
private final AudioManager mAudioManager;
+ private final UserManager mUserManager;
private final Object mLock = new Object();
private final AssistDataRequester mAssistDataRequester;
@@ -179,9 +179,9 @@ public class ContextualSearchManagerService extends SystemService {
LocalServices.getService(ActivityTaskManagerInternal.class));
mPackageManager = LocalServices.getService(PackageManagerInternal.class);
mAudioManager = context.getSystemService(AudioManager.class);
+ mUserManager = context.getSystemService(UserManager.class);
mWmInternal = Objects.requireNonNull(LocalServices.getService(WindowManagerInternal.class));
- mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
mAssistDataRequester = new AssistDataRequester(
mContext,
IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE)),
@@ -308,6 +308,11 @@ public class ContextualSearchManagerService extends SystemService {
}
}
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.CREATE_USERS,
+ android.Manifest.permission.QUERY_USERS
+ })
private Intent getContextualSearchIntent(int entrypoint, int userId, CallbackToken mToken) {
final Intent launchIntent = getResolvedLaunchIntent(userId);
if (launchIntent == null) {
@@ -338,8 +343,7 @@ public class ContextualSearchManagerService extends SystemService {
visiblePackageNames.add(record.getComponentName().getPackageName());
activityTokens.add(record.getActivityToken());
}
- if (mDpmInternal != null
- && mDpmInternal.isUserOrganizationManaged(record.getUserId())) {
+ if (mUserManager.isManagedProfile(record.getUserId())) {
isManagedProfileVisible = true;
}
}
@@ -507,7 +511,10 @@ public class ContextualSearchManagerService extends SystemService {
Intent launchIntent = getContextualSearchIntent(entrypoint, callingUserId, mToken);
if (launchIntent != null) {
int result = invokeContextualSearchIntent(launchIntent, callingUserId);
- if (DEBUG) Log.d(TAG, "Launch result: " + result);
+ if (DEBUG) {
+ Log.d(TAG, "Launch intent: " + launchIntent);
+ Log.d(TAG, "Launch result: " + result);
+ }
}
});
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 057d1274d47d..813e661d6970 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -586,6 +586,9 @@ public class AudioService extends IAudioService.Stub
// protects mRingerMode
private final Object mSettingsLock = new Object();
+ // protects VolumeStreamState / VolumeGroupState operations
+ private final Object mVolumeStateLock = new Object();
+
/** Maximum volume index values for audio streams */
protected static int[] MAX_STREAM_VOLUME = new int[] {
5, // STREAM_VOICE_CALL
@@ -1612,7 +1615,7 @@ public class AudioService extends IAudioService.Stub
private void initVolumeStreamStates() {
int numStreamTypes = AudioSystem.getNumStreamTypes();
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
final VolumeStreamState streamState = getVssForStream(streamType);
if (streamState == null) {
@@ -2420,7 +2423,7 @@ public class AudioService extends IAudioService.Stub
private void checkAllAliasStreamVolumes() {
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
int streamAlias = sStreamVolumeAlias.get(streamType, /*valueIfKeyNotFound=*/-1);
@@ -2502,7 +2505,7 @@ public class AudioService extends IAudioService.Stub
private void onUpdateVolumeStatesForAudioDevice(int device, String caller) {
final int numStreamTypes = AudioSystem.getNumStreamTypes();
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
updateVolumeStates(device, streamType, caller);
}
@@ -2771,7 +2774,7 @@ public class AudioService extends IAudioService.Stub
updateDefaultVolumes();
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
getVssForStreamOrDefault(AudioSystem.STREAM_DTMF)
.setAllIndexes(getVssForStreamOrDefault(dtmfStreamAlias), caller);
getVssForStreamOrDefault(AudioSystem.STREAM_ACCESSIBILITY).setSettingName(
@@ -3233,8 +3236,10 @@ public class AudioService extends IAudioService.Stub
// Each stream will read its own persisted settings
// Broadcast the sticky intents
- broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
- broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
+ synchronized (mSettingsLock) {
+ broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
+ broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
+ }
// Broadcast vibrate settings
broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
@@ -4236,7 +4241,7 @@ public class AudioService extends IAudioService.Stub
private void muteAliasStreams(int streamAlias, boolean state) {
// Locking mSettingsLock to avoid inversion when calling doMute -> updateVolumeGroupIndex
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
List<Integer> streamsToMute = new ArrayList<>();
for (int streamIdx = 0; streamIdx < mStreamStates.size(); streamIdx++) {
final VolumeStreamState vss = mStreamStates.valueAt(streamIdx);
@@ -4280,7 +4285,7 @@ public class AudioService extends IAudioService.Stub
// Locking mSettingsLock to avoid inversion when calling vss.mute -> vss.doMute ->
// vss.updateVolumeGroupIndex
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
final VolumeStreamState streamState = getVssForStreamOrDefault(streamAlias);
// if unmuting causes a change, it was muted
wasMuted = streamState.mute(false, "onUnmuteStreamOnSingleVolDevice");
@@ -4456,7 +4461,7 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#getVolumeGroupVolumeIndex(int) */
public int getVolumeGroupVolumeIndex(int groupId) {
super.getVolumeGroupVolumeIndex_enforcePermission();
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
Log.e(TAG, "No volume group for id " + groupId);
return 0;
@@ -4473,7 +4478,7 @@ public class AudioService extends IAudioService.Stub
MODIFY_AUDIO_SETTINGS_PRIVILEGED, MODIFY_AUDIO_ROUTING })
public int getVolumeGroupMaxVolumeIndex(int groupId) {
super.getVolumeGroupMaxVolumeIndex_enforcePermission();
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
Log.e(TAG, "No volume group for id " + groupId);
return 0;
@@ -4488,7 +4493,7 @@ public class AudioService extends IAudioService.Stub
MODIFY_AUDIO_SETTINGS_PRIVILEGED, MODIFY_AUDIO_ROUTING })
public int getVolumeGroupMinVolumeIndex(int groupId) {
super.getVolumeGroupMinVolumeIndex_enforcePermission();
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
Log.e(TAG, "No volume group for id " + groupId);
return 0;
@@ -4633,7 +4638,7 @@ public class AudioService extends IAudioService.Stub
@android.annotation.EnforcePermission(QUERY_AUDIO_STATE)
public int getLastAudibleVolumeForVolumeGroup(int groupId) {
super.getLastAudibleVolumeForVolumeGroup_enforcePermission();
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
Log.e(TAG, ": no volume group found for id " + groupId);
return 0;
@@ -4645,7 +4650,7 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#isVolumeGroupMuted(int) */
public boolean isVolumeGroupMuted(int groupId) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
Log.e(TAG, ": no volume group found for id " + groupId);
return false;
@@ -5473,7 +5478,7 @@ public class AudioService extends IAudioService.Stub
}
streamType = replaceBtScoStreamWithVoiceCall(streamType, "isStreamMute");
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
ensureValidStreamType(streamType);
return getVssForStreamOrDefault(streamType).mIsMuted;
}
@@ -5654,7 +5659,7 @@ public class AudioService extends IAudioService.Stub
}
private int getStreamVolume(int streamType, int device) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
final VolumeStreamState vss = getVssForStreamOrDefault(streamType);
int index = vss.getIndex(device);
@@ -5698,7 +5703,7 @@ public class AudioService extends IAudioService.Stub
vib.setMinVolumeIndex((vss.mIndexMin + 5) / 10);
vib.setMaxVolumeIndex((vss.mIndexMax + 5) / 10);
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
final int index;
if (isFixedVolumeDevice(ada.getInternalType())) {
index = (vss.mIndexMax + 5) / 10;
@@ -6266,7 +6271,7 @@ public class AudioService extends IAudioService.Stub
// ring and notifications volume should never be 0 when not silenced
if (sStreamVolumeAlias.get(streamType) == AudioSystem.STREAM_RING
|| sStreamVolumeAlias.get(streamType) == AudioSystem.STREAM_NOTIFICATION) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
for (int i = 0; i < vss.mIndexMap.size(); i++) {
int device = vss.mIndexMap.keyAt(i);
int value = vss.mIndexMap.valueAt(i);
@@ -7026,7 +7031,7 @@ public class AudioService extends IAudioService.Stub
}
streamState.readSettings();
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
// unmute stream that was muted but is not affect by mute anymore
if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
!isStreamMutedByRingerOrZenMode(streamType)) || mUseFixedVolume)) {
@@ -8059,14 +8064,14 @@ public class AudioService extends IAudioService.Stub
public Set<Integer> getDeviceSetForStream(int stream) {
stream = replaceBtScoStreamWithVoiceCall(stream, "getDeviceSetForStream");
ensureValidStreamType(stream);
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
return getVssForStreamOrDefault(stream).observeDevicesForStream_syncVSS(true);
}
}
private void onObserveDevicesForAllStreams(int skipStream) {
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
for (int stream = 0; stream < mStreamStates.size(); stream++) {
final VolumeStreamState vss = mStreamStates.valueAt(stream);
if (vss != null && vss.getStreamType() != skipStream) {
@@ -8648,7 +8653,7 @@ public class AudioService extends IAudioService.Stub
private void readVolumeGroupsSettings(boolean userSwitch) {
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (DEBUG_VOL) {
Log.d(TAG, "readVolumeGroupsSettings userSwitch=" + userSwitch);
}
@@ -8706,7 +8711,7 @@ public class AudioService extends IAudioService.Stub
// NOTE: Locking order for synchronized objects related to volume management:
// 1 mSettingsLock
- // 2 VolumeStreamState.class
+ // 2 mVolumeStateLock
private class VolumeGroupState {
private final AudioVolumeGroup mAudioVolumeGroup;
private final SparseIntArray mIndexMap = new SparseIntArray(8);
@@ -8800,7 +8805,7 @@ public class AudioService extends IAudioService.Stub
* Mute/unmute the volume group
* @param muted the new mute state
*/
- @GuardedBy("AudioService.VolumeStreamState.class")
+ @GuardedBy("AudioService.this.mVolumeStateLock")
public boolean mute(boolean muted) {
if (!isMutable()) {
// Non mutable volume group
@@ -8824,7 +8829,7 @@ public class AudioService extends IAudioService.Stub
public void adjustVolume(int direction, int flags) {
synchronized (mSettingsLock) {
- synchronized (AudioService.VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
int device = getDeviceForVolume();
int previousIndex = getIndex(device);
if (isMuteAdjust(direction) && !isMutable()) {
@@ -8878,14 +8883,14 @@ public class AudioService extends IAudioService.Stub
}
public int getVolumeIndex() {
- synchronized (AudioService.VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
return getIndex(getDeviceForVolume());
}
}
public void setVolumeIndex(int index, int flags) {
synchronized (mSettingsLock) {
- synchronized (AudioService.VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (mUseFixedVolume) {
return;
}
@@ -8894,7 +8899,7 @@ public class AudioService extends IAudioService.Stub
}
}
- @GuardedBy("AudioService.VolumeStreamState.class")
+ @GuardedBy("AudioService.this.mVolumeStateLock")
private void setVolumeIndex(int index, int device, int flags) {
// Update cache & persist (muted by volume 0 shall be persisted)
updateVolumeIndex(index, device);
@@ -8907,7 +8912,7 @@ public class AudioService extends IAudioService.Stub
}
}
- @GuardedBy("AudioService.VolumeStreamState.class")
+ @GuardedBy("AudioService.this.mVolumeStateLock")
public void updateVolumeIndex(int index, int device) {
// Filter persistency if already exist and the index has not changed
if (mIndexMap.indexOfKey(device) < 0 || mIndexMap.get(device) != index) {
@@ -8925,7 +8930,7 @@ public class AudioService extends IAudioService.Stub
}
}
- @GuardedBy("AudioService.VolumeStreamState.class")
+ @GuardedBy("AudioService.this.mVolumeStateLock")
private void setVolumeIndexInt(int index, int device, int flags) {
// Reflect mute state of corresponding stream by forcing index to 0 if muted
// Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.
@@ -8958,14 +8963,14 @@ public class AudioService extends IAudioService.Stub
mAudioSystem.setVolumeIndexForAttributes(mAudioAttributes, index, muted, device);
}
- @GuardedBy("AudioService.VolumeStreamState.class")
+ @GuardedBy("AudioService.this.mVolumeStateLock")
private int getIndex(int device) {
int index = mIndexMap.get(device, -1);
// there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
return (index != -1) ? index : mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
}
- @GuardedBy("AudioService.VolumeStreamState.class")
+ @GuardedBy("AudioService.this.mVolumeStateLock")
private boolean hasIndexForDevice(int device) {
return (mIndexMap.get(device, -1) != -1);
}
@@ -8992,7 +8997,7 @@ public class AudioService extends IAudioService.Stub
public void applyAllVolumes(boolean userSwitch) {
String caller = "from vgs";
- synchronized (AudioService.VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
// apply device specific volumes first
for (int i = 0; i < mIndexMap.size(); i++) {
int device = mIndexMap.keyAt(i);
@@ -9095,25 +9100,27 @@ public class AudioService extends IAudioService.Stub
if (mUseFixedVolume || mHasValidStreamType) {
return;
}
- if (DEBUG_VOL) {
- Log.v(TAG, "persistVolumeGroup: storing index " + getIndex(device) + " for group "
- + mAudioVolumeGroup.name()
- + ", device " + AudioSystem.getOutputDeviceName(device)
- + " and User=" + getCurrentUserId()
- + " mSettingName: " + mSettingName);
- }
+ synchronized (mVolumeStateLock) {
+ if (DEBUG_VOL) {
+ Log.v(TAG, "persistVolumeGroup: storing index " + getIndex(device)
+ + " for group " + mAudioVolumeGroup.name()
+ + ", device " + AudioSystem.getOutputDeviceName(device)
+ + " and User=" + getCurrentUserId()
+ + " mSettingName: " + mSettingName);
+ }
- boolean success = mSettings.putSystemIntForUser(mContentResolver,
- getSettingNameForDevice(device),
- getIndex(device),
- getVolumePersistenceUserId());
- if (!success) {
- Log.e(TAG, "persistVolumeGroup failed for group " + mAudioVolumeGroup.name());
+ boolean success = mSettings.putSystemIntForUser(mContentResolver,
+ getSettingNameForDevice(device),
+ getIndex(device),
+ getVolumePersistenceUserId());
+ if (!success) {
+ Log.e(TAG, "persistVolumeGroup failed for group " + mAudioVolumeGroup.name());
+ }
}
}
public void readSettings() {
- synchronized (AudioService.VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
// force maximum volume on all streams if fixed volume property is set
if (mUseFixedVolume) {
mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
@@ -9147,7 +9154,7 @@ public class AudioService extends IAudioService.Stub
}
}
- @GuardedBy("AudioService.VolumeStreamState.class")
+ @GuardedBy("AudioService.this.mVolumeStateLock")
private int getValidIndex(int index) {
if (index < mIndexMin) {
return mIndexMin;
@@ -9221,7 +9228,7 @@ public class AudioService extends IAudioService.Stub
// 1 mScoclient OR mSafeMediaVolumeState
// 2 mSetModeLock
// 3 mSettingsLock
- // 4 VolumeStreamState.class
+ // 4 mVolumeStateLock
/*package*/ class VolumeStreamState {
private final int mStreamType;
private VolumeGroupState mVolumeGroupState = null;
@@ -9430,7 +9437,7 @@ public class AudioService extends IAudioService.Stub
*
* This is a reference to the local list, do not modify.
*/
- @GuardedBy("VolumeStreamState.class")
+ @GuardedBy("mVolumeStateLock")
@NonNull
public Set<Integer> observeDevicesForStream_syncVSS(
boolean checkOthers) {
@@ -9498,7 +9505,7 @@ public class AudioService extends IAudioService.Stub
public void readSettings() {
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
// force maximum volume on all streams if fixed volume property is set
if (mUseFixedVolume) {
mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
@@ -9518,7 +9525,7 @@ public class AudioService extends IAudioService.Stub
}
}
}
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
for (int device : AudioSystem.DEVICE_OUT_ALL_SET) {
// retrieve current volume for device
@@ -9551,7 +9558,7 @@ public class AudioService extends IAudioService.Stub
* will send the non-zero index together with muted state. Otherwise, index 0 will be sent
* to native for signalising a muted stream.
**/
- @GuardedBy("VolumeStreamState.class")
+ @GuardedBy("mVolumeStateLock")
private void setStreamVolumeIndex(int index, int device) {
// Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.
// This allows RX path muting by the audio HAL only when explicitly muted but not when
@@ -9573,8 +9580,8 @@ public class AudioService extends IAudioService.Stub
mAudioSystem.setStreamVolumeIndexAS(mStreamType, index, muted, device);
}
- // must be called while synchronized VolumeStreamState.class
- @GuardedBy("VolumeStreamState.class")
+ // must be called while synchronized mVolumeStateLock
+ @GuardedBy("mVolumeStateLock")
/*package*/ void applyDeviceVolume_syncVSS(int device) {
int index;
if (isFullyMuted() && !ringMyCar()) {
@@ -9600,7 +9607,7 @@ public class AudioService extends IAudioService.Stub
}
public void applyAllVolumes() {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
// apply device specific volumes first
int index;
boolean isAbsoluteVolume = false;
@@ -9662,7 +9669,7 @@ public class AudioService extends IAudioService.Stub
final boolean isCurrentDevice;
final StringBuilder aliasStreamIndexes = new StringBuilder();
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
oldIndex = getIndex(device);
index = getValidIndex(index, hasModifyAudioSettings);
// for STREAM_SYSTEM_ENFORCED, do not sync aliased streams on the enforced index
@@ -9780,7 +9787,7 @@ public class AudioService extends IAudioService.Stub
}
public int getIndex(int device) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
int index = mIndexMap.get(device, -1);
if (index == -1) {
// there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
@@ -9791,7 +9798,7 @@ public class AudioService extends IAudioService.Stub
}
public @NonNull VolumeInfo getVolumeInfo(int device) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
int index = mIndexMap.get(device, -1);
if (index == -1) {
// there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
@@ -9808,7 +9815,7 @@ public class AudioService extends IAudioService.Stub
}
public boolean hasIndexForDevice(int device) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
return (mIndexMap.get(device, -1) != -1);
}
}
@@ -9840,8 +9847,8 @@ public class AudioService extends IAudioService.Stub
* @param srcStream
* @param caller
*/
- // must be sync'd on mSettingsLock before VolumeStreamState.class
- @GuardedBy("VolumeStreamState.class")
+ // must be sync'd on mSettingsLock before mVolumeStateLock
+ @GuardedBy("mVolumeStateLock")
public void setAllIndexes(VolumeStreamState srcStream, String caller) {
if (srcStream == null || mStreamType == srcStream.mStreamType) {
return;
@@ -9865,8 +9872,8 @@ public class AudioService extends IAudioService.Stub
}
}
- // must be sync'd on mSettingsLock before VolumeStreamState.class
- @GuardedBy("VolumeStreamState.class")
+ // must be sync'd on mSettingsLock before mVolumeStateLock
+ @GuardedBy("mVolumeStateLock")
public void setAllIndexesToMax() {
for (int i = 0; i < mIndexMap.size(); i++) {
mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
@@ -9879,7 +9886,7 @@ public class AudioService extends IAudioService.Stub
// vss.setIndex which grabs this lock after VSS.class. Locking order needs to be
// preserved
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (mVolumeGroupState != null) {
int groupIndex = (getIndex(device) + 5) / 10;
if (DEBUG_VOL) {
@@ -9911,7 +9918,7 @@ public class AudioService extends IAudioService.Stub
*/
public boolean mute(boolean state, String source) {
boolean changed = false;
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
changed = mute(state, true, source);
}
if (changed) {
@@ -9927,7 +9934,7 @@ public class AudioService extends IAudioService.Stub
*/
public boolean muteInternally(boolean state) {
boolean changed = false;
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (state != mIsMutedInternally) {
changed = true;
mIsMutedInternally = state;
@@ -9942,7 +9949,7 @@ public class AudioService extends IAudioService.Stub
return changed;
}
- @GuardedBy("VolumeStreamState.class")
+ @GuardedBy("mVolumeStateLock")
public boolean isFullyMuted() {
return mIsMuted || mIsMutedInternally;
}
@@ -9963,7 +9970,7 @@ public class AudioService extends IAudioService.Stub
*/
public boolean mute(boolean state, boolean apply, String src) {
boolean changed;
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
changed = state != mIsMuted;
if (changed) {
sMuteLogger.enqueue(
@@ -9997,7 +10004,7 @@ public class AudioService extends IAudioService.Stub
}
public void doMute() {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
// If associated to volume group, update group cache
updateVolumeGroupIndex(getDeviceForStream(mStreamType), /* forceMuteState= */true);
@@ -10018,7 +10025,7 @@ public class AudioService extends IAudioService.Stub
}
public void checkFixedVolumeDevices() {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
// ignore settings for fixed volume devices: volume should always be at max or 0
if (sStreamVolumeAlias.get(mStreamType) == AudioSystem.STREAM_MUSIC) {
for (int i = 0; i < mIndexMap.size(); i++) {
@@ -10189,8 +10196,7 @@ public class AudioService extends IAudioService.Stub
}
/*package*/ void setDeviceVolume(VolumeStreamState streamState, int device) {
-
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
sendMsg(mAudioHandler, SoundDoseHelper.MSG_CSD_UPDATE_ATTENUATION, SENDMSG_QUEUE,
device, (isAbsoluteVolumeDevice(device) || isA2dpAbsoluteVolumeDevice(device)
|| AudioSystem.isLeAudioDeviceType(device) ? 1 : 0),
@@ -12194,7 +12200,7 @@ public class AudioService extends IAudioService.Stub
mCameraSoundForced = cameraSoundForced;
if (cameraSoundForcedChanged) {
if (!mIsSingleVolume) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
final VolumeStreamState s = getVssForStreamOrDefault(
AudioSystem.STREAM_SYSTEM_ENFORCED);
if (cameraSoundForced) {
diff --git a/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java b/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java
index 000ee5446962..9f364677705e 100644
--- a/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java
+++ b/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java
@@ -20,12 +20,16 @@ import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
import android.annotation.NonNull;
import android.hardware.SensorPrivacyManager;
+import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraManager;
+import android.util.Log;
import java.util.concurrent.ConcurrentHashMap;
public class BiometricCameraManagerImpl implements BiometricCameraManager {
+ private static final String TAG = "BiometricCameraManager";
+
private final CameraManager mCameraManager;
private final SensorPrivacyManager mSensorPrivacyManager;
private final ConcurrentHashMap<String, Boolean> mIsCameraAvailable = new ConcurrentHashMap<>();
@@ -52,12 +56,18 @@ public class BiometricCameraManagerImpl implements BiometricCameraManager {
@Override
public boolean isAnyCameraUnavailable() {
- for (String cameraId : mIsCameraAvailable.keySet()) {
- if (!mIsCameraAvailable.get(cameraId)) {
- return true;
+ try {
+ for (String cameraId : mCameraManager.getCameraIdList()) {
+ if (!mIsCameraAvailable.getOrDefault(cameraId, true)) {
+ return true;
+ }
}
+ return false;
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Camera exception thrown when trying to determine availability: ", e);
+ //If face HAL is unable to get access to a camera, it will return an error.
+ return false;
}
- return false;
}
@Override
diff --git a/tests/AppJankTest/res/values/strings.xml b/tests/AppJankTest/res/values/strings.xml
new file mode 100644
index 000000000000..ab2d18fa9d53
--- /dev/null
+++ b/tests/AppJankTest/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="continue_test">Continue Test</string>
+</resources> \ No newline at end of file
diff --git a/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java
index fe9f63615757..3498974b348e 100644
--- a/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java
+++ b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java
@@ -209,7 +209,8 @@ public class IntegrationTests {
JankTrackerActivity.class);
resumeJankTracker.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
mEmptyActivity.startActivity(resumeJankTracker);
- mDevice.wait(Until.findObject(By.text("Edit Text")), WAIT_FOR_TIMEOUT_MS);
+ mDevice.wait(Until.findObject(By.text(mEmptyActivity.getString(R.string.continue_test))),
+ WAIT_FOR_TIMEOUT_MS);
assertTrue(jankTracker.shouldTrack());
}
diff --git a/tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java b/tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java
index 80ab6ad3e587..686758200853 100644
--- a/tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java
+++ b/tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java
@@ -18,15 +18,41 @@ package android.app.jank.tests;
import android.app.Activity;
import android.os.Bundle;
+import android.widget.EditText;
public class JankTrackerActivity extends Activity {
+ private static final int CONTINUE_TEST_DELAY_MS = 4000;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.jank_tracker_activity_layout);
}
+
+ /**
+ * In IntegrationTests#jankTrackingResumed_whenActivityBecomesVisibleAgain this activity is
+ * placed into the background and then resumed via an intent. The test waits until the
+ * `continue_test` string is visible on the screen before validating that Jank tracking has
+ * resumed.
+ *
+ * <p>The 4 second delay allows JankTracker to re-register its callbacks and start receiving
+ * JankData before the test proceeds.
+ */
+ @Override
+ protected void onResume() {
+ super.onResume();
+ getActivityThread().getHandler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ EditText editTextView = findViewById(R.id.edit_text);
+ if (editTextView != null) {
+ editTextView.setText(R.string.continue_test);
+ }
+ }
+ }, CONTINUE_TEST_DELAY_MS);
+ }
}