Merge "ITS: doBasicRecording command impl." into tm-dev
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
index 06f8288..bab2bd2 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
@@ -16,6 +16,8 @@
 
 package android.accessibilityservice.cts;
 
+import static android.accessibility.cts.common.ShellCommandBuilder.execShellCommand;
+import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.AM_BROADCAST_CLOSE_SYSTEM_DIALOG_COMMAND;
 import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.homeScreenOrBust;
 
 import static org.junit.Assert.assertTrue;
@@ -172,6 +174,7 @@
         // Ideally should verify that we actually have a screenshot, but it's also possible
         // for the screenshot to fail
         waitForIdle();
+        execShellCommand(sUiAutomation, AM_BROADCAST_CLOSE_SYSTEM_DIALOG_COMMAND);
     }
 
     @MediumTest
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java
index 7e9904c..4ecc13f 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java
@@ -63,7 +63,7 @@
     private static final String LOG_TAG = "ActivityLaunchUtils";
     private static final String AM_START_HOME_ACTIVITY_COMMAND =
             "am start -a android.intent.action.MAIN -c android.intent.category.HOME";
-    private static final String AM_BROADCAST_CLOSE_SYSTEM_DIALOG_COMMAND =
+    public static final String AM_BROADCAST_CLOSE_SYSTEM_DIALOG_COMMAND =
             "am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS";
 
     // Using a static variable so it can be used in lambdas. Not preserving state in it.
