summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java10
-rw-r--r--core/java/android/companion/virtual/flags.aconfig11
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java54
-rw-r--r--core/java/android/net/NetworkPolicyManager.java6
-rw-r--r--core/java/android/provider/Settings.java29
-rw-r--r--core/java/android/view/GestureDetector.java72
-rw-r--r--core/java/android/view/VelocityTracker.java4
-rw-r--r--core/java/android/view/ViewRootImpl.java79
-rw-r--r--core/java/android/view/inputmethod/InputMethodInfo.java23
-rw-r--r--core/java/android/view/inputmethod/InputMethodSubtypeArray.java13
-rw-r--r--core/java/android/widget/flags/notification_widget_flags.aconfig10
-rw-r--r--core/java/com/android/internal/widget/MessagingLinearLayout.java6
-rw-r--r--core/res/res/layout/side_fps_toast.xml2
-rw-r--r--core/res/res/values-watch/config.xml3
-rw-r--r--libs/WindowManager/Shell/aconfig/multitasking.aconfig7
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java5
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java4
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java12
-rw-r--r--packages/SystemUI/Android.bp17
-rwxr-xr-xpackages/SystemUI/flag_check.py44
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt42
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt57
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MessageRouterImplTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/concurrency/RepeatableExecutorTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt113
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt47
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/service/PackageObserverTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/service/PersistentConnectionManagerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java11
-rw-r--r--services/core/java/com/android/server/PinnerService.java13
-rw-r--r--services/core/java/com/android/server/inputmethod/ImeBindingState.java10
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java20
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodMap.java24
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java5
-rw-r--r--services/core/java/com/android/server/net/NetworkManagementService.java228
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyLogger.java14
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java89
-rw-r--r--services/core/java/com/android/server/net/flags.aconfig10
-rw-r--r--services/core/java/com/android/server/ondeviceintelligence/BundleUtil.java18
-rw-r--r--services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java170
-rw-r--r--services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceIntelligenceService.java16
-rw-r--r--services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceSandboxedInferenceService.java20
-rw-r--r--services/core/java/com/android/server/ondeviceintelligence/callbacks/ListenableDownloadCallback.java97
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java13
-rw-r--r--services/core/java/com/android/server/stats/stats_flags.aconfig8
-rw-r--r--services/tests/servicestests/AndroidTest.xml7
-rw-r--r--services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java78
66 files changed, 1234 insertions, 525 deletions
diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
index 488292d68620..f726361effd6 100644
--- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
+++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
@@ -292,13 +292,17 @@ public class AccessibilityNodeInfoDumper {
int childCount = node.getChildCount();
for (int x = 0; x < childCount; x++) {
AccessibilityNodeInfo childNode = node.getChild(x);
-
+ if (childNode == null) {
+ continue;
+ }
if (!safeCharSeqToString(childNode.getContentDescription()).isEmpty()
- || !safeCharSeqToString(childNode.getText()).isEmpty())
+ || !safeCharSeqToString(childNode.getText()).isEmpty()) {
return true;
+ }
- if (childNafCheck(childNode))
+ if (childNafCheck(childNode)) {
return true;
+ }
}
return false;
}
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index 3e23762a4f70..b29b52d67310 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -127,4 +127,15 @@ flag {
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag {
+ name: "impulse_velocity_strategy_for_touch_navigation"
+ is_exported: true
+ namespace: "virtual_devices"
+ description: "Use impulse velocity strategy during conversion of touch navigation flings into Dpad events"
+ bug: "338426241"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
} \ No newline at end of file
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 2b7d8f155bff..708f8a173aba 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -39,7 +39,6 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.hardware.CameraExtensionSessionStats;
-import android.hardware.CameraIdRemapping;
import android.hardware.CameraStatus;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
@@ -1996,17 +1995,6 @@ public final class CameraManager {
}
/**
- * Remaps Camera Ids in the CameraService.
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.CAMERA_INJECT_EXTERNAL_CAMERA)
- public void remapCameraIds(@NonNull CameraIdRemapping cameraIdRemapping)
- throws CameraAccessException, SecurityException, IllegalArgumentException {
- CameraManagerGlobal.get().remapCameraIds(cameraIdRemapping);
- }
-
- /**
* Injects session params into existing clients in the CameraService.
*
* @param cameraId The camera id of client to inject session params into.
@@ -2117,13 +2105,6 @@ public final class CameraManager {
private final Object mLock = new Object();
- /**
- * The active CameraIdRemapping. This will be used to refresh the cameraIdRemapping state
- * in the CameraService every time we connect to it, including when the CameraService
- * Binder dies and we reconnect to it.
- */
- @Nullable private CameraIdRemapping mActiveCameraIdRemapping;
-
// Access only through getCameraService to deal with binder death
private ICameraService mCameraService;
private boolean mHasOpenCloseListenerPermission = false;
@@ -2275,41 +2256,6 @@ public final class CameraManager {
} catch (RemoteException e) {
// Camera service died in all probability
}
-
- if (mActiveCameraIdRemapping != null) {
- try {
- cameraService.remapCameraIds(mActiveCameraIdRemapping);
- } catch (ServiceSpecificException e) {
- // Unexpected failure, ignore and continue.
- Log.e(TAG, "Unable to remap camera Ids in the camera service");
- } catch (RemoteException e) {
- // Camera service died in all probability
- }
- }
- }
-
- /** Updates the cameraIdRemapping state in the CameraService. */
- public void remapCameraIds(@NonNull CameraIdRemapping cameraIdRemapping)
- throws CameraAccessException, SecurityException {
- synchronized (mLock) {
- ICameraService cameraService = getCameraService();
- if (cameraService == null) {
- throw new CameraAccessException(
- CameraAccessException.CAMERA_DISCONNECTED,
- "Camera service is currently unavailable.");
- }
-
- try {
- cameraService.remapCameraIds(cameraIdRemapping);
- mActiveCameraIdRemapping = cameraIdRemapping;
- } catch (ServiceSpecificException e) {
- throw ExceptionUtils.throwAsPublicException(e);
- } catch (RemoteException e) {
- throw new CameraAccessException(
- CameraAccessException.CAMERA_DISCONNECTED,
- "Camera service is currently unavailable.");
- }
- }
}
/** Injects session params into an existing client for cameraid. */
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 594ec18d9996..334b2316b268 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -173,6 +173,12 @@ public class NetworkPolicyManager {
public static final String FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY = "low_power_standby";
/** @hide */
public static final String FIREWALL_CHAIN_NAME_BACKGROUND = "background";
+ /** @hide */
+ public static final String FIREWALL_CHAIN_NAME_METERED_ALLOW = "metered_allow";
+ /** @hide */
+ public static final String FIREWALL_CHAIN_NAME_METERED_DENY_USER = "metered_deny_user";
+ /** @hide */
+ public static final String FIREWALL_CHAIN_NAME_METERED_DENY_ADMIN = "metered_deny_admin";
private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 90ec5aad235d..4f5b67c34845 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11173,6 +11173,35 @@ public final class Settings {
"visual_query_accessibility_detection_enabled";
/**
+ * Timeout to be used for unbinding to the configured remote
+ * {@link android.service.ondeviceintelligence.OnDeviceIntelligenceService} if there are no
+ * requests in the queue. A value of -1 represents to never unbind.
+ *
+ * @hide
+ */
+ public static final String ON_DEVICE_INTELLIGENCE_UNBIND_TIMEOUT_MS =
+ "on_device_intelligence_unbind_timeout_ms";
+
+
+ /**
+ * Timeout that represents maximum idle time before which a callback should be populated.
+ *
+ * @hide
+ */
+ public static final String ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS =
+ "on_device_intelligence_idle_timeout_ms";
+
+ /**
+ * Timeout to be used for unbinding to the configured remote
+ * {@link android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService} if there
+ * are no requests in the queue. A value of -1 represents to never unbind.
+ *
+ * @hide
+ */
+ public static final String ON_DEVICE_INFERENCE_UNBIND_TIMEOUT_MS =
+ "on_device_inference_unbind_timeout_ms";
+
+ /**
* Control whether Night display is currently activated.
* @hide
*/
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 9ff29a81a5c6..4837ee5a797c 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -26,11 +26,13 @@ import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFI
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiContext;
+import android.app.Activity;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.StrictMode;
import android.os.SystemClock;
@@ -299,6 +301,11 @@ public class GestureDetector {
private VelocityTracker mVelocityTracker;
/**
+ * Determines strategy for velocity calculation
+ */
+ private @VelocityTracker.VelocityTrackerStrategy int mVelocityTrackerStrategy;
+
+ /**
* Consistency verifier for debugging purposes.
*/
private final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
@@ -347,17 +354,17 @@ public class GestureDetector {
/**
* Creates a GestureDetector with the supplied listener.
- * This variant of the constructor should be used from a non-UI thread
+ * This variant of the constructor should be used from a non-UI thread
* (as it allows specifying the Handler).
- *
+ *
* @param listener the listener invoked for all the callbacks, this must
* not be null.
* @param handler the handler to use
*
* @throws NullPointerException if {@code listener} is null.
*
- * @deprecated Use {@link #GestureDetector(android.content.Context,
- * android.view.GestureDetector.OnGestureListener, android.os.Handler)} instead.
+ * @deprecated Use {@link #GestureDetector(Context, GestureDetector.OnGestureListener, Handler)}
+ * instead.
*/
@Deprecated
public GestureDetector(@NonNull OnGestureListener listener, @Nullable Handler handler) {
@@ -367,15 +374,14 @@ public class GestureDetector {
/**
* Creates a GestureDetector with the supplied listener.
* You may only use this constructor from a UI thread (this is the usual situation).
- * @see android.os.Handler#Handler()
- *
+ * @see Handler#Handler()
+ *
* @param listener the listener invoked for all the callbacks, this must
* not be null.
- *
+ *
* @throws NullPointerException if {@code listener} is null.
*
- * @deprecated Use {@link #GestureDetector(android.content.Context,
- * android.view.GestureDetector.OnGestureListener)} instead.
+ * @deprecated Use {@link #GestureDetector(Context, GestureDetector.OnGestureListener)} instead.
*/
@Deprecated
public GestureDetector(@NonNull OnGestureListener listener) {
@@ -384,10 +390,10 @@ public class GestureDetector {
/**
* Creates a GestureDetector with the supplied listener.
- * You may only use this constructor from a {@link android.os.Looper} thread.
- * @see android.os.Handler#Handler()
+ * You may only use this constructor from a {@link Looper} thread.
+ * @see Handler#Handler()
*
- * @param context An {@link android.app.Activity} or a {@link Context} created from
+ * @param context An {@link Activity} or a {@link Context} created from
* {@link Context#createWindowContext(int, Bundle)}
* @param listener the listener invoked for all the callbacks, this must
* not be null. If the listener implements the {@link OnDoubleTapListener} or
@@ -404,10 +410,10 @@ public class GestureDetector {
/**
* Creates a GestureDetector with the supplied listener that runs deferred events on the
- * thread associated with the supplied {@link android.os.Handler}.
- * @see android.os.Handler#Handler()
+ * thread associated with the supplied {@link Handler}.
+ * @see Handler#Handler()
*
- * @param context An {@link android.app.Activity} or a {@link Context} created from
+ * @param context An {@link Activity} or a {@link Context} created from
* {@link Context#createWindowContext(int, Bundle)}
* @param listener the listener invoked for all the callbacks, this must
* not be null. If the listener implements the {@link OnDoubleTapListener} or
@@ -419,6 +425,31 @@ public class GestureDetector {
*/
public GestureDetector(@Nullable @UiContext Context context,
@NonNull OnGestureListener listener, @Nullable Handler handler) {
+ this(context, listener, handler, VelocityTracker.VELOCITY_TRACKER_STRATEGY_DEFAULT);
+ }
+
+ /**
+ * Creates a GestureDetector with the supplied listener that runs deferred events on the
+ * thread associated with the supplied {@link Handler}.
+ * @see Handler#Handler()
+ *
+ * @param context An {@link Activity} or a {@link Context} created from
+ * {@link Context#createWindowContext(int, Bundle)}
+ * @param listener the listener invoked for all the callbacks, this must
+ * not be null. If the listener implements the {@link OnDoubleTapListener} or
+ * {@link OnContextClickListener} then it will also be set as the listener for
+ * these callbacks (for example when using the {@link SimpleOnGestureListener}).
+ * @param handler the handler to use for running deferred listener events.
+ * @param velocityTrackerStrategy strategy to use for velocity calculation of scroll/fling
+ * events.
+ *
+ * @throws NullPointerException if {@code listener} is null.
+ *
+ * @hide
+ */
+ public GestureDetector(@Nullable @UiContext Context context,
+ @NonNull OnGestureListener listener, @Nullable Handler handler,
+ @VelocityTracker.VelocityTrackerStrategy int velocityTrackerStrategy) {
if (handler != null) {
mHandler = new GestureHandler(handler);
} else {
@@ -431,15 +462,16 @@ public class GestureDetector {
if (listener instanceof OnContextClickListener) {
setContextClickListener((OnContextClickListener) listener);
}
+ mVelocityTrackerStrategy = velocityTrackerStrategy;
init(context);
}
-
+
/**
* Creates a GestureDetector with the supplied listener that runs deferred events on the
- * thread associated with the supplied {@link android.os.Handler}.
- * @see android.os.Handler#Handler()
+ * thread associated with the supplied {@link Handler}.
+ * @see Handler#Handler()
*
- * @param context An {@link android.app.Activity} or a {@link Context} created from
+ * @param context An {@link Activity} or a {@link Context} created from
* {@link Context#createWindowContext(int, Bundle)}
* @param listener the listener invoked for all the callbacks, this must
* not be null.
@@ -547,7 +579,7 @@ public class GestureDetector {
mCurrentMotionEvent = MotionEvent.obtain(ev);
if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
+ mVelocityTracker = VelocityTracker.obtain(mVelocityTrackerStrategy);
}
mVelocityTracker.addMovement(ev);
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index d31f82398cdf..27176a4c2094 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -264,7 +264,6 @@ public final class VelocityTracker {
/**
* Obtains a velocity tracker with the specified strategy.
- * For testing and comparison purposes only.
*
* @param strategy The strategy Id, VELOCITY_TRACKER_STRATEGY_DEFAULT to use the default.
* @return The velocity tracker.
@@ -272,6 +271,9 @@ public final class VelocityTracker {
* @hide
*/
public static VelocityTracker obtain(int strategy) {
+ if (strategy == VELOCITY_TRACKER_STRATEGY_DEFAULT) {
+ return obtain();
+ }
return new VelocityTracker(strategy);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 155c0537b5b5..fb0c0a30414e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -8609,48 +8609,55 @@ public final class ViewRootImpl implements ViewParent,
private int mPendingKeyMetaState;
- private final GestureDetector mGestureDetector = new GestureDetector(mContext,
- new GestureDetector.OnGestureListener() {
- @Override
- public boolean onDown(@NonNull MotionEvent e) {
- // This can be ignored since it's not clear what KeyEvent this will
- // belong to.
- return true;
- }
-
- @Override
- public void onShowPress(@NonNull MotionEvent e) {
+ private final GestureDetector mGestureDetector;
- }
+ SyntheticTouchNavigationHandler() {
+ super(true);
+ int gestureDetectorVelocityStrategy =
+ android.companion.virtual.flags.Flags
+ .impulseVelocityStrategyForTouchNavigation()
+ ? VelocityTracker.VELOCITY_TRACKER_STRATEGY_IMPULSE
+ : VelocityTracker.VELOCITY_TRACKER_STRATEGY_DEFAULT;
+ mGestureDetector = new GestureDetector(mContext,
+ new GestureDetector.OnGestureListener() {
+ @Override
+ public boolean onDown(@NonNull MotionEvent e) {
+ // This can be ignored since it's not clear what KeyEvent this will
+ // belong to.
+ return true;
+ }
- @Override
- public boolean onSingleTapUp(@NonNull MotionEvent e) {
- dispatchTap(e.getEventTime());
- return true;
- }
+ @Override
+ public void onShowPress(@NonNull MotionEvent e) {
+ }
- @Override
- public boolean onScroll(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
- float distanceX, float distanceY) {
- // Scroll doesn't translate to DPAD events so should be ignored.
- return true;
- }
+ @Override
+ public boolean onSingleTapUp(@NonNull MotionEvent e) {
+ dispatchTap(e.getEventTime());
+ return true;
+ }
- @Override
- public void onLongPress(@NonNull MotionEvent e) {
- // Long presses don't translate to DPAD events so should be ignored.
- }
+ @Override
+ public boolean onScroll(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
+ float distanceX, float distanceY) {
+ // Scroll doesn't translate to DPAD events so should be ignored.
+ return true;
+ }
- @Override
- public boolean onFling(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
- float velocityX, float velocityY) {
- dispatchFling(velocityX, velocityY, e2.getEventTime());
- return true;
- }
- });
+ @Override
+ public void onLongPress(@NonNull MotionEvent e) {
+ // Long presses don't translate to DPAD events so should be ignored.
+ }
- SyntheticTouchNavigationHandler() {
- super(true);
+ @Override
+ public boolean onFling(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
+ float velocityX, float velocityY) {
+ dispatchFling(velocityX, velocityY, e2.getEventTime());
+ return true;
+ }
+ },
+ /* handler= */ null,
+ gestureDetectorVelocityStrategy);
}
public void process(MotionEvent event) {
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 7885cd95ca25..11ee286652a1 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -54,6 +54,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -431,6 +432,14 @@ public final class InputMethodInfo implements Parcelable {
* @hide
*/
public InputMethodInfo(InputMethodInfo source) {
+ this(source, Collections.emptyList());
+ }
+
+ /**
+ * @hide
+ */
+ public InputMethodInfo(@NonNull InputMethodInfo source,
+ @NonNull List<InputMethodSubtype> additionalSubtypes) {
mId = source.mId;
mSettingsActivityName = source.mSettingsActivityName;
mLanguageSettingsActivityName = source.mLanguageSettingsActivityName;
@@ -445,7 +454,19 @@ public final class InputMethodInfo implements Parcelable {
mIsVrOnly = source.mIsVrOnly;
mIsVirtualDeviceOnly = source.mIsVirtualDeviceOnly;
mService = source.mService;
- mSubtypes = source.mSubtypes;
+ if (additionalSubtypes.isEmpty()) {
+ mSubtypes = source.mSubtypes;
+ } else {
+ final ArrayList<InputMethodSubtype> subtypes = source.mSubtypes.toList();
+ final int additionalSubtypeCount = additionalSubtypes.size();
+ for (int i = 0; i < additionalSubtypeCount; ++i) {
+ final InputMethodSubtype additionalSubtype = additionalSubtypes.get(i);
+ if (!subtypes.contains(additionalSubtype)) {
+ subtypes.add(additionalSubtype);
+ }
+ }
+ mSubtypes = new InputMethodSubtypeArray(subtypes);
+ }
mHandledConfigChanges = source.mHandledConfigChanges;
mSupportsStylusHandwriting = source.mSupportsStylusHandwriting;
mSupportsConnectionlessStylusHandwriting = source.mSupportsConnectionlessStylusHandwriting;
diff --git a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
index c243a22b27b1..e2d343f45e5d 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
@@ -25,6 +25,7 @@ import android.util.Slog;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@@ -163,6 +164,18 @@ public class InputMethodSubtypeArray {
}
/**
+ * @return A list of {@link InputMethodInfo} copied from this array.
+ */
+ @NonNull
+ public ArrayList<InputMethodSubtype> toList() {
+ final ArrayList<InputMethodSubtype> list = new ArrayList<>(mCount);
+ for (int i = 0; i < mCount; ++i) {
+ list.add(get(i));
+ }
+ return list;
+ }
+
+ /**
* Return the number of {@link InputMethodSubtype} objects.
*/
public int getCount() {
diff --git a/core/java/android/widget/flags/notification_widget_flags.aconfig b/core/java/android/widget/flags/notification_widget_flags.aconfig
index 3a39631f8c81..503e542f715a 100644
--- a/core/java/android/widget/flags/notification_widget_flags.aconfig
+++ b/core/java/android/widget/flags/notification_widget_flags.aconfig
@@ -47,3 +47,13 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "messaging_child_request_layout"
+ namespace: "systemui"
+ description: "MessagingChild always needs to be measured during MessagingLinearLayout onMeasure."
+ bug: "324537506"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index e07acac52f2c..3d8237ea5389 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -16,6 +16,8 @@
package com.android.internal.widget;
+import static android.widget.flags.Flags.messagingChildRequestLayout;
+
import android.annotation.Nullable;
import android.annotation.Px;
import android.content.Context;
@@ -92,6 +94,10 @@ public class MessagingLinearLayout extends ViewGroup {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
lp.hide = true;
+ // Child always needs to be measured to calculate hide property correctly in onMeasure.
+ if (messagingChildRequestLayout()) {
+ child.requestLayout();
+ }
if (child instanceof MessagingChild) {
MessagingChild messagingChild = (MessagingChild) child;
// Whenever we encounter the message first, it's always first in the layout
diff --git a/core/res/res/layout/side_fps_toast.xml b/core/res/res/layout/side_fps_toast.xml
index 2c35c9b888cf..78299ab0ea99 100644
--- a/core/res/res/layout/side_fps_toast.xml
+++ b/core/res/res/layout/side_fps_toast.xml
@@ -25,6 +25,7 @@
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="6"
+ android:paddingBottom="10dp"
android:text="@string/fp_power_button_enrollment_title"
android:textColor="@color/side_fps_text_color"
android:paddingLeft="20dp"/>
@@ -36,6 +37,7 @@
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="3"
+ android:paddingBottom="10dp"
android:text="@string/fp_power_button_enrollment_button_text"
style="?android:attr/buttonBarNegativeButtonStyle"
android:textColor="@color/side_fps_button_color"
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 31acd9af164c..52662149b23a 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -93,4 +93,7 @@
<!-- If this is true, allow wake from theater mode from motion. -->
<bool name="config_allowTheaterModeWakeFromMotion">true</bool>
+
+ <!-- True if the device supports system decorations on secondary displays. -->
+ <bool name="config_supportsSystemDecorsOnSecondaryDisplays">false</bool>
</resources>
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index fe68123513ca..8977d5cad780 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -71,3 +71,10 @@ flag {
description: "Hides the bubble overflow if there aren't any overflowed bubbles"
bug: "334175587"
}
+
+flag {
+ name: "enable_retrievable_bubbles"
+ namespace: "multitasking"
+ description: "Allow opening bubbles overflow UI without bubbles being visible"
+ bug: "340337839"
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index be3f4108fdd1..888e39593a2e 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -274,6 +274,9 @@ public class SecureSettings {
Settings.Secure.SCREEN_RESOLUTION_MODE,
Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS,
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
- Settings.Secure.CHARGE_OPTIMIZATION_MODE
+ Settings.Secure.CHARGE_OPTIMIZATION_MODE,
+ Settings.Secure.ON_DEVICE_INTELLIGENCE_UNBIND_TIMEOUT_MS,
+ Settings.Secure.ON_DEVICE_INFERENCE_UNBIND_TIMEOUT_MS,
+ Settings.Secure.ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS,
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index b1feede57506..b992ddc8a397 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -18,6 +18,7 @@ package android.provider.settings.validators;
import static android.provider.settings.validators.SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.ANY_LONG_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.AUTOFILL_SERVICE_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
@@ -433,5 +434,8 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
new InclusiveIntegerRangeValidator(0, 10));
VALIDATORS.put(Secure.CHARGE_OPTIMIZATION_MODE, new InclusiveIntegerRangeValidator(0, 10));
+ VALIDATORS.put(Secure.ON_DEVICE_INFERENCE_UNBIND_TIMEOUT_MS, ANY_LONG_VALIDATOR);
+ VALIDATORS.put(Secure.ON_DEVICE_INTELLIGENCE_UNBIND_TIMEOUT_MS, ANY_LONG_VALIDATOR);
+ VALIDATORS.put(Secure.ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS, NONE_NEGATIVE_LONG_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
index 677c81ad9271..255b1ad3b3d2 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
@@ -239,6 +239,18 @@ public class SettingsValidators {
}
};
+ static final Validator ANY_LONG_VALIDATOR = value -> {
+ if (value == null) {
+ return true;
+ }
+ try {
+ Long.parseLong(value);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ };
+
static final Validator CREDENTIAL_SERVICE_VALIDATOR = new Validator() {
@Override
public boolean validate(String value) {
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index c04ec4f61c89..d2ca11207084 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -78,11 +78,23 @@ filegroup {
visibility: ["//visibility:private"],
}
+filegroup {
+ name: "SystemUI-tests-broken-robofiles-run",
+ srcs: [
+ "tests/src/**/systemui/util/LifecycleFragmentTest.java",
+ "tests/src/**/systemui/util/TestableAlertDialogTest.kt",
+ "tests/src/**/systemui/util/kotlin/PairwiseFlowTest",
+ "tests/src/**/systemui/util/sensors/AsyncManagerTest.java",
+ "tests/src/**/systemui/util/sensors/ThresholdSensorImplTest.java",
+ "tests/src/**/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java",
+ ],
+}
+
// We are running robolectric tests in the tests directory as well as
// multivalent tests. If you add a test, and it doesn't run in robolectric,
// it should be added to this exclusion list. go/multivalent-tests
filegroup {
- name: "SystemUI-tests-broken-robofiles",
+ name: "SystemUI-tests-broken-robofiles-compile",
srcs: [
"tests/src/**/*DeviceOnlyTest.java",
"tests/src/**/*DeviceOnlyTest.kt",
@@ -703,7 +715,8 @@ android_robolectric_test {
":SystemUI-tests-robofiles",
],
exclude_srcs: [
- ":SystemUI-tests-broken-robofiles",
+ ":SystemUI-tests-broken-robofiles-compile",
+ ":SystemUI-tests-broken-robofiles-run",
],
static_libs: [
"RoboTestLibraries",
diff --git a/packages/SystemUI/flag_check.py b/packages/SystemUI/flag_check.py
index bac3553e7498..95a25c58bc67 100755
--- a/packages/SystemUI/flag_check.py
+++ b/packages/SystemUI/flag_check.py
@@ -12,19 +12,20 @@ following case-sensitive regex:
%s
The Flag: stanza is regex matched and should describe whether your change is behind a flag or flags.
-
-As a CL author, you'll have a consistent place to describe the risk of the proposed change by explicitly calling out the name of the
-flag in addition to its state (ENABLED|DISABLED|DEVELOPMENT|STAGING|TEAMFOOD|TRUNKFOOD|NEXTFOOD).
+As a CL author, you'll have a consistent place to describe the risk of the proposed change by explicitly calling out the name of the flag.
+For legacy flags use EXEMPT with your flag name.
Some examples below:
-Flag: NONE
-Flag: NA
-Flag: LEGACY ENABLE_ONE_SEARCH DISABLED
-Flag: ACONFIG com.android.launcher3.enable_twoline_allapps DEVELOPMENT
-Flag: ACONFIG com.android.launcher3.enable_twoline_allapps TRUNKFOOD
+Flag: NONE Repohook Update
+Flag: TEST_ONLY
+Flag: EXEMPT resource only update
+Flag: EXEMPT bugfix
+Flag: EXEMPT refactor
+Flag: com.android.launcher3.enable_twoline_allapps
+Flag: com.google.android.apps.nexuslauncher.zero_state_web_data_loader
-Check the git history for more examples. It's a regex matched field.
+Check the git history for more examples. It's a regex matched field. See go/android-flag-directive for more details on various formats.
"""
def main():
@@ -63,28 +64,31 @@ def main():
return
field = 'Flag'
- none = '(NONE|NA|N\/A)' # NONE|NA|N/A
-
- typeExpression = '\s*(LEGACY|ACONFIG)' # [type:LEGACY|ACONFIG]
+ none = 'NONE'
+ testOnly = 'TEST_ONLY'
+ docsOnly = 'DOCS_ONLY'
+ exempt = 'EXEMPT'
+ justification = '<justification>'
- # legacyFlagName contains only uppercase alphabets with '_' - Ex: ENABLE_ONE_SEARCH
- # Aconfig Flag name format = "packageName"."flagName"
+ # Aconfig Flag name format = <packageName>.<flagName>
# package name - Contains only lowercase alphabets + digits + '.' - Ex: com.android.launcher3
- # For now alphabets, digits, "_", "." characters are allowed in flag name and not adding stricter format check.
+ # For now alphabets, digits, "_", "." characters are allowed in flag name.
+ # Checks if there is "one dot" between packageName and flagName and not adding stricter format check
#common_typos_disable
- flagName = '([a-zA-z0-9_.])+'
+ flagName = '([a-zA-Z0-9.]+)([.]+)([a-zA-Z0-9_.]+)'
- #[state:ENABLED|DISABLED|DEVELOPMENT|TEAM*(TEAMFOOD)|STAGING|TRUNK*(TRUNK_STAGING, TRUNK_FOOD)|NEXT*(NEXTFOOD)]
- stateExpression = '\s*(ENABLED|DISABLED|DEVELOPMENT|TEAM[a-zA-z]*|STAGING|TRUNK[a-zA-z]*|NEXT[a-zA-z]*)'
+ # None and Exempt needs justification
+ exemptRegex = fr'{exempt}\s*[a-zA-Z]+'
+ noneRegex = fr'{none}\s*[a-zA-Z]+'
#common_typos_enable
- readableRegexMsg = '\n\tFlag: (NONE|NA)\n\tFlag: LEGACY|ACONFIG FlagName|packageName.flagName ENABLED|DISABLED|DEVELOPMENT|TEAMFOOD|STAGING|TRUNKFOOD|NEXTFOOD'
+ readableRegexMsg = '\n\tFlag: '+none+' '+justification+'\n\tFlag: <packageName>.<flagName>\n\tFlag: ' +exempt+' '+justification+'\n\tFlag: '+testOnly+'\n\tFlag: '+docsOnly
flagRegex = fr'^{field}: .*$'
check_flag = re.compile(flagRegex) #Flag:
# Ignore case for flag name format.
- flagNameRegex = fr'(?i)^{field}:\s*({none}|{typeExpression}\s*{flagName}\s*{stateExpression})\s*'
+ flagNameRegex = fr'(?i)^{field}:\s*({noneRegex}|{flagName}|{testOnly}|{docsOnly}|{exemptRegex})\s*'
check_flagName = re.compile(flagNameRegex) #Flag: <flag name format>
flagError = False
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index b4b812d60a1a..0ab09595d6b0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -265,7 +265,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
// Device is dreaming and on communal.
- fakeKeyguardRepository.setDreaming(true)
+ updateDreaming(true)
communalInteractor.changeScene(CommunalScenes.Communal)
val scene by collectLastValue(communalInteractor.desiredScene)
@@ -282,7 +282,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
// Device is not dreaming and on communal.
- fakeKeyguardRepository.setDreaming(false)
+ updateDreaming(false)
communalInteractor.changeScene(CommunalScenes.Communal)
// Scene stays as Communal
@@ -297,7 +297,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
// Device is dreaming and on communal.
- fakeKeyguardRepository.setDreaming(true)
+ updateDreaming(true)
communalInteractor.changeScene(CommunalScenes.Communal)
val scene by collectLastValue(communalInteractor.desiredScene)
@@ -309,7 +309,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
// Dream stops, timeout is cancelled and device stays on hub, because the regular
// screen timeout will take effect at this point.
- fakeKeyguardRepository.setDreaming(false)
+ updateDreaming(false)
advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
}
@@ -320,7 +320,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
with(kosmos) {
testScope.runTest {
// Device is on communal, but not dreaming.
- fakeKeyguardRepository.setDreaming(false)
+ updateDreaming(false)
communalInteractor.changeScene(CommunalScenes.Communal)
val scene by collectLastValue(communalInteractor.desiredScene)
@@ -328,7 +328,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
// Wait a bit, but not long enough to timeout, then start dreaming.
advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- fakeKeyguardRepository.setDreaming(true)
+ updateDreaming(true)
assertThat(scene).isEqualTo(CommunalScenes.Communal)
// Device times out after one screen timeout interval, dream doesn't reset timeout.
@@ -338,11 +338,31 @@ class CommunalSceneStartableTest : SysuiTestCase() {
}
@Test
+ fun hubTimeout_dreamAfterInitialTimeout_goesToBlank() =
+ with(kosmos) {
+ testScope.runTest {
+ // Device is on communal.
+ communalInteractor.changeScene(CommunalScenes.Communal)
+
+ // Device stays on the hub after the timeout since we're not dreaming.
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds * 2)
+ val scene by collectLastValue(communalInteractor.desiredScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Start dreaming.
+ updateDreaming(true)
+
+ // Hub times out immediately.
+ assertThat(scene).isEqualTo(CommunalScenes.Blank)
+ }
+ }
+
+ @Test
fun hubTimeout_userActivityTriggered_resetsTimeout() =
with(kosmos) {
testScope.runTest {
// Device is dreaming and on communal.
- fakeKeyguardRepository.setDreaming(true)
+ updateDreaming(true)
communalInteractor.changeScene(CommunalScenes.Communal)
val scene by collectLastValue(communalInteractor.desiredScene)
@@ -371,7 +391,7 @@ class CommunalSceneStartableTest : SysuiTestCase() {
fakeSettings.putInt(Settings.System.SCREEN_OFF_TIMEOUT, SCREEN_TIMEOUT * 2)
// Device is dreaming and on communal.
- fakeKeyguardRepository.setDreaming(true)
+ updateDreaming(true)
communalInteractor.changeScene(CommunalScenes.Communal)
val scene by collectLastValue(communalInteractor.desiredScene)
@@ -395,6 +415,12 @@ class CommunalSceneStartableTest : SysuiTestCase() {
runCurrent()
}
+ private fun TestScope.updateDreaming(dreaming: Boolean) =
+ with(kosmos) {
+ fakeKeyguardRepository.setDreaming(dreaming)
+ runCurrent()
+ }
+
private suspend fun TestScope.enableCommunal() =
with(kosmos) {
setCommunalAvailable(true)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index 971ab111d2f6..6f20a8daf00a 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -42,6 +42,7 @@ import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
@@ -73,6 +74,10 @@ constructor(
) : CoreStartable {
private var screenTimeout: Int = DEFAULT_SCREEN_TIMEOUT
+ private var timeoutJob: Job? = null
+
+ private var isDreaming: Boolean = false
+
override fun start() {
// Handle automatically switching based on keyguard state.
keyguardTransitionInteractor.startedKeyguardTransitionStep
@@ -112,31 +117,35 @@ constructor(
}
.launchIn(bgScope)
- // Handle timing out back to the dream.
+ // The hub mode timeout should start as soon as the user enters hub mode. At the end of the
+ // timer, if the device is dreaming, hub mode should closed and reveal the dream. If the
+ // dream is not running, nothing will happen. However if the dream starts again underneath
+ // hub mode after the initial timeout expires, such as if the device is docked or the dream
+ // app is updated by the Play store, a new timeout should be started.
bgScope.launch {
combine(
communalInteractor.desiredScene,
// Emit a value on start so the combine starts.
communalInteractor.userActivity.emitOnStart()
) { scene, _ ->
- // Time out should run whenever we're dreaming and the hub is open, even if not
- // docked.
+ // Only timeout if we're on the hub is open.
scene == CommunalScenes.Communal
}
- // mapLatest cancels the previous action block when new values arrive, so any
- // already running timeout gets cancelled when conditions change or user interaction
- // is detected.
- .mapLatest { shouldTimeout ->
- if (!shouldTimeout) {
- return@mapLatest false
+ .collectLatest { shouldTimeout ->
+ cancelHubTimeout()
+ if (shouldTimeout) {
+ startHubTimeout()
}
-
- delay(screenTimeout.milliseconds)
- true
}
- .sample(keyguardInteractor.isDreaming, ::Pair)
- .collect { (shouldTimeout, isDreaming) ->
- if (isDreaming && shouldTimeout) {
+ }
+ bgScope.launch {
+ keyguardInteractor.isDreaming
+ .sample(communalInteractor.desiredScene, ::Pair)
+ .collectLatest { (isDreaming, scene) ->
+ this@CommunalSceneStartable.isDreaming = isDreaming
+ if (scene == CommunalScenes.Communal && isDreaming && timeoutJob == null) {
+ // If dreaming starts after timeout has expired, ex. if dream restarts under
+ // the hub, just close the hub immediately.
communalInteractor.changeScene(CommunalScenes.Blank)
}
}
@@ -151,6 +160,24 @@ constructor(
}
}
+ private fun cancelHubTimeout() {
+ timeoutJob?.cancel()
+ timeoutJob = null
+ }
+
+ private fun startHubTimeout() {
+ if (timeoutJob == null) {
+ timeoutJob =
+ bgScope.launch {
+ delay(screenTimeout.milliseconds)
+ if (isDreaming) {
+ communalInteractor.changeScene(CommunalScenes.Blank)
+ }
+ timeoutJob = null
+ }
+ }
+ }
+
private suspend fun determineSceneAfterTransition(
lastStartedTransition: TransitionStep,
): SceneKey? {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
index 31848a67698c..e1dcb145f20b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
@@ -1,8 +1,8 @@
package com.android.systemui.util
import android.graphics.Rect
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.wm.shell.common.FloatingContentCoordinator
@@ -14,7 +14,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class FloatingContentCoordinatorTest : SysuiTestCase() {
@@ -198,12 +198,11 @@ class FloatingContentCoordinatorTest : SysuiTestCase() {
}
/**
- * Helper class that uses [floatingCoordinator.findAreaForContentVertically] to move a
- * Rect when needed.
+ * Helper class that uses [floatingCoordinator.findAreaForContentVertically] to move a Rect when
+ * needed.
*/
- inner class FloatingRect(
- private val underlyingRect: Rect
- ) : FloatingContentCoordinator.FloatingContent {
+ inner class FloatingRect(private val underlyingRect: Rect) :
+ FloatingContentCoordinator.FloatingContent {
override fun moveToBounds(bounds: Rect) {
underlyingRect.set(bounds)
}
@@ -216,4 +215,4 @@ class FloatingContentCoordinatorTest : SysuiTestCase() {
return underlyingRect
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt
index 436f5b827ec6..457f2bb5d826 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt
@@ -19,12 +19,13 @@ package com.android.systemui.util
import android.content.BroadcastReceiver
import android.content.IntentFilter
import android.os.UserHandle
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.lifecycle.Observer
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
+import java.util.concurrent.Executor
import org.junit.After
import org.junit.Assert.assertTrue
import org.junit.Before
@@ -38,10 +39,9 @@ import org.mockito.Mockito.anyInt
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
-import java.util.concurrent.Executor
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class RingerModeLiveDataTest : SysuiTestCase() {
@@ -52,16 +52,11 @@ class RingerModeLiveDataTest : SysuiTestCase() {
private val INTENT = "INTENT"
}
- @Mock
- private lateinit var broadcastDispatcher: BroadcastDispatcher
- @Mock
- private lateinit var valueSupplier: () -> Int
- @Mock
- private lateinit var observer: Observer<Int>
- @Captor
- private lateinit var broadcastReceiverCaptor: ArgumentCaptor<BroadcastReceiver>
- @Captor
- private lateinit var intentFilterCaptor: ArgumentCaptor<IntentFilter>
+ @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
+ @Mock private lateinit var valueSupplier: () -> Int
+ @Mock private lateinit var observer: Observer<Int>
+ @Captor private lateinit var broadcastReceiverCaptor: ArgumentCaptor<BroadcastReceiver>
+ @Captor private lateinit var intentFilterCaptor: ArgumentCaptor<IntentFilter>
// Run everything immediately
private val executor = Executor { it.run() }
@@ -88,14 +83,14 @@ class RingerModeLiveDataTest : SysuiTestCase() {
fun testOnActive_broadcastRegistered() {
liveData.observeForever(observer)
verify(broadcastDispatcher)
- .registerReceiver(any(), any(), eq(executor), eq(UserHandle.ALL), anyInt(), any())
+ .registerReceiver(any(), any(), eq(executor), eq(UserHandle.ALL), anyInt(), any())
}
@Test
fun testOnActive_intentFilterHasIntent() {
liveData.observeForever(observer)
- verify(broadcastDispatcher).registerReceiver(any(), capture(intentFilterCaptor), any(),
- any(), anyInt(), any())
+ verify(broadcastDispatcher)
+ .registerReceiver(any(), capture(intentFilterCaptor), any(), any(), anyInt(), any())
assertTrue(intentFilterCaptor.value.hasAction(INTENT))
}
@@ -111,4 +106,4 @@ class RingerModeLiveDataTest : SysuiTestCase() {
liveData.removeObserver(observer)
verify(broadcastDispatcher).unregisterReceiver(any())
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
index b13cb72dc944..6271904b2f04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
@@ -19,10 +19,10 @@ package com.android.systemui.util
import android.app.WallpaperInfo
import android.app.WallpaperManager
import android.os.IBinder
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.View
import android.view.ViewRootImpl
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.eq
@@ -32,36 +32,30 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.any
import org.mockito.Mockito.anyFloat
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.doThrow
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
+import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnit
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
@SmallTest
class WallpaperControllerTest : SysuiTestCase() {
- @Mock
- private lateinit var wallpaperManager: WallpaperManager
- @Mock
- private lateinit var root: View
- @Mock
- private lateinit var viewRootImpl: ViewRootImpl
- @Mock
- private lateinit var windowToken: IBinder
+ @Mock private lateinit var wallpaperManager: WallpaperManager
+ @Mock private lateinit var root: View
+ @Mock private lateinit var viewRootImpl: ViewRootImpl
+ @Mock private lateinit var windowToken: IBinder
private val wallpaperRepository = FakeWallpaperRepository()
- @JvmField
- @Rule
- val mockitoRule = MockitoJUnit.rule()
+ @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
private lateinit var wallaperController: WallpaperController
@@ -92,9 +86,7 @@ class WallpaperControllerTest : SysuiTestCase() {
@Test
fun setUnfoldTransitionZoom_defaultUnfoldTransitionIsDisabled_doesNotUpdateWallpaperZoom() {
- wallpaperRepository.wallpaperInfo.value = createWallpaperInfo(
- useDefaultTransition = false
- )
+ wallpaperRepository.wallpaperInfo.value = createWallpaperInfo(useDefaultTransition = false)
wallaperController.setUnfoldTransitionZoom(0.5f)
@@ -130,7 +122,8 @@ class WallpaperControllerTest : SysuiTestCase() {
@Test
fun setNotificationZoom_exceptionWhenUpdatingZoom_doesNotFail() {
- doThrow(IllegalArgumentException("test exception")).`when`(wallpaperManager)
+ doThrow(IllegalArgumentException("test exception"))
+ .`when`(wallpaperManager)
.setWallpaperZoomOut(any(), anyFloat())
wallaperController.setNotificationShadeZoom(0.5f)
@@ -140,8 +133,7 @@ class WallpaperControllerTest : SysuiTestCase() {
private fun createWallpaperInfo(useDefaultTransition: Boolean = true): WallpaperInfo {
val info = mock(WallpaperInfo::class.java)
- whenever(info.shouldUseDefaultUnfoldTransition())
- .thenReturn(useDefaultTransition)
+ whenever(info.shouldUseDefaultUnfoldTransition()).thenReturn(useDefaultTransition)
return info
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
index 92afb038b321..b26598c80478 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
@@ -16,13 +16,16 @@
package com.android.systemui.util.animation
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
-import org.junit.Test
import java.lang.IllegalArgumentException
+import org.junit.runner.RunWith
+import org.junit.Test
@SmallTest
+@RunWith(AndroidJUnit4::class)
class AnimationUtilTest : SysuiTestCase() {
@Test
fun getMsForFrames_5frames_returns83() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
index 9dfa14dd0784..7dfac0ab2650 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
@@ -22,8 +22,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import android.testing.AndroidTestingRunner;
-
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -39,7 +38,7 @@ import java.util.ArrayList;
import java.util.List;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class FakeExecutorTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MessageRouterImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MessageRouterImplTest.java
index 78fc6803ea7e..48fb74514b01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MessageRouterImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MessageRouterImplTest.java
@@ -24,8 +24,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
-
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -39,7 +38,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class MessageRouterImplTest extends SysuiTestCase {
private static final int MESSAGE_A = 0;
private static final int MESSAGE_B = 1;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt
index 15032dc182d6..7ec420f0b6da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt
@@ -15,7 +15,7 @@
*/
package com.android.systemui.util.concurrency
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.time.FakeSystemClock
@@ -26,7 +26,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class MockExecutorHandlerTest : SysuiTestCase() {
/** Test FakeExecutor that receives non-delayed items to execute. */
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/RepeatableExecutorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/RepeatableExecutorTest.java
index 00f37ae6f6cb..13fff29d89ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/RepeatableExecutorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/RepeatableExecutorTest.java
@@ -18,8 +18,7 @@ package com.android.systemui.util.concurrency;
import static com.google.common.truth.Truth.assertThat;
-import android.testing.AndroidTestingRunner;
-
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -30,7 +29,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class RepeatableExecutorTest extends SysuiTestCase {
private static final int DELAY = 100;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java
index b367a603ec67..37015e30781e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java
@@ -23,8 +23,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
-
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.CoreStartable;
@@ -44,7 +43,7 @@ import java.util.HashSet;
import java.util.Set;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class ConditionalCoreStartableTest extends SysuiTestCase {
public static class FakeConditionalCoreStartable extends ConditionalCoreStartable {
interface Callback {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
index ac357ea34be0..b8f581574848 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
@@ -4,7 +4,7 @@ import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.ShapeDrawable
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -12,7 +12,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class DrawableSizeTest : SysuiTestCase() {
@@ -32,14 +32,11 @@ class DrawableSizeTest : SysuiTestCase() {
@Test
fun testDownscaleToSize_drawableSmallerThanRequirement_unchanged() {
- val drawable = BitmapDrawable(resources,
- Bitmap.createBitmap(
- resources.displayMetrics,
- 150,
- 150,
- Bitmap.Config.ARGB_8888
- )
- )
+ val drawable =
+ BitmapDrawable(
+ resources,
+ Bitmap.createBitmap(resources.displayMetrics, 150, 150, Bitmap.Config.ARGB_8888)
+ )
val result = DrawableSize.downscaleToSize(resources, drawable, 300, 300)
assertThat(result).isSameInstanceAs(drawable)
}
@@ -48,14 +45,11 @@ class DrawableSizeTest : SysuiTestCase() {
fun testDownscaleToSize_drawableLargerThanRequirementWithDensity_resized() {
// This bitmap would actually fail to resize if the method doesn't check for
// bitmap dimensions inside drawable.
- val drawable = BitmapDrawable(resources,
- Bitmap.createBitmap(
- resources.displayMetrics,
- 150,
- 75,
- Bitmap.Config.ARGB_8888
- )
- )
+ val drawable =
+ BitmapDrawable(
+ resources,
+ Bitmap.createBitmap(resources.displayMetrics, 150, 75, Bitmap.Config.ARGB_8888)
+ )
val result = DrawableSize.downscaleToSize(resources, drawable, 75, 75)
assertThat(result).isNotSameInstanceAs(drawable)
@@ -65,9 +59,9 @@ class DrawableSizeTest : SysuiTestCase() {
@Test
fun testDownscaleToSize_drawableAnimated_unchanged() {
- val drawable = resources.getDrawable(android.R.drawable.stat_sys_download,
- resources.newTheme())
+ val drawable =
+ resources.getDrawable(android.R.drawable.stat_sys_download, resources.newTheme())
val result = DrawableSize.downscaleToSize(resources, drawable, 1, 1)
assertThat(result).isSameInstanceAs(drawable)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
index 7d0d57b4037a..e2ce50ccb6da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
@@ -16,7 +16,7 @@
package com.android.systemui.util.kotlin
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.time.FakeSystemClock
@@ -47,7 +47,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class PairwiseFlowTest : SysuiTestCase() {
@Test
fun simple() = runBlocking {
@@ -89,7 +89,9 @@ class PairwiseFlowTest : SysuiTestCase() {
initRun = true
"initial"
}
- ) { prev: String, next: String -> "$prev|$next" }
+ ) { prev: String, next: String ->
+ "$prev|$next"
+ }
)
.emitsExactly("initial|val1", "val1|val2")
assertThat(initRun).isTrue()
@@ -104,7 +106,9 @@ class PairwiseFlowTest : SysuiTestCase() {
initRun = true
"initial"
}
- ) { prev: String, next: String -> "$prev|$next" }
+ ) { prev: String, next: String ->
+ "$prev|$next"
+ }
)
.emitsNothing()
// Even though the flow will not emit anything, the initial value function should still get
@@ -120,7 +124,9 @@ class PairwiseFlowTest : SysuiTestCase() {
initRun = true
"initial"
}
- ) { prev: String, next: String -> "$prev|$next" }
+ ) { prev: String, next: String ->
+ "$prev|$next"
+ }
// Since the flow isn't collected, ensure [initialValueFun] isn't run.
assertThat(initRun).isFalse()
@@ -146,7 +152,7 @@ class PairwiseFlowTest : SysuiTestCase() {
}
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class SetChangesFlowTest : SysuiTestCase() {
@Test
fun simple() = runBlocking {
@@ -198,7 +204,7 @@ class SetChangesFlowTest : SysuiTestCase() {
}
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class SampleFlowTest : SysuiTestCase() {
@Test
fun simple() = runBlocking {
@@ -240,7 +246,7 @@ class SampleFlowTest : SysuiTestCase() {
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ThrottleFlowTest : SysuiTestCase() {
@Test
@@ -248,13 +254,16 @@ class ThrottleFlowTest : SysuiTestCase() {
// Arrange
val choreographer = createChoreographer(this)
val output = mutableListOf<Int>()
- val collectJob = backgroundScope.launch {
- flow {
- emit(1)
- delay(1000)
- emit(2)
- }.throttle(1000, choreographer.fakeClock).toList(output)
- }
+ val collectJob =
+ backgroundScope.launch {
+ flow {
+ emit(1)
+ delay(1000)
+ emit(2)
+ }
+ .throttle(1000, choreographer.fakeClock)
+ .toList(output)
+ }
// Act
choreographer.advanceAndRun(0)
@@ -283,13 +292,16 @@ class ThrottleFlowTest : SysuiTestCase() {
// Arrange
val choreographer = createChoreographer(this)
val output = mutableListOf<Int>()
- val collectJob = backgroundScope.launch {
- flow {
- emit(1)
- delay(500)
- emit(2)
- }.throttle(1000, choreographer.fakeClock).toList(output)
- }
+ val collectJob =
+ backgroundScope.launch {
+ flow {
+ emit(1)
+ delay(500)
+ emit(2)
+ }
+ .throttle(1000, choreographer.fakeClock)
+ .toList(output)
+ }
// Act
choreographer.advanceAndRun(0)
@@ -319,15 +331,18 @@ class ThrottleFlowTest : SysuiTestCase() {
// Arrange
val choreographer = createChoreographer(this)
val output = mutableListOf<Int>()
- val collectJob = backgroundScope.launch {
- flow {
- emit(1)
- delay(500)
- emit(2)
- delay(500)
- emit(3)
- }.throttle(1000, choreographer.fakeClock).toList(output)
- }
+ val collectJob =
+ backgroundScope.launch {
+ flow {
+ emit(1)
+ delay(500)
+ emit(2)
+ delay(500)
+ emit(3)
+ }
+ .throttle(1000, choreographer.fakeClock)
+ .toList(output)
+ }
// Act
choreographer.advanceAndRun(0)
@@ -357,15 +372,18 @@ class ThrottleFlowTest : SysuiTestCase() {
// Arrange
val choreographer = createChoreographer(this)
val output = mutableListOf<Int>()
- val collectJob = backgroundScope.launch {
- flow {
- emit(1)
- delay(500)
- emit(2)
- delay(250)
- emit(3)
- }.throttle(1000, choreographer.fakeClock).toList(output)
- }
+ val collectJob =
+ backgroundScope.launch {
+ flow {
+ emit(1)
+ delay(500)
+ emit(2)
+ delay(250)
+ emit(3)
+ }
+ .throttle(1000, choreographer.fakeClock)
+ .toList(output)
+ }
// Act
choreographer.advanceAndRun(0)
@@ -391,15 +409,16 @@ class ThrottleFlowTest : SysuiTestCase() {
collectJob.cancel()
}
- private fun createChoreographer(testScope: TestScope) = object {
- val fakeClock = FakeSystemClock()
+ private fun createChoreographer(testScope: TestScope) =
+ object {
+ val fakeClock = FakeSystemClock()
- fun advanceAndRun(millis: Long) {
- fakeClock.advanceTime(millis)
- testScope.advanceTimeBy(millis)
- testScope.runCurrent()
+ fun advanceAndRun(millis: Long) {
+ fakeClock.advanceTime(millis)
+ testScope.advanceTimeBy(millis)
+ testScope.runCurrent()
+ }
}
- }
}
private fun <T> assertThatFlow(flow: Flow<T>) =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt
index 4ca1fd39682d..c31b287fddce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.util.kotlin
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import java.util.concurrent.atomic.AtomicLong
@@ -31,43 +31,42 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class IpcSerializerTest : SysuiTestCase() {
private val serializer = IpcSerializer()
@Ignore("b/253046405")
@Test
- fun serializeManyIncomingIpcs(): Unit = runBlocking(Dispatchers.Main.immediate) {
- val processor = launch(start = CoroutineStart.LAZY) { serializer.process() }
- withContext(Dispatchers.IO) {
- val lastEvaluatedTime = AtomicLong(System.currentTimeMillis())
- // First, launch many serialization requests in parallel
- repeat(100_000) {
- launch(Dispatchers.Unconfined) {
- val enqueuedTime = System.currentTimeMillis()
- serializer.runSerialized {
- val last = lastEvaluatedTime.getAndSet(enqueuedTime)
- assertTrue(
- "expected $last less than or equal to $enqueuedTime ",
- last <= enqueuedTime,
- )
+ fun serializeManyIncomingIpcs(): Unit =
+ runBlocking(Dispatchers.Main.immediate) {
+ val processor = launch(start = CoroutineStart.LAZY) { serializer.process() }
+ withContext(Dispatchers.IO) {
+ val lastEvaluatedTime = AtomicLong(System.currentTimeMillis())
+ // First, launch many serialization requests in parallel
+ repeat(100_000) {
+ launch(Dispatchers.Unconfined) {
+ val enqueuedTime = System.currentTimeMillis()
+ serializer.runSerialized {
+ val last = lastEvaluatedTime.getAndSet(enqueuedTime)
+ assertTrue(
+ "expected $last less than or equal to $enqueuedTime ",
+ last <= enqueuedTime,
+ )
+ }
}
}
+ // Then, process them all in the order they came in.
+ processor.start()
}
- // Then, process them all in the order they came in.
- processor.start()
+ // All done, stop processing
+ processor.cancel()
}
- // All done, stop processing
- processor.cancel()
- }
@Test(timeout = 5000)
fun serializeOnOneThread_doesNotDeadlock() = runBlocking {
val job = launch { serializer.process() }
- repeat(100) {
- serializer.runSerializedBlocking { }
- }
+ repeat(100) { serializer.runSerializedBlocking {} }
job.cancel()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
index 2013bb0a547e..8bfff9c209e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
@@ -27,13 +27,13 @@ import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-import org.junit.runners.Parameterized.Parameters
import org.mockito.Mock
import org.mockito.MockitoAnnotations
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@SmallTest
-@RunWith(Parameterized::class)
+@RunWith(ParameterizedAndroidJunit4::class)
internal class PackageManagerExtComponentEnabledTest(private val testCase: TestCase) :
SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
index 6848b836a348..b2f7c1aa0384 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
@@ -16,7 +16,7 @@
package com.android.systemui.util.kotlin
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -28,7 +28,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class RaceSuspendTest : SysuiTestCase() {
@Test
fun raceSimple() = runBlocking {
@@ -46,10 +46,11 @@ class RaceSuspendTest : SysuiTestCase() {
@Test
fun raceImmediate() = runBlocking {
assertThat(
- race<Int>(
- { 1 },
- { 2 },
+ race<Int>(
+ { 1 },
+ { 2 },
+ )
)
- ).isEqualTo(1)
+ .isEqualTo(1)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java
index 84129beea92a..300c29852ead 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java
@@ -26,9 +26,9 @@ import static org.mockito.Mockito.verify;
import android.content.res.Resources;
import android.hardware.Sensor;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -46,7 +46,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class PostureDependentProximitySensorTest extends SysuiTestCase {
@Mock private Resources mResources;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
index 19dbf9aa3c13..5dd008ac10f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
@@ -23,9 +23,9 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -40,7 +40,7 @@ import org.junit.runner.RunWith;
import java.util.function.Consumer;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class ProximityCheckTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java
index 5e7557896145..0eab74eb3cfb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java
@@ -24,9 +24,9 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -40,7 +40,7 @@ import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class ProximitySensorImplDualTest extends SysuiTestCase {
private ProximitySensor mProximitySensor;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java
index 752cd3211161..f44c842ad2eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java
@@ -21,9 +21,9 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -40,7 +40,7 @@ import org.mockito.MockitoAnnotations;
* Tests for ProximitySensor that rely on a single hardware sensor.
*/
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class ProximitySensorImplSingleTest extends SysuiTestCase {
private ProximitySensor mProximitySensor;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
index 8d26c877f4cf..a54afad617bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
@@ -30,8 +30,8 @@ import android.content.Intent;
import android.content.pm.UserInfo;
import android.os.IBinder;
import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -49,7 +49,7 @@ import java.util.List;
import java.util.Objects;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class ObservableServiceConnectionTest extends SysuiTestCase {
static class Foo {
int mValue;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/service/PackageObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/service/PackageObserverTest.java
index a2fd288ef33e..a70b00c8972d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/service/PackageObserverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/service/PackageObserverTest.java
@@ -24,8 +24,8 @@ import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -38,7 +38,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class PackageObserverTest extends SysuiTestCase {
@Mock
Context mContext;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/service/PersistentConnectionManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/service/PersistentConnectionManagerTest.java
index 55c49ee4360d..ef10fdf63741 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/service/PersistentConnectionManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/service/PersistentConnectionManagerTest.java
@@ -19,8 +19,7 @@ package com.android.systemui.util.service;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
-
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -37,7 +36,7 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class PersistentConnectionManagerTest extends SysuiTestCase {
private static final int MAX_RETRIES = 5;
private static final int RETRY_DELAY_MS = 1000;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
index f65caee24e34..99f6303ad73d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
@@ -28,8 +28,8 @@ import static org.mockito.Mockito.verify;
import android.database.ContentObserver;
import android.os.UserHandle;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -44,7 +44,7 @@ import java.util.Collection;
import java.util.Map;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class FakeSettingsTest extends SysuiTestCase {
@Mock
ContentObserver mContentObserver;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt
index 913759f77013..88b2630bd78f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.util.settings.repository
import android.content.pm.UserInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -33,11 +34,10 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class UserAwareSecureSettingsRepositoryTest : SysuiTestCase() {
private val dispatcher = StandardTestDispatcher()
@@ -48,11 +48,12 @@ class UserAwareSecureSettingsRepositoryTest : SysuiTestCase() {
@Before
fun setup() {
- repository = UserAwareSecureSettingsRepositoryImpl(
- secureSettings,
- userRepository,
- dispatcher,
- )
+ repository =
+ UserAwareSecureSettingsRepositoryImpl(
+ secureSettings,
+ userRepository,
+ dispatcher,
+ )
userRepository.setUserInfos(USER_INFOS)
setSettingValueForUser(enabled = true, userInfo = SETTING_ENABLED_USER)
setSettingValueForUser(enabled = false, userInfo = SETTING_DISABLED_USER)
@@ -105,4 +106,4 @@ class UserAwareSecureSettingsRepositoryTest : SysuiTestCase() {
val SETTING_DISABLED_USER = UserInfo(/* id= */ 1, "user2", /* flags= */ 0)
val USER_INFOS = listOf(SETTING_ENABLED_USER, SETTING_DISABLED_USER)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
index 94100fe7f4c4..6637d5f8de92 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.util.ui
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -30,7 +30,7 @@ import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class AnimatedValueTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
index e3cd9b2d6eaf..3dcb82811408 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
@@ -19,17 +19,20 @@ package com.android.systemui.util.view
import android.graphics.Rect
import android.view.View
import android.widget.TextView
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.spy
import org.mockito.Mockito.`when`
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ViewUtilTest : SysuiTestCase() {
private val viewUtil = ViewUtil()
private lateinit var view: View
@@ -45,11 +48,13 @@ class ViewUtilTest : SysuiTestCase() {
location[1] = VIEW_TOP
`when`(view.locationOnScreen).thenReturn(location)
doAnswer { invocation ->
- val pos = invocation.arguments[0] as IntArray
- pos[0] = VIEW_LEFT
- pos[1] = VIEW_TOP
- null
- }.`when`(view).getLocationInWindow(any())
+ val pos = invocation.arguments[0] as IntArray
+ pos[0] = VIEW_LEFT
+ pos[1] = VIEW_TOP
+ null
+ }
+ .`when`(view)
+ .getLocationInWindow(any())
}
@Test
@@ -59,9 +64,8 @@ class ViewUtilTest : SysuiTestCase() {
@Test
fun touchIsWithinView_onTopLeftCorner_returnsTrue() {
- assertThat(viewUtil.touchIsWithinView(
- view, VIEW_LEFT.toFloat(), VIEW_TOP.toFloat())
- ).isTrue()
+ assertThat(viewUtil.touchIsWithinView(view, VIEW_LEFT.toFloat(), VIEW_TOP.toFloat()))
+ .isTrue()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
index ed07ad2a0976..207c35da1892 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
@@ -35,15 +35,18 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
import java.util.List;
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
+
@SmallTest
-@RunWith(Parameterized.class)
+@RunWith(ParameterizedAndroidJunit4.class)
public class WakeLockTest extends SysuiTestCase {
- @Parameterized.Parameters(name = "{0}")
+ @Parameters(name = "{0}")
public static List<FlagsParameterization> getFlags() {
return FlagsParameterization.allCombinationsOf(
Flags.FLAG_DELAYED_WAKELOCK_RELEASE_ON_BACKGROUND_THREAD);
@@ -114,4 +117,4 @@ public class WakeLockTest extends SysuiTestCase {
// shouldn't throw an exception on production builds
mWakeLock.release(WHY);
}
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index d04dbc2f417e..d9e6186639ce 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -870,6 +870,7 @@ public final class PinnerService extends SystemService {
}
synchronized (this) {
pinnedApp.mFiles.add(pf);
+ mPinnedFiles.put(pf.fileName, pf);
}
apkPinSizeLimit -= pf.bytesPinned;
@@ -1341,18 +1342,6 @@ public final class PinnerService extends SystemService {
public List<PinnedFileStat> getPinnerStats() {
ArrayList<PinnedFileStat> stats = new ArrayList<>();
- Collection<PinnedApp> pinnedApps;
- synchronized(this) {
- pinnedApps = mPinnedApps.values();
- }
- for (PinnedApp pinnedApp : pinnedApps) {
- for (PinnedFile pf : pinnedApp.mFiles) {
- PinnedFileStat stat =
- new PinnedFileStat(pf.fileName, pf.bytesPinned, pf.groupName);
- stats.add(stat);
- }
- }
-
Collection<PinnedFile> pinnedFiles;
synchronized(this) {
pinnedFiles = mPinnedFiles.values();
diff --git a/services/core/java/com/android/server/inputmethod/ImeBindingState.java b/services/core/java/com/android/server/inputmethod/ImeBindingState.java
index 4c20c3b9784a..f78ea84efb77 100644
--- a/services/core/java/com/android/server/inputmethod/ImeBindingState.java
+++ b/services/core/java/com/android/server/inputmethod/ImeBindingState.java
@@ -21,7 +21,9 @@ import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_FOCU
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.os.IBinder;
+import android.os.UserHandle;
import android.util.Printer;
import android.util.proto.ProtoOutputStream;
import android.view.WindowManager;
@@ -36,6 +38,9 @@ import com.android.server.wm.WindowManagerInternal;
*/
final class ImeBindingState {
+ @UserIdInt
+ final int mUserId;
+
/**
* The last window token that we confirmed to be focused. This is always updated upon
* reports from the input method client. If the window state is already changed before the
@@ -90,6 +95,7 @@ final class ImeBindingState {
static ImeBindingState newEmptyState() {
return new ImeBindingState(
+ /*userId=*/ UserHandle.USER_NULL,
/*focusedWindow=*/ null,
/*focusedWindowSoftInputMode=*/ SOFT_INPUT_STATE_UNSPECIFIED,
/*focusedWindowClient=*/ null,
@@ -97,10 +103,12 @@ final class ImeBindingState {
);
}
- ImeBindingState(@Nullable IBinder focusedWindow,
+ ImeBindingState(@UserIdInt int userId,
+ @Nullable IBinder focusedWindow,
@SoftInputModeFlags int focusedWindowSoftInputMode,
@Nullable ClientState focusedWindowClient,
@Nullable EditorInfo focusedWindowEditorInfo) {
+ mUserId = userId;
mFocusedWindow = focusedWindow;
mFocusedWindowSoftInputMode = focusedWindowSoftInputMode;
mFocusedWindowClient = focusedWindowClient;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 691145c500d9..98f0102dc750 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1024,8 +1024,16 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
}
private void onFinishPackageChangesInternal() {
+ final int userId = getChangingUserId();
+
+ // Instantiating InputMethodInfo requires disk I/O.
+ // Do them before acquiring the lock to minimize the chances of ANR (b/340221861).
+ final var newMethodMapWithoutAdditionalSubtypes =
+ queryInputMethodServicesInternal(mContext, userId,
+ AdditionalSubtypeMap.EMPTY_MAP, DirectBootAwareness.AUTO)
+ .getMethodMap();
+
synchronized (ImfLock.class) {
- final int userId = getChangingUserId();
final boolean isCurrentUser = (userId == mCurrentUserId);
final AdditionalSubtypeMap additionalSubtypeMap =
AdditionalSubtypeMapRepository.get(userId);
@@ -1077,9 +1085,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
&& !(additionalSubtypeChanged || shouldRebuildInputMethodListLocked())) {
return;
}
-
- final InputMethodSettings newSettings = queryInputMethodServicesInternal(mContext,
- userId, newAdditionalSubtypeMap, DirectBootAwareness.AUTO);
+ final var newMethodMap = newMethodMapWithoutAdditionalSubtypes
+ .applyAdditionalSubtypes(newAdditionalSubtypeMap);
+ final InputMethodSettings newSettings =
+ InputMethodSettings.create(newMethodMap, userId);
InputMethodSettingsRepository.put(userId, newSettings);
if (!isCurrentUser) {
return;
@@ -3712,7 +3721,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
null, null, null, null, -1, false);
}
- mImeBindingState = new ImeBindingState(windowToken, softInputMode, cs, editorInfo);
+ mImeBindingState = new ImeBindingState(userData.mUserId, windowToken, softInputMode, cs,
+ editorInfo);
mFocusedWindowPerceptible.put(windowToken, true);
// We want to start input before showing the IME, but after closing
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMap.java b/services/core/java/com/android/server/inputmethod/InputMethodMap.java
index a8e5e2ef4f72..221309e4bf3e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMap.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMap.java
@@ -75,4 +75,28 @@ final class InputMethodMap {
int size() {
return mMap.size();
}
+
+ @AnyThread
+ @NonNull
+ public InputMethodMap applyAdditionalSubtypes(
+ @NonNull AdditionalSubtypeMap additionalSubtypeMap) {
+ if (additionalSubtypeMap.isEmpty()) {
+ return this;
+ }
+ final int size = size();
+ final ArrayMap<String, InputMethodInfo> newMethodMap = new ArrayMap<>(size);
+ boolean updated = false;
+ for (int i = 0; i < size; ++i) {
+ final var imi = valueAt(i);
+ final var imeId = imi.getId();
+ final var newAdditionalSubtypes = additionalSubtypeMap.get(imeId);
+ if (newAdditionalSubtypes == null || newAdditionalSubtypes.isEmpty()) {
+ newMethodMap.put(imi.getId(), imi);
+ } else {
+ newMethodMap.put(imi.getId(), new InputMethodInfo(imi, newAdditionalSubtypes));
+ updated = true;
+ }
+ }
+ return updated ? InputMethodMap.of(newMethodMap) : this;
+ }
}
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
index a0dbfa082978..4ec7a6fd0afc 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
@@ -412,10 +412,15 @@ import java.util.concurrent.atomic.AtomicInteger;
/* package */
synchronized void addTransaction(
ContextHubServiceTransaction transaction) throws IllegalStateException {
+ if (transaction == null) {
+ return;
+ }
+
if (mTransactionQueue.size() == MAX_PENDING_REQUESTS) {
throw new IllegalStateException("Transaction queue is full (capacity = "
+ MAX_PENDING_REQUESTS + ")");
}
+
mTransactionQueue.add(transaction);
mTransactionRecordDeque.add(new TransactionRecord(transaction.toString()));
diff --git a/services/core/java/com/android/server/net/NetworkManagementService.java b/services/core/java/com/android/server/net/NetworkManagementService.java
index d25f52973085..5ea3e70f7957 100644
--- a/services/core/java/com/android/server/net/NetworkManagementService.java
+++ b/services/core/java/com/android/server/net/NetworkManagementService.java
@@ -20,6 +20,9 @@ import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
@@ -31,6 +34,9 @@ import static android.net.INetd.FIREWALL_RULE_DENY;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_BACKGROUND;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_METERED_ALLOW;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_METERED_DENY_ADMIN;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_METERED_DENY_USER;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_RESTRICTED;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
@@ -143,6 +149,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
private final Object mQuotaLock = new Object();
private final Object mRulesLock = new Object();
+ private final boolean mUseMeteredFirewallChains;
+
/** Set of interfaces with active quotas. */
@GuardedBy("mQuotaLock")
private HashMap<String, Long> mActiveQuotas = Maps.newHashMap();
@@ -150,9 +158,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
@GuardedBy("mQuotaLock")
private HashMap<String, Long> mActiveAlerts = Maps.newHashMap();
/** Set of UIDs denied on metered networks. */
+ // TODO: b/336693007 - Remove once NPMS has completely migrated to metered firewall chains.
@GuardedBy("mRulesLock")
private SparseBooleanArray mUidRejectOnMetered = new SparseBooleanArray();
/** Set of UIDs allowed on metered networks. */
+ // TODO: b/336693007 - Remove once NPMS has completely migrated to metered firewall chains.
@GuardedBy("mRulesLock")
private SparseBooleanArray mUidAllowOnMetered = new SparseBooleanArray();
/** Set of UIDs with cleartext penalties. */
@@ -196,10 +206,32 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
@GuardedBy("mRulesLock")
private final SparseIntArray mUidFirewallBackgroundRules = new SparseIntArray();
+ /**
+ * Contains the per-UID firewall rules that are used to allowlist the app from metered-network
+ * restrictions when data saver is enabled.
+ */
+ @GuardedBy("mRulesLock")
+ private final SparseIntArray mUidMeteredFirewallAllowRules = new SparseIntArray();
+
+ /**
+ * Contains the per-UID firewall rules that are used to deny app access to metered networks
+ * due to user action.
+ */
+ @GuardedBy("mRulesLock")
+ private final SparseIntArray mUidMeteredFirewallDenyUserRules = new SparseIntArray();
+
+ /**
+ * Contains the per-UID firewall rules that are used to deny app access to metered networks
+ * due to admin action.
+ */
+ @GuardedBy("mRulesLock")
+ private final SparseIntArray mUidMeteredFirewallDenyAdminRules = new SparseIntArray();
+
/** Set of states for the child firewall chains. True if the chain is active. */
@GuardedBy("mRulesLock")
final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
+ // TODO: b/336693007 - Remove once NPMS has completely migrated to metered firewall chains.
@GuardedBy("mQuotaLock")
private volatile boolean mDataSaverMode;
@@ -217,6 +249,15 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
mContext = context;
mDeps = deps;
+ mUseMeteredFirewallChains = Flags.useMeteredFirewallChains();
+
+ if (mUseMeteredFirewallChains) {
+ // These firewalls are always on and currently ConnectivityService does not allow
+ // changing their enabled state.
+ mFirewallChainStates.put(FIREWALL_CHAIN_METERED_DENY_USER, true);
+ mFirewallChainStates.put(FIREWALL_CHAIN_METERED_DENY_ADMIN, true);
+ }
+
mDaemonHandler = new Handler(FgThread.get().getLooper());
mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener();
@@ -410,33 +451,39 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
}
}
- SparseBooleanArray uidRejectOnQuota = null;
- SparseBooleanArray uidAcceptOnQuota = null;
- synchronized (mRulesLock) {
- size = mUidRejectOnMetered.size();
- if (size > 0) {
- if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered denylist rules");
- uidRejectOnQuota = mUidRejectOnMetered;
- mUidRejectOnMetered = new SparseBooleanArray();
- }
+ if (!mUseMeteredFirewallChains) {
+ SparseBooleanArray uidRejectOnQuota = null;
+ SparseBooleanArray uidAcceptOnQuota = null;
+ synchronized (mRulesLock) {
+ size = mUidRejectOnMetered.size();
+ if (size > 0) {
+ if (DBG) {
+ Slog.d(TAG, "Pushing " + size + " UIDs to metered denylist rules");
+ }
+ uidRejectOnQuota = mUidRejectOnMetered;
+ mUidRejectOnMetered = new SparseBooleanArray();
+ }
- size = mUidAllowOnMetered.size();
- if (size > 0) {
- if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered allowlist rules");
- uidAcceptOnQuota = mUidAllowOnMetered;
- mUidAllowOnMetered = new SparseBooleanArray();
+ size = mUidAllowOnMetered.size();
+ if (size > 0) {
+ if (DBG) {
+ Slog.d(TAG, "Pushing " + size + " UIDs to metered allowlist rules");
+ }
+ uidAcceptOnQuota = mUidAllowOnMetered;
+ mUidAllowOnMetered = new SparseBooleanArray();
+ }
}
- }
- if (uidRejectOnQuota != null) {
- for (int i = 0; i < uidRejectOnQuota.size(); i++) {
- setUidOnMeteredNetworkDenylist(uidRejectOnQuota.keyAt(i),
- uidRejectOnQuota.valueAt(i));
+ if (uidRejectOnQuota != null) {
+ for (int i = 0; i < uidRejectOnQuota.size(); i++) {
+ setUidOnMeteredNetworkDenylist(uidRejectOnQuota.keyAt(i),
+ uidRejectOnQuota.valueAt(i));
+ }
}
- }
- if (uidAcceptOnQuota != null) {
- for (int i = 0; i < uidAcceptOnQuota.size(); i++) {
- setUidOnMeteredNetworkAllowlist(uidAcceptOnQuota.keyAt(i),
- uidAcceptOnQuota.valueAt(i));
+ if (uidAcceptOnQuota != null) {
+ for (int i = 0; i < uidAcceptOnQuota.size(); i++) {
+ setUidOnMeteredNetworkAllowlist(uidAcceptOnQuota.keyAt(i),
+ uidAcceptOnQuota.valueAt(i));
+ }
}
}
@@ -459,8 +506,16 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
syncFirewallChainLocked(FIREWALL_CHAIN_RESTRICTED, "restricted ");
syncFirewallChainLocked(FIREWALL_CHAIN_LOW_POWER_STANDBY, "low power standby ");
syncFirewallChainLocked(FIREWALL_CHAIN_BACKGROUND, FIREWALL_CHAIN_NAME_BACKGROUND);
+ if (mUseMeteredFirewallChains) {
+ syncFirewallChainLocked(FIREWALL_CHAIN_METERED_ALLOW,
+ FIREWALL_CHAIN_NAME_METERED_ALLOW);
+ syncFirewallChainLocked(FIREWALL_CHAIN_METERED_DENY_USER,
+ FIREWALL_CHAIN_NAME_METERED_DENY_USER);
+ syncFirewallChainLocked(FIREWALL_CHAIN_METERED_DENY_ADMIN,
+ FIREWALL_CHAIN_NAME_METERED_DENY_ADMIN);
+ }
- final int[] chains = {
+ final int[] chainsToEnable = {
FIREWALL_CHAIN_STANDBY,
FIREWALL_CHAIN_DOZABLE,
FIREWALL_CHAIN_POWERSAVE,
@@ -469,14 +524,13 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
FIREWALL_CHAIN_BACKGROUND,
};
- for (int chain : chains) {
+ for (int chain : chainsToEnable) {
if (getFirewallChainState(chain)) {
setFirewallChainEnabled(chain, true);
}
}
}
-
try {
getBatteryStats().noteNetworkStatsEnabled();
} catch (RemoteException e) {
@@ -1077,6 +1131,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
mContext.getSystemService(ConnectivityManager.class)
.setDataSaverEnabled(enable);
mDataSaverMode = enable;
+ if (mUseMeteredFirewallChains) {
+ // Copy mDataSaverMode state to FIREWALL_CHAIN_METERED_ALLOW
+ // until ConnectivityService allows manipulation of the data saver mode via
+ // FIREWALL_CHAIN_METERED_ALLOW.
+ synchronized (mRulesLock) {
+ mFirewallChainStates.put(FIREWALL_CHAIN_METERED_ALLOW, enable);
+ }
+ }
return true;
} else {
final boolean changed = mNetdService.bandwidthEnableDataSaver(enable);
@@ -1191,9 +1253,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
setFirewallChainState(chain, enable);
}
- final String chainName = getFirewallChainName(chain);
- if (chain == FIREWALL_CHAIN_NONE) {
- throw new IllegalArgumentException("Bad child chain: " + chainName);
+ if (!isValidFirewallChainForSetEnabled(chain)) {
+ throw new IllegalArgumentException("Invalid chain for setFirewallChainEnabled: "
+ + NetworkPolicyLogger.getFirewallChainName(chain));
}
final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
@@ -1205,38 +1267,29 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
}
}
- private String getFirewallChainName(int chain) {
- switch (chain) {
- case FIREWALL_CHAIN_STANDBY:
- return FIREWALL_CHAIN_NAME_STANDBY;
- case FIREWALL_CHAIN_DOZABLE:
- return FIREWALL_CHAIN_NAME_DOZABLE;
- case FIREWALL_CHAIN_POWERSAVE:
- return FIREWALL_CHAIN_NAME_POWERSAVE;
- case FIREWALL_CHAIN_RESTRICTED:
- return FIREWALL_CHAIN_NAME_RESTRICTED;
- case FIREWALL_CHAIN_LOW_POWER_STANDBY:
- return FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY;
- case FIREWALL_CHAIN_BACKGROUND:
- return FIREWALL_CHAIN_NAME_BACKGROUND;
- default:
- throw new IllegalArgumentException("Bad child chain: " + chain);
- }
+ private boolean isValidFirewallChainForSetEnabled(int chain) {
+ return switch (chain) {
+ case FIREWALL_CHAIN_STANDBY, FIREWALL_CHAIN_DOZABLE, FIREWALL_CHAIN_POWERSAVE,
+ FIREWALL_CHAIN_RESTRICTED, FIREWALL_CHAIN_LOW_POWER_STANDBY,
+ FIREWALL_CHAIN_BACKGROUND -> true;
+ // METERED_* firewall chains are not yet supported by
+ // ConnectivityService#setFirewallChainEnabled.
+ default -> false;
+ };
}
private int getFirewallType(int chain) {
switch (chain) {
case FIREWALL_CHAIN_STANDBY:
+ case FIREWALL_CHAIN_METERED_DENY_ADMIN:
+ case FIREWALL_CHAIN_METERED_DENY_USER:
return FIREWALL_DENYLIST;
case FIREWALL_CHAIN_DOZABLE:
- return FIREWALL_ALLOWLIST;
case FIREWALL_CHAIN_POWERSAVE:
- return FIREWALL_ALLOWLIST;
case FIREWALL_CHAIN_RESTRICTED:
- return FIREWALL_ALLOWLIST;
case FIREWALL_CHAIN_LOW_POWER_STANDBY:
- return FIREWALL_ALLOWLIST;
case FIREWALL_CHAIN_BACKGROUND:
+ case FIREWALL_CHAIN_METERED_ALLOW:
return FIREWALL_ALLOWLIST;
default:
return isFirewallEnabled() ? FIREWALL_ALLOWLIST : FIREWALL_DENYLIST;
@@ -1360,6 +1413,12 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
return mUidFirewallLowPowerStandbyRules;
case FIREWALL_CHAIN_BACKGROUND:
return mUidFirewallBackgroundRules;
+ case FIREWALL_CHAIN_METERED_ALLOW:
+ return mUidMeteredFirewallAllowRules;
+ case FIREWALL_CHAIN_METERED_DENY_USER:
+ return mUidMeteredFirewallDenyUserRules;
+ case FIREWALL_CHAIN_METERED_DENY_ADMIN:
+ return mUidMeteredFirewallDenyAdminRules;
case FIREWALL_CHAIN_NONE:
return mUidFirewallRules;
default:
@@ -1378,6 +1437,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ pw.println("Flags:");
+ pw.println(Flags.FLAG_USE_METERED_FIREWALL_CHAINS + ": " + mUseMeteredFirewallChains);
+ pw.println();
+
synchronized (mQuotaLock) {
pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
@@ -1416,6 +1479,27 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
pw.print("UID firewall background chain enabled: ");
pw.println(getFirewallChainState(FIREWALL_CHAIN_BACKGROUND));
dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_BACKGROUND, mUidFirewallBackgroundRules);
+
+ pw.print("UID firewall metered allow chain enabled (Data saver mode): ");
+ // getFirewallChainState should maintain a duplicated state from mDataSaverMode when
+ // mUseMeteredFirewallChains is enabled.
+ pw.println(getFirewallChainState(FIREWALL_CHAIN_METERED_ALLOW));
+ dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_METERED_ALLOW,
+ mUidMeteredFirewallAllowRules);
+
+ pw.print("UID firewall metered deny_user chain enabled (always-on): ");
+ // This always-on state should be reflected by getFirewallChainState when
+ // mUseMeteredFirewallChains is enabled.
+ pw.println(getFirewallChainState(FIREWALL_CHAIN_METERED_DENY_USER));
+ dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_METERED_DENY_USER,
+ mUidMeteredFirewallDenyUserRules);
+
+ pw.print("UID firewall metered deny_admin chain enabled (always-on): ");
+ // This always-on state should be reflected by getFirewallChainState when
+ // mUseMeteredFirewallChains is enabled.
+ pw.println(getFirewallChainState(FIREWALL_CHAIN_METERED_DENY_ADMIN));
+ dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_METERED_DENY_ADMIN,
+ mUidMeteredFirewallDenyAdminRules);
}
pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
@@ -1520,14 +1604,40 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because it is in background");
return true;
}
- if (mUidRejectOnMetered.get(uid)) {
- if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of no metered data"
- + " in the background");
- return true;
- }
- if (mDataSaverMode && !mUidAllowOnMetered.get(uid)) {
- if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of data saver mode");
- return true;
+ if (mUseMeteredFirewallChains) {
+ if (getFirewallChainState(FIREWALL_CHAIN_METERED_DENY_USER)
+ && mUidMeteredFirewallDenyUserRules.get(uid) == FIREWALL_RULE_DENY) {
+ if (DBG) {
+ Slog.d(TAG, "Uid " + uid + " restricted because of user-restricted metered"
+ + " data in the background");
+ }
+ return true;
+ }
+ if (getFirewallChainState(FIREWALL_CHAIN_METERED_DENY_ADMIN)
+ && mUidMeteredFirewallDenyAdminRules.get(uid) == FIREWALL_RULE_DENY) {
+ if (DBG) {
+ Slog.d(TAG, "Uid " + uid + " restricted because of admin-restricted metered"
+ + " data in the background");
+ }
+ return true;
+ }
+ if (getFirewallChainState(FIREWALL_CHAIN_METERED_ALLOW)
+ && mUidMeteredFirewallAllowRules.get(uid) != FIREWALL_RULE_ALLOW) {
+ if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of data saver mode");
+ return true;
+ }
+ } else {
+ if (mUidRejectOnMetered.get(uid)) {
+ if (DBG) {
+ Slog.d(TAG, "Uid " + uid
+ + " restricted because of no metered data in the background");
+ }
+ return true;
+ }
+ if (mDataSaverMode && !mUidAllowOnMetered.get(uid)) {
+ if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of data saver mode");
+ return true;
+ }
}
return false;
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 8e2d7780204a..681aa8aef219 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -19,6 +19,9 @@ import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
@@ -28,6 +31,9 @@ import static android.net.NetworkPolicyManager.ALLOWED_REASON_NONE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_BACKGROUND;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_METERED_ALLOW;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_METERED_DENY_ADMIN;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_METERED_DENY_USER;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_RESTRICTED;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
@@ -379,7 +385,7 @@ public class NetworkPolicyLogger {
return "Interfaces of netId=" + netId + " changed to " + newIfaces;
}
- private static String getFirewallChainName(int chain) {
+ static String getFirewallChainName(int chain) {
switch (chain) {
case FIREWALL_CHAIN_DOZABLE:
return FIREWALL_CHAIN_NAME_DOZABLE;
@@ -393,6 +399,12 @@ public class NetworkPolicyLogger {
return FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY;
case FIREWALL_CHAIN_BACKGROUND:
return FIREWALL_CHAIN_NAME_BACKGROUND;
+ case FIREWALL_CHAIN_METERED_ALLOW:
+ return FIREWALL_CHAIN_NAME_METERED_ALLOW;
+ case FIREWALL_CHAIN_METERED_DENY_USER:
+ return FIREWALL_CHAIN_NAME_METERED_DENY_USER;
+ case FIREWALL_CHAIN_METERED_DENY_ADMIN:
+ return FIREWALL_CHAIN_NAME_METERED_DENY_ADMIN;
default:
return String.valueOf(chain);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 22f5332e150c..c60ac3a74ebd 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -60,6 +60,9 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
@@ -514,6 +517,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
*/
private boolean mBackgroundNetworkRestricted;
+ /**
+ * Whether or not metered firewall chains should be used for uid policy controlling access to
+ * metered networks.
+ */
+ private boolean mUseMeteredFirewallChains;
+
// See main javadoc for instructions on how to use these locks.
final Object mUidRulesFirstLock = new Object();
final Object mNetworkPoliciesSecondLock = new Object();
@@ -997,6 +1006,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mAppStandby = LocalServices.getService(AppStandbyInternal.class);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+ mUseMeteredFirewallChains = Flags.useMeteredFirewallChains();
+
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
updatePowerSaveAllowlistUL();
@@ -4030,8 +4041,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
fout.println();
fout.println("Flags:");
- fout.println("Network blocked for TOP_SLEEPING and above: "
+ fout.println(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE + ": "
+ mBackgroundNetworkRestricted);
+ fout.println(Flags.FLAG_USE_METERED_FIREWALL_CHAINS + ": "
+ + mUseMeteredFirewallChains);
fout.println();
fout.println("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode);
@@ -5373,23 +5386,44 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
postUidRulesChangedMsg(uid, uidRules);
}
- // Note that the conditionals below are for avoiding unnecessary calls to netd.
- // TODO: Measure the performance for doing a no-op call to netd so that we can
- // remove the conditionals to simplify the logic below. We can also further reduce
- // some calls to netd if they turn out to be costly.
- final int denylistReasons = BLOCKED_METERED_REASON_ADMIN_DISABLED
- | BLOCKED_METERED_REASON_USER_RESTRICTED;
- if ((oldEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE
- || (newEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE) {
- setMeteredNetworkDenylist(uid,
- (newEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE);
- }
- final int allowlistReasons = ALLOWED_METERED_REASON_FOREGROUND
- | ALLOWED_METERED_REASON_USER_EXEMPTED;
- if ((oldAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE
- || (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE) {
- setMeteredNetworkAllowlist(uid,
- (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE);
+ if (mUseMeteredFirewallChains) {
+ if ((newEffectiveBlockedReasons & BLOCKED_METERED_REASON_ADMIN_DISABLED)
+ != BLOCKED_REASON_NONE) {
+ setUidFirewallRuleUL(FIREWALL_CHAIN_METERED_DENY_ADMIN, uid, FIREWALL_RULE_DENY);
+ } else {
+ setUidFirewallRuleUL(FIREWALL_CHAIN_METERED_DENY_ADMIN, uid, FIREWALL_RULE_DEFAULT);
+ }
+ if ((newEffectiveBlockedReasons & BLOCKED_METERED_REASON_USER_RESTRICTED)
+ != BLOCKED_REASON_NONE) {
+ setUidFirewallRuleUL(FIREWALL_CHAIN_METERED_DENY_USER, uid, FIREWALL_RULE_DENY);
+ } else {
+ setUidFirewallRuleUL(FIREWALL_CHAIN_METERED_DENY_USER, uid, FIREWALL_RULE_DEFAULT);
+ }
+ if ((newAllowedReasons & (ALLOWED_METERED_REASON_FOREGROUND
+ | ALLOWED_METERED_REASON_USER_EXEMPTED)) != ALLOWED_REASON_NONE) {
+ setUidFirewallRuleUL(FIREWALL_CHAIN_METERED_ALLOW, uid, FIREWALL_RULE_ALLOW);
+ } else {
+ setUidFirewallRuleUL(FIREWALL_CHAIN_METERED_ALLOW, uid, FIREWALL_RULE_DEFAULT);
+ }
+ } else {
+ // Note that the conditionals below are for avoiding unnecessary calls to netd.
+ // TODO: Measure the performance for doing a no-op call to netd so that we can
+ // remove the conditionals to simplify the logic below. We can also further reduce
+ // some calls to netd if they turn out to be costly.
+ final int denylistReasons = BLOCKED_METERED_REASON_ADMIN_DISABLED
+ | BLOCKED_METERED_REASON_USER_RESTRICTED;
+ if ((oldEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE
+ || (newEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE) {
+ setMeteredNetworkDenylist(uid,
+ (newEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE);
+ }
+ final int allowlistReasons = ALLOWED_METERED_REASON_FOREGROUND
+ | ALLOWED_METERED_REASON_USER_EXEMPTED;
+ if ((oldAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE
+ || (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE) {
+ setMeteredNetworkAllowlist(uid,
+ (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE);
+ }
}
}
@@ -6149,6 +6183,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} else if (chain == FIREWALL_CHAIN_BACKGROUND) {
mUidFirewallBackgroundRules.put(uid, rule);
}
+ // Note that we do not need keep a separate cache of uid rules for chains that we do
+ // not call #setUidFirewallRulesUL for.
try {
mNetworkManager.setFirewallUidRule(chain, uid, rule);
@@ -6206,10 +6242,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
FIREWALL_RULE_DEFAULT);
mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, uid,
FIREWALL_RULE_DEFAULT);
- mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, false);
- mLogger.meteredAllowlistChanged(uid, false);
- mNetworkManager.setUidOnMeteredNetworkDenylist(uid, false);
- mLogger.meteredDenylistChanged(uid, false);
+ if (mUseMeteredFirewallChains) {
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_METERED_DENY_ADMIN, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_METERED_DENY_USER, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_METERED_ALLOW, uid,
+ FIREWALL_RULE_DEFAULT);
+ } else {
+ mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, false);
+ mLogger.meteredAllowlistChanged(uid, false);
+ mNetworkManager.setUidOnMeteredNetworkDenylist(uid, false);
+ mLogger.meteredDenylistChanged(uid, false);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem resetting firewall uid rules for " + uid, e);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/net/flags.aconfig b/services/core/java/com/android/server/net/flags.aconfig
index d9491de52d87..e986dd81b94b 100644
--- a/services/core/java/com/android/server/net/flags.aconfig
+++ b/services/core/java/com/android/server/net/flags.aconfig
@@ -7,3 +7,13 @@ flag {
description: "Block network access for apps in a low importance background state"
bug: "304347838"
}
+
+flag {
+ name: "use_metered_firewall_chains"
+ namespace: "backstage_power"
+ description: "Use metered firewall chains to control access to metered networks"
+ bug: "336693007"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/ondeviceintelligence/BundleUtil.java b/services/core/java/com/android/server/ondeviceintelligence/BundleUtil.java
index a165d9b3075d..eb3f1e1e5363 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/BundleUtil.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/BundleUtil.java
@@ -42,7 +42,10 @@ import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
+import com.android.internal.infra.AndroidFuture;
+
import java.util.concurrent.Executor;
+import java.util.concurrent.TimeoutException;
/**
* Util methods for ensuring the Bundle passed in various methods are read-only and restricted to
@@ -181,7 +184,8 @@ public class BundleUtil {
public static IStreamingResponseCallback wrapWithValidation(
IStreamingResponseCallback streamingResponseCallback,
- Executor resourceClosingExecutor) {
+ Executor resourceClosingExecutor,
+ AndroidFuture future) {
return new IStreamingResponseCallback.Stub() {
@Override
public void onNewContent(Bundle processedResult) throws RemoteException {
@@ -201,6 +205,7 @@ public class BundleUtil {
streamingResponseCallback.onSuccess(resultBundle);
} finally {
resourceClosingExecutor.execute(() -> tryCloseResource(resultBundle));
+ future.complete(null);
}
}
@@ -208,6 +213,7 @@ public class BundleUtil {
public void onFailure(int errorCode, String errorMessage,
PersistableBundle errorParams) throws RemoteException {
streamingResponseCallback.onFailure(errorCode, errorMessage, errorParams);
+ future.completeExceptionally(new TimeoutException());
}
@Override
@@ -235,7 +241,8 @@ public class BundleUtil {
}
public static IResponseCallback wrapWithValidation(IResponseCallback responseCallback,
- Executor resourceClosingExecutor) {
+ Executor resourceClosingExecutor,
+ AndroidFuture future) {
return new IResponseCallback.Stub() {
@Override
public void onSuccess(Bundle resultBundle)
@@ -245,6 +252,7 @@ public class BundleUtil {
responseCallback.onSuccess(resultBundle);
} finally {
resourceClosingExecutor.execute(() -> tryCloseResource(resultBundle));
+ future.complete(null);
}
}
@@ -252,6 +260,7 @@ public class BundleUtil {
public void onFailure(int errorCode, String errorMessage,
PersistableBundle errorParams) throws RemoteException {
responseCallback.onFailure(errorCode, errorMessage, errorParams);
+ future.completeExceptionally(new TimeoutException());
}
@Override
@@ -278,17 +287,20 @@ public class BundleUtil {
}
- public static ITokenInfoCallback wrapWithValidation(ITokenInfoCallback responseCallback) {
+ public static ITokenInfoCallback wrapWithValidation(ITokenInfoCallback responseCallback,
+ AndroidFuture future) {
return new ITokenInfoCallback.Stub() {
@Override
public void onSuccess(TokenInfo tokenInfo) throws RemoteException {
responseCallback.onSuccess(tokenInfo);
+ future.complete(null);
}
@Override
public void onFailure(int errorCode, String errorMessage, PersistableBundle errorParams)
throws RemoteException {
responseCallback.onFailure(errorCode, errorMessage, errorParams);
+ future.completeExceptionally(new TimeoutException());
}
};
}
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
index 235e3cd7c9d2..b2e861cf2876 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
@@ -33,6 +33,7 @@ import android.annotation.RequiresPermission;
import android.app.AppGlobals;
import android.app.ondeviceintelligence.DownloadCallback;
import android.app.ondeviceintelligence.Feature;
+import android.app.ondeviceintelligence.FeatureDetails;
import android.app.ondeviceintelligence.IDownloadCallback;
import android.app.ondeviceintelligence.IFeatureCallback;
import android.app.ondeviceintelligence.IFeatureDetailsCallback;
@@ -64,6 +65,7 @@ import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.provider.DeviceConfig;
+import android.provider.Settings;
import android.service.ondeviceintelligence.IOnDeviceIntelligenceService;
import android.service.ondeviceintelligence.IOnDeviceSandboxedInferenceService;
import android.service.ondeviceintelligence.IProcessingUpdateStatusCallback;
@@ -82,13 +84,17 @@ import com.android.internal.infra.ServiceConnector;
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.ondeviceintelligence.callbacks.ListenableDownloadCallback;
import java.io.FileDescriptor;
import java.io.IOException;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* This is the system service for handling calls on the
@@ -135,7 +141,6 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
@GuardedBy("mLock")
private String[] mTemporaryServiceNames;
-
@GuardedBy("mLock")
private String[] mTemporaryBroadcastKeys;
@GuardedBy("mLock")
@@ -145,6 +150,8 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
* Handler used to reset the temporary service names.
*/
private Handler mTemporaryHandler;
+ private final @NonNull Handler mMainHandler = new Handler(Looper.getMainLooper());
+
public OnDeviceIntelligenceManagerService(Context context) {
super(context);
@@ -204,8 +211,16 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
return;
}
ensureRemoteIntelligenceServiceInitialized();
- mRemoteOnDeviceIntelligenceService.run(
- service -> service.getVersion(remoteCallback));
+ mRemoteOnDeviceIntelligenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ service.getVersion(new RemoteCallback(
+ result -> {
+ remoteCallback.sendResult(result);
+ future.complete(null);
+ }));
+ return future.orTimeout(getIdleTimeoutMs(), TimeUnit.MILLISECONDS);
+ });
}
@Override
@@ -225,8 +240,25 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
ensureRemoteIntelligenceServiceInitialized();
int callerUid = Binder.getCallingUid();
- mRemoteOnDeviceIntelligenceService.run(
- service -> service.getFeature(callerUid, id, featureCallback));
+ mRemoteOnDeviceIntelligenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ service.getFeature(callerUid, id, new IFeatureCallback.Stub() {
+ @Override
+ public void onSuccess(Feature result) throws RemoteException {
+ featureCallback.onSuccess(result);
+ future.complete(null);
+ }
+
+ @Override
+ public void onFailure(int errorCode, String errorMessage,
+ PersistableBundle errorParams) throws RemoteException {
+ featureCallback.onFailure(errorCode, errorMessage, errorParams);
+ future.completeExceptionally(new TimeoutException());
+ }
+ });
+ return future.orTimeout(getIdleTimeoutMs(), TimeUnit.MILLISECONDS);
+ });
}
@Override
@@ -246,9 +278,29 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
ensureRemoteIntelligenceServiceInitialized();
int callerUid = Binder.getCallingUid();
- mRemoteOnDeviceIntelligenceService.run(
- service -> service.listFeatures(callerUid,
- listFeaturesCallback));
+ mRemoteOnDeviceIntelligenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ service.listFeatures(callerUid,
+ new IListFeaturesCallback.Stub() {
+ @Override
+ public void onSuccess(List<Feature> result)
+ throws RemoteException {
+ listFeaturesCallback.onSuccess(result);
+ future.complete(null);
+ }
+
+ @Override
+ public void onFailure(int errorCode, String errorMessage,
+ PersistableBundle errorParams)
+ throws RemoteException {
+ listFeaturesCallback.onFailure(errorCode, errorMessage,
+ errorParams);
+ future.completeExceptionally(new TimeoutException());
+ }
+ });
+ return future.orTimeout(getIdleTimeoutMs(), TimeUnit.MILLISECONDS);
+ });
}
@Override
@@ -270,9 +322,29 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
ensureRemoteIntelligenceServiceInitialized();
int callerUid = Binder.getCallingUid();
- mRemoteOnDeviceIntelligenceService.run(
- service -> service.getFeatureDetails(callerUid, feature,
- featureDetailsCallback));
+ mRemoteOnDeviceIntelligenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ service.getFeatureDetails(callerUid, feature,
+ new IFeatureDetailsCallback.Stub() {
+ @Override
+ public void onSuccess(FeatureDetails result)
+ throws RemoteException {
+ future.complete(null);
+ featureDetailsCallback.onSuccess(result);
+ }
+
+ @Override
+ public void onFailure(int errorCode, String errorMessage,
+ PersistableBundle errorParams)
+ throws RemoteException {
+ future.completeExceptionally(null);
+ featureDetailsCallback.onFailure(errorCode,
+ errorMessage, errorParams);
+ }
+ });
+ return future.orTimeout(getIdleTimeoutMs(), TimeUnit.MILLISECONDS);
+ });
}
@Override
@@ -293,10 +365,20 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
ensureRemoteIntelligenceServiceInitialized();
int callerUid = Binder.getCallingUid();
- mRemoteOnDeviceIntelligenceService.run(
- service -> service.requestFeatureDownload(callerUid, feature,
- wrapCancellationFuture(cancellationSignalFuture),
- downloadCallback));
+ mRemoteOnDeviceIntelligenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ ListenableDownloadCallback listenableDownloadCallback =
+ new ListenableDownloadCallback(
+ downloadCallback,
+ mMainHandler, future, getIdleTimeoutMs());
+ service.requestFeatureDownload(callerUid, feature,
+ wrapCancellationFuture(cancellationSignalFuture),
+ listenableDownloadCallback);
+ return future; // this future has no timeout because, actual download
+ // might take long, but we fail early if there is no progress callbacks.
+ }
+ );
}
@@ -323,11 +405,15 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
ensureRemoteInferenceServiceInitialized();
int callerUid = Binder.getCallingUid();
- result = mRemoteInferenceService.post(
- service -> service.requestTokenInfo(callerUid, feature,
- request,
- wrapCancellationFuture(cancellationSignalFuture),
- wrapWithValidation(tokenInfoCallback)));
+ result = mRemoteInferenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ service.requestTokenInfo(callerUid, feature,
+ request,
+ wrapCancellationFuture(cancellationSignalFuture),
+ wrapWithValidation(tokenInfoCallback, future));
+ return future.orTimeout(getIdleTimeoutMs(), TimeUnit.MILLISECONDS);
+ });
result.whenCompleteAsync((c, e) -> BundleUtil.tryCloseResource(request),
resourceClosingExecutor);
} finally {
@@ -362,13 +448,18 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
ensureRemoteInferenceServiceInitialized();
int callerUid = Binder.getCallingUid();
- result = mRemoteInferenceService.post(
- service -> service.processRequest(callerUid, feature,
- request,
- requestType,
- wrapCancellationFuture(cancellationSignalFuture),
- wrapProcessingFuture(processingSignalFuture),
- wrapWithValidation(responseCallback, resourceClosingExecutor)));
+ result = mRemoteInferenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ service.processRequest(callerUid, feature,
+ request,
+ requestType,
+ wrapCancellationFuture(cancellationSignalFuture),
+ wrapProcessingFuture(processingSignalFuture),
+ wrapWithValidation(responseCallback,
+ resourceClosingExecutor, future));
+ return future.orTimeout(getIdleTimeoutMs(), TimeUnit.MILLISECONDS);
+ });
result.whenCompleteAsync((c, e) -> BundleUtil.tryCloseResource(request),
resourceClosingExecutor);
} finally {
@@ -402,13 +493,18 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
}
ensureRemoteInferenceServiceInitialized();
int callerUid = Binder.getCallingUid();
- result = mRemoteInferenceService.post(
- service -> service.processRequestStreaming(callerUid,
- feature,
- request, requestType,
- wrapCancellationFuture(cancellationSignalFuture),
- wrapProcessingFuture(processingSignalFuture),
- streamingCallback));
+ result = mRemoteInferenceService.postAsync(
+ service -> {
+ AndroidFuture future = new AndroidFuture();
+ service.processRequestStreaming(callerUid,
+ feature,
+ request, requestType,
+ wrapCancellationFuture(cancellationSignalFuture),
+ wrapProcessingFuture(processingSignalFuture),
+ wrapWithValidation(streamingCallback,
+ resourceClosingExecutor, future));
+ return future.orTimeout(getIdleTimeoutMs(), TimeUnit.MILLISECONDS);
+ });
result.whenCompleteAsync((c, e) -> BundleUtil.tryCloseResource(request),
resourceClosingExecutor);
} finally {
@@ -859,4 +955,10 @@ public class OnDeviceIntelligenceManagerService extends SystemService {
return mTemporaryHandler;
}
+
+ private long getIdleTimeoutMs() {
+ return Settings.Secure.getLongForUser(mContext.getContentResolver(),
+ Settings.Secure.ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS, TimeUnit.HOURS.toMillis(1),
+ mContext.getUserId());
+ }
}
diff --git a/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceIntelligenceService.java b/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceIntelligenceService.java
index 48258d7bea72..ac9747aa83b3 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceIntelligenceService.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceIntelligenceService.java
@@ -22,17 +22,21 @@ import static android.content.Context.BIND_INCLUDE_CAPABILITIES;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.provider.Settings;
import android.service.ondeviceintelligence.IOnDeviceIntelligenceService;
import android.service.ondeviceintelligence.OnDeviceIntelligenceService;
import com.android.internal.infra.ServiceConnector;
+import java.util.concurrent.TimeUnit;
+
/**
* Manages the connection to the remote on-device intelligence service. Also, handles unbinding
* logic set by the service implementation via a Secure Settings flag.
*/
public class RemoteOnDeviceIntelligenceService extends
ServiceConnector.Impl<IOnDeviceIntelligenceService> {
+ private static final long LONG_TIMEOUT = TimeUnit.HOURS.toMillis(4);
private static final String TAG =
RemoteOnDeviceIntelligenceService.class.getSimpleName();
@@ -48,9 +52,15 @@ public class RemoteOnDeviceIntelligenceService extends
}
@Override
+ protected long getRequestTimeoutMs() {
+ return LONG_TIMEOUT;
+ }
+
+ @Override
protected long getAutoDisconnectTimeoutMs() {
- // Disable automatic unbinding.
- // TODO: add logic to fetch this flag via SecureSettings.
- return -1;
+ return Settings.Secure.getLongForUser(mContext.getContentResolver(),
+ Settings.Secure.ON_DEVICE_INTELLIGENCE_UNBIND_TIMEOUT_MS,
+ TimeUnit.SECONDS.toMillis(30),
+ mContext.getUserId());
}
}
diff --git a/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceSandboxedInferenceService.java b/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceSandboxedInferenceService.java
index 69ba1d2fb599..18b13838ea7c 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceSandboxedInferenceService.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceSandboxedInferenceService.java
@@ -22,18 +22,24 @@ import static android.content.Context.BIND_INCLUDE_CAPABILITIES;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.provider.Settings;
import android.service.ondeviceintelligence.IOnDeviceSandboxedInferenceService;
import android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService;
import com.android.internal.infra.ServiceConnector;
+import java.util.concurrent.TimeUnit;
+
/**
- * Manages the connection to the remote on-device sand boxed inference service. Also, handles unbinding
+ * Manages the connection to the remote on-device sand boxed inference service. Also, handles
+ * unbinding
* logic set by the service implementation via a SecureSettings flag.
*/
public class RemoteOnDeviceSandboxedInferenceService extends
ServiceConnector.Impl<IOnDeviceSandboxedInferenceService> {
+ private static final long LONG_TIMEOUT = TimeUnit.HOURS.toMillis(1);
+
/**
* Creates an instance of {@link ServiceConnector}
*
@@ -54,11 +60,17 @@ public class RemoteOnDeviceSandboxedInferenceService extends
connect();
}
+ @Override
+ protected long getRequestTimeoutMs() {
+ return LONG_TIMEOUT;
+ }
+
@Override
protected long getAutoDisconnectTimeoutMs() {
- // Disable automatic unbinding.
- // TODO: add logic to fetch this flag via SecureSettings.
- return -1;
+ return Settings.Secure.getLongForUser(mContext.getContentResolver(),
+ Settings.Secure.ON_DEVICE_INFERENCE_UNBIND_TIMEOUT_MS,
+ TimeUnit.SECONDS.toMillis(30),
+ mContext.getUserId());
}
}
diff --git a/services/core/java/com/android/server/ondeviceintelligence/callbacks/ListenableDownloadCallback.java b/services/core/java/com/android/server/ondeviceintelligence/callbacks/ListenableDownloadCallback.java
new file mode 100644
index 000000000000..32f0698a8f9c
--- /dev/null
+++ b/services/core/java/com/android/server/ondeviceintelligence/callbacks/ListenableDownloadCallback.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.ondeviceintelligence.callbacks;
+
+import android.app.ondeviceintelligence.IDownloadCallback;
+import android.os.Handler;
+import android.os.PersistableBundle;
+import android.os.RemoteException;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This class extends the {@link IDownloadCallback} and adds a timeout Runnable to the callback
+ * such that, in the case where the callback methods are not invoked, we do not have to wait for
+ * timeout based on {@link #onDownloadCompleted} which might take minutes or hours to complete in
+ * some cases. Instead, in such cases we rely on the remote service sending progress updates and if
+ * there are *no* progress callbacks in the duration of {@link #idleTimeoutMs}, we can assume the
+ * download will not complete and enabling faster cleanup.
+ */
+public class ListenableDownloadCallback extends IDownloadCallback.Stub implements Runnable {
+ private final IDownloadCallback callback;
+ private final Handler handler;
+ private final AndroidFuture future;
+ private final long idleTimeoutMs;
+
+ /**
+ * Constructor to create a ListenableDownloadCallback.
+ *
+ * @param callback callback to send download updates to caller.
+ * @param handler handler to schedule timeout runnable.
+ * @param future future to complete to signal the callback has reached a terminal state.
+ * @param idleTimeoutMs timeout within which download updates should be received.
+ */
+ public ListenableDownloadCallback(IDownloadCallback callback, Handler handler,
+ AndroidFuture future,
+ long idleTimeoutMs) {
+ this.callback = callback;
+ this.handler = handler;
+ this.future = future;
+ this.idleTimeoutMs = idleTimeoutMs;
+ handler.postDelayed(this,
+ idleTimeoutMs); // init the timeout runnable in case no callback is ever invoked
+ }
+
+ @Override
+ public void onDownloadStarted(long bytesToDownload) throws RemoteException {
+ callback.onDownloadStarted(bytesToDownload);
+ handler.removeCallbacks(this);
+ handler.postDelayed(this, idleTimeoutMs);
+ }
+
+ @Override
+ public void onDownloadProgress(long bytesDownloaded) throws RemoteException {
+ callback.onDownloadProgress(bytesDownloaded);
+ handler.removeCallbacks(this); // remove previously queued timeout tasks.
+ handler.postDelayed(this, idleTimeoutMs); // queue fresh timeout task for next update.
+ }
+
+ @Override
+ public void onDownloadFailed(int failureStatus,
+ String errorMessage, PersistableBundle errorParams) throws RemoteException {
+ callback.onDownloadFailed(failureStatus, errorMessage, errorParams);
+ handler.removeCallbacks(this);
+ future.completeExceptionally(new TimeoutException());
+ }
+
+ @Override
+ public void onDownloadCompleted(
+ android.os.PersistableBundle downloadParams) throws RemoteException {
+ callback.onDownloadCompleted(downloadParams);
+ handler.removeCallbacks(this);
+ future.complete(null);
+ }
+
+ @Override
+ public void run() {
+ future.completeExceptionally(
+ new TimeoutException()); // complete the future as we haven't received updates
+ // for download progress.
+ }
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index e3e478d5ce9f..3beeaedb59cc 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -61,7 +61,6 @@ import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STA
import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__UNKNOWN;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.stats.Flags.addMobileBytesTransferByProcStatePuller;
-import static com.android.server.stats.Flags.statsPullNetworkStatsManagerInitOrderFix;
import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
import static com.android.server.stats.pull.ProcfsMemoryUtil.getProcessCmdlines;
@@ -431,12 +430,6 @@ public class StatsPullAtomService extends SystemService {
public static final boolean ENABLE_MOBILE_DATA_STATS_AGGREGATED_PULLER =
addMobileBytesTransferByProcStatePuller();
- /**
- * Whether or not to enable the mNetworkStatsManager initialization order fix
- */
- private static final boolean ENABLE_NETWORK_STATS_MANAGER_INIT_ORDER_FIX =
- statsPullNetworkStatsManagerInitOrderFix();
-
// Puller locks
private final Object mDataBytesTransferLock = new Object();
private final Object mBluetoothBytesTransferLock = new Object();
@@ -840,7 +833,7 @@ public class StatsPullAtomService extends SystemService {
registerEventListeners();
});
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
- if (ENABLE_NETWORK_STATS_MANAGER_INIT_ORDER_FIX) {
+ if (true) {
initNetworkStatsManager();
}
BackgroundThread.getHandler().post(() -> {
@@ -863,7 +856,7 @@ public class StatsPullAtomService extends SystemService {
mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
mStatsSubscriptionsListener = new StatsSubscriptionsListener(mSubscriptionManager);
mStorageManager = (StorageManager) mContext.getSystemService(StorageManager.class);
- if (!ENABLE_NETWORK_STATS_MANAGER_INIT_ORDER_FIX) {
+ if (false) {
initNetworkStatsManager();
}
@@ -1047,7 +1040,7 @@ public class StatsPullAtomService extends SystemService {
*/
@NonNull
private NetworkStatsManager getNetworkStatsManager() {
- if (ENABLE_NETWORK_STATS_MANAGER_INIT_ORDER_FIX) {
+ if (true) {
if (mNetworkStatsManager == null) {
throw new IllegalStateException("NetworkStatsManager is not ready");
}
diff --git a/services/core/java/com/android/server/stats/stats_flags.aconfig b/services/core/java/com/android/server/stats/stats_flags.aconfig
index c479c6d11164..6faa2737ac30 100644
--- a/services/core/java/com/android/server/stats/stats_flags.aconfig
+++ b/services/core/java/com/android/server/stats/stats_flags.aconfig
@@ -8,11 +8,3 @@ flag {
bug: "309512867"
is_fixed_read_only: true
}
-
-flag {
- name: "stats_pull_network_stats_manager_init_order_fix"
- namespace: "statsd"
- description: "Fix the mNetworkStatsManager initialization order"
- bug: "331989853"
- is_fixed_read_only: true
-}
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index 27c522d68119..b56af87ee020 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -25,6 +25,13 @@
value="/data/local/tmp/cts/content/broken_shortcut.xml" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="force-skip-system-props" value="true" />
+ <option name="set-global-setting" key="verifier_engprod" value="1" />
+ <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" />
+ <option name="restore-settings" value="true" />
+ </target_preparer>
+
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="install-arg" value="-t" />
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
index 07fb9fc2f509..570256bf43e6 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
@@ -19,9 +19,16 @@ package com.android.server.net;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
+import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
+import static android.net.ConnectivityManager.FIREWALL_RULE_DEFAULT;
+import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static android.util.DebugUtils.valueToString;
import static org.junit.Assert.assertEquals;
@@ -51,7 +58,10 @@ import android.os.PermissionEnforcer;
import android.os.Process;
import android.os.RemoteException;
import android.os.test.FakePermissionEnforcer;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArrayMap;
import androidx.test.filters.SmallTest;
@@ -62,6 +72,7 @@ import com.android.modules.utils.build.SdkLevel;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -84,6 +95,9 @@ public class NetworkManagementServiceTest {
@Mock private IBatteryStats.Stub mBatteryStatsService;
@Mock private INetd.Stub mNetdService;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+
private static final int TEST_UID = 111;
@NonNull
@@ -254,6 +268,7 @@ public class NetworkManagementServiceTest {
}
@Test
+ @DisableFlags(Flags.FLAG_USE_METERED_FIREWALL_CHAINS)
public void testMeteredNetworkRestrictions() throws RemoteException {
// Make sure the mocked netd method returns true.
doReturn(true).when(mNetdService).bandwidthEnableDataSaver(anyBoolean());
@@ -295,6 +310,69 @@ public class NetworkManagementServiceTest {
}
@Test
+ @EnableFlags(Flags.FLAG_USE_METERED_FIREWALL_CHAINS)
+ public void testMeteredNetworkRestrictionsByAdminChain() {
+ mNMService.setFirewallUidRule(FIREWALL_CHAIN_METERED_DENY_ADMIN, TEST_UID,
+ FIREWALL_RULE_DENY);
+ verify(mCm).setUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_ADMIN, TEST_UID,
+ FIREWALL_RULE_DENY);
+ assertTrue("Should be true since mobile data usage is restricted by admin chain",
+ mNMService.isNetworkRestricted(TEST_UID));
+
+ mNMService.setFirewallUidRule(FIREWALL_CHAIN_METERED_DENY_ADMIN, TEST_UID,
+ FIREWALL_RULE_DEFAULT);
+ verify(mCm).setUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_ADMIN, TEST_UID,
+ FIREWALL_RULE_DEFAULT);
+ assertFalse("Should be false since mobile data usage is no longer restricted by admin",
+ mNMService.isNetworkRestricted(TEST_UID));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_USE_METERED_FIREWALL_CHAINS)
+ public void testMeteredNetworkRestrictionsByUserChain() {
+ mNMService.setFirewallUidRule(FIREWALL_CHAIN_METERED_DENY_USER, TEST_UID,
+ FIREWALL_RULE_DENY);
+ verify(mCm).setUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_USER, TEST_UID,
+ FIREWALL_RULE_DENY);
+ assertTrue("Should be true since mobile data usage is restricted by user chain",
+ mNMService.isNetworkRestricted(TEST_UID));
+
+ mNMService.setFirewallUidRule(FIREWALL_CHAIN_METERED_DENY_USER, TEST_UID,
+ FIREWALL_RULE_DEFAULT);
+ verify(mCm).setUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_USER, TEST_UID,
+ FIREWALL_RULE_DEFAULT);
+ assertFalse("Should be false since mobile data usage is no longer restricted by user",
+ mNMService.isNetworkRestricted(TEST_UID));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_USE_METERED_FIREWALL_CHAINS)
+ public void testDataSaverRestrictionsWithAllowChain() {
+ mNMService.setDataSaverModeEnabled(true);
+ verify(mCm).setDataSaverEnabled(true);
+
+ assertTrue("Should be true since data saver is on and the uid is not allowlisted",
+ mNMService.isNetworkRestricted(TEST_UID));
+
+ mNMService.setFirewallUidRule(FIREWALL_CHAIN_METERED_ALLOW, TEST_UID, FIREWALL_RULE_ALLOW);
+ verify(mCm).setUidFirewallRule(FIREWALL_CHAIN_METERED_ALLOW, TEST_UID, FIREWALL_RULE_ALLOW);
+ assertFalse("Should be false since data saver is on and the uid is allowlisted",
+ mNMService.isNetworkRestricted(TEST_UID));
+
+ // remove uid from allowlist and turn datasaver off again
+
+ mNMService.setFirewallUidRule(FIREWALL_CHAIN_METERED_ALLOW, TEST_UID,
+ FIREWALL_RULE_DEFAULT);
+ verify(mCm).setUidFirewallRule(FIREWALL_CHAIN_METERED_ALLOW, TEST_UID,
+ FIREWALL_RULE_DEFAULT);
+ mNMService.setDataSaverModeEnabled(false);
+ verify(mCm).setDataSaverEnabled(false);
+
+ assertFalse("Network should not be restricted when data saver is off",
+ mNMService.isNetworkRestricted(TEST_UID));
+ }
+
+ @Test
public void testFirewallChains() {
final ArrayMap<Integer, ArrayMap<Integer, Boolean>> expected = new ArrayMap<>();
// Dozable chain