@@ -190,8 +190,7 @@
                 if (packageName != null) {
                     for (ResolveInfo resolveInfo : resolveInfos) {
                         if ((resolveInfo.activityInfo != null)
-                                && packageName.equals(resolveInfo.activityInfo.packageName)
-                                && window.isActive()) {
+                                && packageName.equals(resolveInfo.activityInfo.packageName)) {
                             return true;
                         }
                     }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
index 39dcbd5..b2790bb 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
@@ -366,6 +366,7 @@
     @Test
     public void testTranslucentAppOrientationRequests() {
         assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest());
+        disableIgnoreOrientationRequest();
 
         separateTestJournal();
         launchActivity(PORTRAIT_ORIENTATION_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
@@ -537,6 +538,7 @@
         assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest());
         // TODO(b/209920544) remove assumeFalse after issue fix.
         assumeFalse(ENABLE_SHELL_TRANSITIONS);
+        disableIgnoreOrientationRequest();
 
         final RotationSession rotationSession = createManagedRotationSession();
         rotationSession.set(ROTATION_0);
@@ -555,6 +557,7 @@
     @Test
     public void testTaskCloseRestoreFixedOrientation() {
         assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest());
+        disableIgnoreOrientationRequest();
 
         // Start landscape activity.
         launchActivity(LANDSCAPE_ORIENTATION_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
@@ -760,6 +763,7 @@
         // TODO(b/110533226): Fix test on devices with display cutout
         assumeFalse("Skipping test: display cutout present, can't predict exact lifecycle",
                 hasDisplayCutout());
+        disableIgnoreOrientationRequest();
 
         // Start portrait-fixed activity
         separateTestJournal();
@@ -803,6 +807,7 @@
     @Test
     public void testTaskMoveToBackOrientation() {
         assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest());
+        disableIgnoreOrientationRequest();
 
         // Start landscape activity.
         launchActivity(LANDSCAPE_ORIENTATION_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java
index 35beba0..7762a00 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java
@@ -110,6 +110,8 @@
 public class SplashscreenTests extends ActivityManagerTestBase {
 
     private static final int CENTER_ICON_SIZE = 192;
+    private static final int BRANDING_HEIGHT = 80;
+    private static final int BRANDING_DEFAULT_MARGIN = 60;
 
     @Rule
     public final DumpOnFailure dumpOnFailure = new DumpOnFailure();
@@ -357,6 +359,19 @@
         result.setPixel(x + debugOffsetX, y, debugPixel);
     }
 
+    // Roughly check whether the height of the window is high enough to display the brand image.
+    private boolean canShowBranding() {
+        final int iconHeight = WindowManagerState.dpToPx(CENTER_ICON_SIZE,
+                mContext.getResources().getConfiguration().densityDpi);
+        final int brandingHeight = WindowManagerState.dpToPx(BRANDING_HEIGHT,
+                mContext.getResources().getConfiguration().densityDpi);
+        final int brandingDefaultMargin = WindowManagerState.dpToPx(BRANDING_DEFAULT_MARGIN,
+                mContext.getResources().getConfiguration().densityDpi);
+        final WindowMetrics windowMetrics = mWm.getMaximumWindowMetrics();
+        final Rect drawableBounds = new Rect(windowMetrics.getBounds());
+        final int leftHeight = (drawableBounds.height() - iconHeight) / 2;
+        return leftHeight > brandingHeight + brandingDefaultMargin;
+    }
     @Test
     public void testHandleExitAnimationOnCreate() throws Exception {
         assumeFalse(isLeanBack());
@@ -624,8 +639,9 @@
         assertEquals(iconAnimatable, journal.extras.getBoolean(CENTER_VIEW_IS_SURFACE_VIEW));
         assertEquals(iconAnimatable, (iconAnimationStart != 0));
         assertEquals(iconAnimatable ? 500 : 0, iconAnimationDuration);
-        assertEquals(containsBranding, journal.extras.getBoolean(CONTAINS_BRANDING_VIEW));
-
+        if (containsBranding && canShowBranding()) {
+            assertEquals(containsBranding, journal.extras.getBoolean(CONTAINS_BRANDING_VIEW));
+        }
         if (containsIcon && !iconAnimatable) {
             assertEquals(Color.BLUE, journal.extras.getInt(ICON_BACKGROUND_COLOR, Color.YELLOW));
         } else {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
index 0953fc5..aa19b08 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
@@ -28,6 +28,8 @@
 import static android.view.WindowInsets.Type.statusBars;
 import static android.view.WindowInsets.Type.systemBars;
 import static android.view.WindowInsets.Type.systemGestures;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
 import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -66,6 +68,7 @@
 import android.view.Window;
 import android.view.WindowInsets;
 import android.view.WindowInsetsAnimation;
+import android.view.WindowInsetsController;
 import android.view.WindowManager;
 import android.widget.EditText;
 import android.widget.LinearLayout;
@@ -244,6 +247,42 @@
     }
 
     @Test
+    public void testSetSystemBarsAppearance() {
+        final TestActivity activity = startActivity(TestActivity.class);
+        final View rootView = activity.getWindow().getDecorView();
+        final WindowInsetsController controller = rootView.getWindowInsetsController();
+        getInstrumentation().runOnMainSync(() -> {
+            // Set APPEARANCE_LIGHT_STATUS_BARS.
+            controller.setSystemBarsAppearance(
+                    APPEARANCE_LIGHT_STATUS_BARS, APPEARANCE_LIGHT_STATUS_BARS);
+
+            // Clear APPEARANCE_LIGHT_NAVIGATION_BARS.
+            controller.setSystemBarsAppearance(
+                    0 /* appearance */, APPEARANCE_LIGHT_NAVIGATION_BARS);
+        });
+        waitForIdle();
+
+        // We must have APPEARANCE_LIGHT_STATUS_BARS, but not APPEARANCE_LIGHT_NAVIGATION_BARS.
+        assertEquals(APPEARANCE_LIGHT_STATUS_BARS,
+                controller.getSystemBarsAppearance()
+                        & (APPEARANCE_LIGHT_STATUS_BARS | APPEARANCE_LIGHT_NAVIGATION_BARS));
+
+        final boolean[] onPreDrawCalled = { false };
+        rootView.getViewTreeObserver().addOnPreDrawListener(() -> {
+            onPreDrawCalled[0] = true;
+            return true;
+        });
+
+        // Clear APPEARANCE_LIGHT_NAVIGATION_BARS again.
+        getInstrumentation().runOnMainSync(() -> controller.setSystemBarsAppearance(
+                0 /* appearance */, APPEARANCE_LIGHT_NAVIGATION_BARS));
+        waitForIdle();
+
+        assertFalse("Setting the same appearance must not cause a new traversal",
+                onPreDrawCalled[0]);
+    }
+
+    @Test
     public void testSetSystemBarsBehavior_default() throws InterruptedException {
         final TestActivity activity = startActivityInWindowingModeFullScreen(TestActivity.class);
         final View rootView = activity.getWindow().getDecorView();
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index 8bf60f4..5611dc1 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -1357,6 +1357,11 @@
         return mObjectTracker.manage(new FontScaleSession());
     }
 
+    /** Allows requesting orientation in case ignore_orientation_request is set to true. */
+    protected void disableIgnoreOrientationRequest() {
+        mObjectTracker.manage(new IgnoreOrientationRequestSession(DEFAULT_DISPLAY, false));
+    }
+
     /**
      * Test @Rule class that disables screen doze settings before each test method running and
      * restoring to initial values after test method finished.
diff --git a/tests/tests/bluetooth/TEST_MAPPING b/tests/tests/bluetooth/TEST_MAPPING
index f349b92..0df5768 100644
--- a/tests/tests/bluetooth/TEST_MAPPING
+++ b/tests/tests/bluetooth/TEST_MAPPING
@@ -3,5 +3,10 @@
     {
       "name": "CtsBluetoothTestCases"
     }
+  ],
+  "hwasan-postsubmit": [
+    {
+      "name": "CtsBluetoothTestCases"
+    }
   ]
 }
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualDeviceTestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualDeviceTestCase.java
index 717c5e2..b8d3f6f 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualDeviceTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualDeviceTestCase.java
@@ -16,7 +16,10 @@
 
 package android.hardware.input.cts.tests;
 
+import static android.content.pm.PackageManager.FEATURE_COMPANION_DEVICE_SETUP;
+
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 
 import android.app.ActivityOptions;
 import android.companion.AssociationInfo;
@@ -24,6 +27,7 @@
 import android.companion.virtual.VirtualDeviceManager;
 import android.companion.virtual.VirtualDeviceParams;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.graphics.Point;
 import android.graphics.SurfaceTexture;
 import android.hardware.display.VirtualDisplay;
@@ -89,6 +93,10 @@
     @Override
     void onBeforeLaunchActivity() {
         final Context context = InstrumentationRegistry.getTargetContext();
+        final PackageManager packageManager = context.getPackageManager();
+        // TVs do not support companion
+        assumeTrue(packageManager.hasSystemFeature(PackageManager.FEATURE_COMPANION_DEVICE_SETUP));
+
         final String packageName = context.getPackageName();
         associateCompanionDevice(packageName);
         AssociationInfo associationInfo = null;
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualKeyboardTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualKeyboardTest.java
index 1b0a42f..741116b 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualKeyboardTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualKeyboardTest.java
@@ -44,7 +44,9 @@
 
     @Override
     void onTearDownVirtualInputDevice() {
-        mVirtualKeyboard.close();
+        if (mVirtualKeyboard != null) {
+            mVirtualKeyboard.close();
+        }
     }
 
     @Test
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualMouseTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualMouseTest.java
index b96858f..7cf713f 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualMouseTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualMouseTest.java
@@ -54,7 +54,9 @@
 
     @Override
     void onTearDownVirtualInputDevice() {
-        mVirtualMouse.close();
+        if (mVirtualMouse != null) {
+            mVirtualMouse.close();
+        }
     }
 
     @Test
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualTouchscreenTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualTouchscreenTest.java
index a14228e..7bd7b46 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualTouchscreenTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualTouchscreenTest.java
@@ -45,7 +45,9 @@
 
     @Override
     void onTearDownVirtualInputDevice() {
-        mVirtualTouchscreen.close();
+        if (mVirtualTouchscreen != null) {
+            mVirtualTouchscreen.close();
+        }
     }
 
     @Test
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/VideoDecoderPerfTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/VideoDecoderPerfTest.java
index 3464193..8eb38e7 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/VideoDecoderPerfTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/VideoDecoderPerfTest.java
@@ -189,9 +189,9 @@
         // Ensure we can finish this test within the test timeout. Allow 25% slack (4/5).
         long maxTimeMs = Math.min(
                 MAX_TEST_TIMEOUT_MS * 4 / 5 / NUMBER_OF_REPEATS, MAX_TIME_MS);
-        // reduce test run on non-real device
+        // reduce test run on non-real device to maximum of 2 seconds
         if (MediaUtils.onFrankenDevice()) {
-            maxTimeMs /= 10;
+            maxTimeMs = Math.min(2000, maxTimeMs);
         }
         double measuredFps[] = new double[NUMBER_OF_REPEATS];
 
diff --git a/tests/tests/os/src/android/os/cts/LowPowerStandbyTest.java b/tests/tests/os/src/android/os/cts/LowPowerStandbyTest.java
index 8f7c410..61e3cab 100644
--- a/tests/tests/os/src/android/os/cts/LowPowerStandbyTest.java
+++ b/tests/tests/os/src/android/os/cts/LowPowerStandbyTest.java
@@ -19,6 +19,7 @@
 import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
 import static android.os.PowerManager.SYSTEM_WAKELOCK;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -28,6 +29,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.Network;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
 import android.platform.test.annotations.AppModeFull;
@@ -71,12 +74,15 @@
 
     private Context mContext;
     private PowerManager mPowerManager;
+    private ConnectivityManager mConnectivityManager;
     private boolean mOriginalEnabled;
+    private WakeLock mSystemWakeLock;
 
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getInstrumentation().getContext();
         mPowerManager = mContext.getSystemService(PowerManager.class);
+        mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
         mOriginalEnabled = mPowerManager.isLowPowerStandbyEnabled();
     }
 
@@ -90,6 +96,10 @@
             }, Manifest.permission.MANAGE_LOW_POWER_STANDBY);
         }
         unforceDoze();
+
+        if (mSystemWakeLock != null) {
+            mSystemWakeLock.release();
+        }
     }
 
     @Test
@@ -152,15 +162,10 @@
             Manifest.permission.DEVICE_POWER})
     public void testLowPowerStandby_wakelockIsDisabled() throws Exception {
         assumeTrue(mPowerManager.isLowPowerStandbySupported());
-
-        // Keep system awake with system wakelock
-        WakeLock systemWakeLock = mPowerManager.newWakeLock(PARTIAL_WAKE_LOCK | SYSTEM_WAKELOCK,
-                SYSTEM_WAKE_LOCK_TAG);
-        systemWakeLock.acquire();
+        keepSystemAwake();
 
         // Acquire test wakelock, which should be disabled by LPS
-        WakeLock testWakeLock = mPowerManager.newWakeLock(PARTIAL_WAKE_LOCK,
-                TEST_WAKE_LOCK_TAG);
+        WakeLock testWakeLock = mPowerManager.newWakeLock(PARTIAL_WAKE_LOCK, TEST_WAKE_LOCK_TAG);
         testWakeLock.acquire();
 
         mPowerManager.setLowPowerStandbyEnabled(true);
@@ -216,7 +221,38 @@
                 500, () -> isWakeLockDisabled(TEST_WAKE_LOCK_TAG));
     }
 
+    @Test
+    @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
+    @EnsureHasPermission({Manifest.permission.MANAGE_LOW_POWER_STANDBY,
+            Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.DEVICE_POWER})
+    public void testLowPowerStandby_networkIsBlocked() throws Exception {
+        assumeTrue(mPowerManager.isLowPowerStandbySupported());
+        keepSystemAwake();
+
+        NetworkBlockedStateAsserter asserter = new NetworkBlockedStateAsserter(mContext);
+        asserter.register();
+
+        try {
+            mPowerManager.setLowPowerStandbyEnabled(true);
+            goToSleep();
+            mPowerManager.forceLowPowerStandbyActive(true);
+
+            asserter.assertNetworkBlocked("Network is not blocked", true);
+
+            wakeUp();
+            mPowerManager.forceLowPowerStandbyActive(false);
+
+            asserter.assertNetworkBlocked("Network is blocked after waking up", false);
+        } finally {
+            asserter.unregister();
+        }
+    }
+
     private void goToSleep() throws Exception {
+        if (!mPowerManager.isInteractive()) {
+            return;
+        }
+
         final BlockingBroadcastReceiver screenOffReceiver = new BlockingBroadcastReceiver(mContext,
                 Intent.ACTION_SCREEN_OFF);
         screenOffReceiver.register();
@@ -228,6 +264,10 @@
     }
 
     private void wakeUp() throws Exception {
+        if (mPowerManager.isInteractive()) {
+            return;
+        }
+
         final BlockingBroadcastReceiver screenOnReceiver = new BlockingBroadcastReceiver(mContext,
                 Intent.ACTION_SCREEN_ON);
         screenOnReceiver.register();
@@ -274,8 +314,56 @@
                 PowerManagerServiceDumpProto.class, "dumpsys power --proto");
     }
 
+    private void keepSystemAwake() {
+        mSystemWakeLock = mPowerManager.newWakeLock(PARTIAL_WAKE_LOCK | SYSTEM_WAKELOCK,
+                SYSTEM_WAKE_LOCK_TAG);
+        mSystemWakeLock.acquire();
+    }
+
     private String executeShellCommand(String command) throws IOException {
         UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
         return uiDevice.executeShellCommand(command);
     }
+
+    private static class NetworkBlockedStateAsserter {
+        private final ConnectivityManager mConnectivityManager;
+        private final ConnectivityManager.NetworkCallback mNetworkCallback;
+
+        private final Object mLock = new Object();
+        private boolean mIsBlocked = false;
+
+        NetworkBlockedStateAsserter(Context context) {
+            mConnectivityManager = context.getSystemService(ConnectivityManager.class);
+            mNetworkCallback =
+                    new ConnectivityManager.NetworkCallback() {
+                        @Override
+                        public void onBlockedStatusChanged(Network network, boolean blocked) {
+                            synchronized (mLock) {
+                                if (mIsBlocked != blocked) {
+                                    mIsBlocked = blocked;
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    };
+        }
+
+        private void register() {
+            mConnectivityManager.registerDefaultNetworkCallback(mNetworkCallback);
+        }
+
+        private void assertNetworkBlocked(String message, boolean expected) throws Exception {
+            synchronized (mLock) {
+                if (mIsBlocked == expected) {
+                    return;
+                }
+                mLock.wait(5000);
+                assertEquals(message, expected, mIsBlocked);
+            }
+        }
+
+        private void unregister() {
+            mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
+        }
+    }
 }