diff options
Diffstat (limited to 'tests')
70 files changed, 789 insertions, 437 deletions
diff --git a/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java index 3498974b348e..229c7bfb53e9 100644 --- a/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java +++ b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java @@ -103,6 +103,10 @@ public class IntegrationTests { @RequiresFlagsEnabled(Flags.FLAG_DETAILED_APP_JANK_METRICS_API) public void reportJankStats_confirmPendingStatsIncreases() { Activity jankTrackerActivity = mJankTrackerActivityRule.launchActivity(null); + mDevice.wait(Until.findObject( + By.text(jankTrackerActivity.getString(R.string.continue_test))), + WAIT_FOR_TIMEOUT_MS); + EditText editText = jankTrackerActivity.findViewById(R.id.edit_text); JankTracker jankTracker = editText.getJankTracker(); @@ -135,6 +139,10 @@ public class IntegrationTests { public void simulateWidgetStateChanges_confirmStateChangesAreTracked() { JankTrackerActivity jankTrackerActivity = mJankTrackerActivityRule.launchActivity(null); + mDevice.wait(Until.findObject( + By.text(jankTrackerActivity.getString(R.string.continue_test))), + WAIT_FOR_TIMEOUT_MS); + TestWidget testWidget = jankTrackerActivity.findViewById(R.id.jank_tracker_widget); JankTracker jankTracker = testWidget.getJankTracker(); jankTracker.forceListenerRegistration(); diff --git a/tests/AppJankTest/src/android/app/jank/tests/JankTrackerTest.java b/tests/AppJankTest/src/android/app/jank/tests/JankTrackerTest.java index 1bdf019d6c42..9d87fbd67eef 100644 --- a/tests/AppJankTest/src/android/app/jank/tests/JankTrackerTest.java +++ b/tests/AppJankTest/src/android/app/jank/tests/JankTrackerTest.java @@ -18,10 +18,12 @@ package android.app.jank.tests; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import android.app.jank.Flags; import android.app.jank.JankTracker; import android.app.jank.StateTracker; +import android.content.Context; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; @@ -55,10 +57,9 @@ public class JankTrackerTest { * Start an empty activity so decore view is not null when creating the JankTracker instance. */ private static ActivityScenario<EmptyActivity> sEmptyActivityRule; - private static String sActivityName; - private static View sActivityDecorView; + private static Context sContext; @BeforeClass public static void classSetup() { @@ -66,6 +67,7 @@ public class JankTrackerTest { sEmptyActivityRule.onActivity(activity -> { sActivityDecorView = activity.getWindow().getDecorView(); sActivityName = activity.toString(); + sContext = activity.getApplicationContext(); }); } @@ -168,4 +170,14 @@ public class JankTrackerTest { assertNotNull(jankTracker); } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_DETAILED_APP_JANK_METRICS_API) + public void jankTracker_IsNull_WhenViewNotInHierarchy() { + TestWidget testWidget = new TestWidget(sContext); + JankTracker jankTracker = testWidget.getJankTracker(); + + assertNull(jankTracker); + } + } diff --git a/tests/AttestationVerificationTest/src/com/android/server/security/CertificateRevocationStatusManagerTest.java b/tests/AttestationVerificationTest/src/com/android/server/security/CertificateRevocationStatusManagerTest.java index 586bb76388f6..3854ae6dc9b3 100644 --- a/tests/AttestationVerificationTest/src/com/android/server/security/CertificateRevocationStatusManagerTest.java +++ b/tests/AttestationVerificationTest/src/com/android/server/security/CertificateRevocationStatusManagerTest.java @@ -20,18 +20,17 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; import android.content.Context; -import android.os.SystemClock; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; -import org.json.JSONObject; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.security.cert.CertPathValidatorException; @@ -39,33 +38,34 @@ import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.time.LocalDateTime; +import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.List; -import java.util.Map; @RunWith(AndroidJUnit4.class) public class CertificateRevocationStatusManagerTest { private static final String TEST_CERTIFICATE_FILE_1 = "test_attestation_with_root_certs.pem"; private static final String TEST_CERTIFICATE_FILE_2 = "test_attestation_wrong_root_certs.pem"; - private static final String TEST_REVOCATION_LIST_FILE_NAME = "test_revocation_list.json"; + private static final String TEST_REMOTE_REVOCATION_LIST_FILE_NAME = + "test_remote_revocation_list.json"; private static final String REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST = "test_revocation_list_no_test_certs.json"; private static final String REVOCATION_LIST_WITH_CERTIFICATES_USED_IN_THIS_TEST = "test_revocation_list_with_test_certs.json"; - private static final String TEST_REVOCATION_STATUS_FILE_NAME = "test_revocation_status.txt"; + private static final String TEST_STORED_REVOCATION_LIST_FILE_NAME = + "test_stored_revocation_list.json"; private static final String FILE_URL_PREFIX = "file://"; private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); private CertificateFactory mFactory; private List<X509Certificate> mCertificates1; private List<X509Certificate> mCertificates2; - private File mRevocationListFile; + private File mRemoteRevocationListFile; private String mRevocationListUrl; private String mNonExistentRevocationListUrl; - private File mRevocationStatusFile; + private File mStoredRevocationListFile; private CertificateRevocationStatusManager mCertificateRevocationStatusManager; @Before @@ -73,27 +73,29 @@ public class CertificateRevocationStatusManagerTest { mFactory = CertificateFactory.getInstance("X.509"); mCertificates1 = getCertificateChain(TEST_CERTIFICATE_FILE_1); mCertificates2 = getCertificateChain(TEST_CERTIFICATE_FILE_2); - mRevocationListFile = new File(mContext.getFilesDir(), TEST_REVOCATION_LIST_FILE_NAME); - mRevocationListUrl = FILE_URL_PREFIX + mRevocationListFile.getAbsolutePath(); + mRemoteRevocationListFile = + new File(mContext.getFilesDir(), TEST_REMOTE_REVOCATION_LIST_FILE_NAME); + mRevocationListUrl = FILE_URL_PREFIX + mRemoteRevocationListFile.getAbsolutePath(); File noSuchFile = new File(mContext.getFilesDir(), "file_does_not_exist"); mNonExistentRevocationListUrl = FILE_URL_PREFIX + noSuchFile.getAbsolutePath(); - mRevocationStatusFile = new File(mContext.getFilesDir(), TEST_REVOCATION_STATUS_FILE_NAME); + mStoredRevocationListFile = + new File(mContext.getFilesDir(), TEST_STORED_REVOCATION_LIST_FILE_NAME); } @After public void tearDown() throws Exception { - mRevocationListFile.delete(); - mRevocationStatusFile.delete(); + mRemoteRevocationListFile.delete(); + mStoredRevocationListFile.delete(); } @Test public void checkRevocationStatus_doesNotExistOnRemoteRevocationList_noException() throws Exception { copyFromAssetToFile( - REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRevocationListFile); + REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRemoteRevocationListFile); mCertificateRevocationStatusManager = new CertificateRevocationStatusManager( - mContext, mRevocationListUrl, mRevocationStatusFile, false); + mContext, mRevocationListUrl, mStoredRevocationListFile, false); mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1); } @@ -102,10 +104,10 @@ public class CertificateRevocationStatusManagerTest { public void checkRevocationStatus_existsOnRemoteRevocationList_throwsException() throws Exception { copyFromAssetToFile( - REVOCATION_LIST_WITH_CERTIFICATES_USED_IN_THIS_TEST, mRevocationListFile); + REVOCATION_LIST_WITH_CERTIFICATES_USED_IN_THIS_TEST, mRemoteRevocationListFile); mCertificateRevocationStatusManager = new CertificateRevocationStatusManager( - mContext, mRevocationListUrl, mRevocationStatusFile, false); + mContext, mRevocationListUrl, mStoredRevocationListFile, false); assertThrows( CertPathValidatorException.class, @@ -118,7 +120,7 @@ public class CertificateRevocationStatusManagerTest { throws Exception { mCertificateRevocationStatusManager = new CertificateRevocationStatusManager( - mContext, mNonExistentRevocationListUrl, mRevocationStatusFile, false); + mContext, mNonExistentRevocationListUrl, mStoredRevocationListFile, false); assertThrows( CertPathValidatorException.class, @@ -128,49 +130,56 @@ public class CertificateRevocationStatusManagerTest { @Test public void checkRevocationStatus_savesRevocationStatus() throws Exception { copyFromAssetToFile( - REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRevocationListFile); + REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRemoteRevocationListFile); mCertificateRevocationStatusManager = new CertificateRevocationStatusManager( - mContext, mRevocationListUrl, mRevocationStatusFile, false); + mContext, mRevocationListUrl, mStoredRevocationListFile, false); mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1); - assertThat(mRevocationStatusFile.length()).isGreaterThan(0); + assertThat(mStoredRevocationListFile.length()).isGreaterThan(0); } @Test - public void checkRevocationStatus_cannotReachRemoteList_certsSaved_noException() + public void checkRevocationStatus_cannotReachRemoteList_listSaved_noException() throws Exception { // call checkRevocationStatus once to save the revocation status copyFromAssetToFile( - REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRevocationListFile); + REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRemoteRevocationListFile); mCertificateRevocationStatusManager = new CertificateRevocationStatusManager( - mContext, mRevocationListUrl, mRevocationStatusFile, false); + mContext, mRevocationListUrl, mStoredRevocationListFile, false); mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1); // call checkRevocationStatus again with mNonExistentRevocationListUrl mCertificateRevocationStatusManager = new CertificateRevocationStatusManager( - mContext, mNonExistentRevocationListUrl, mRevocationStatusFile, false); + mContext, mNonExistentRevocationListUrl, mStoredRevocationListFile, false); mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1); } @Test - public void checkRevocationStatus_cannotReachRemoteList_someCertsNotSaved_exception() + public void checkRevocationStatus_cannotReachRemoteList_storedListTooOld_exception() throws Exception { - // call checkRevocationStatus once to save the revocation status for mCertificates2 + // call checkRevocationStatus once to save the revocation status copyFromAssetToFile( - REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRevocationListFile); + REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRemoteRevocationListFile); mCertificateRevocationStatusManager = new CertificateRevocationStatusManager( - mContext, mRevocationListUrl, mRevocationStatusFile, false); - mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates2); - // call checkRevocationStatus again with mNonExistentRevocationListUrl, this time for - // mCertificates1 + mContext, mRevocationListUrl, mStoredRevocationListFile, false); + mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1); + // set the last modified date of the stored list to an expired date + LocalDateTime now = LocalDateTime.now(); + LocalDateTime expiredListDate = + now.minusDays( + CertificateRevocationStatusManager.MAX_OFFLINE_REVOCATION_LIST_AGE_DAYS + + 1); + mStoredRevocationListFile.setLastModified( + expiredListDate.toEpochSecond(OffsetDateTime.now().getOffset()) * 1000); + // call checkRevocationStatus again with mNonExistentRevocationListUrl mCertificateRevocationStatusManager = new CertificateRevocationStatusManager( - mContext, mNonExistentRevocationListUrl, mRevocationStatusFile, false); + mContext, mNonExistentRevocationListUrl, mStoredRevocationListFile, false); assertThrows( CertPathValidatorException.class, @@ -178,143 +187,112 @@ public class CertificateRevocationStatusManagerTest { } @Test - public void checkRevocationStatus_cannotReachRemoteList_someCertsStatusTooOld_exception() + public void checkRevocationStatus_cannotReachRemoteList_storedListIsFresh_noException() throws Exception { + // call checkRevocationStatus once to save the revocation status + copyFromAssetToFile( + REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRemoteRevocationListFile); mCertificateRevocationStatusManager = new CertificateRevocationStatusManager( - mContext, mNonExistentRevocationListUrl, mRevocationStatusFile, false); + mContext, mRevocationListUrl, mStoredRevocationListFile, false); + mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1); + // set the last modified date of the stored list to a barely not expired date LocalDateTime now = LocalDateTime.now(); - LocalDateTime expiredStatusDate = - now.minusDays(CertificateRevocationStatusManager.MAX_DAYS_SINCE_LAST_CHECK + 1); - Map<String, LocalDateTime> lastRevocationCheckData = new HashMap<>(); - lastRevocationCheckData.put(getSerialNumber(mCertificates1.get(0)), expiredStatusDate); - for (int i = 1; i < mCertificates1.size(); i++) { - lastRevocationCheckData.put(getSerialNumber(mCertificates1.get(i)), now); - } - mCertificateRevocationStatusManager.storeLastRevocationCheckData(lastRevocationCheckData); - - assertThrows( - CertPathValidatorException.class, - () -> mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1)); - } - - @Test - public void checkRevocationStatus_cannotReachRemoteList_allCertResultsFresh_noException() - throws Exception { + LocalDateTime barelyFreshDate = + now.minusDays( + CertificateRevocationStatusManager.MAX_OFFLINE_REVOCATION_LIST_AGE_DAYS + - 1); + mStoredRevocationListFile.setLastModified( + barelyFreshDate.toEpochSecond(OffsetDateTime.now().getOffset()) * 1000); + // call checkRevocationStatus again with mNonExistentRevocationListUrl mCertificateRevocationStatusManager = new CertificateRevocationStatusManager( - mContext, mNonExistentRevocationListUrl, mRevocationStatusFile, false); - LocalDateTime bearlyNotExpiredStatusDate = - LocalDateTime.now() - .minusDays( - CertificateRevocationStatusManager.MAX_DAYS_SINCE_LAST_CHECK - 1); - Map<String, LocalDateTime> lastRevocationCheckData = new HashMap<>(); - for (X509Certificate certificate : mCertificates1) { - lastRevocationCheckData.put(getSerialNumber(certificate), bearlyNotExpiredStatusDate); - } - mCertificateRevocationStatusManager.storeLastRevocationCheckData(lastRevocationCheckData); + mContext, mNonExistentRevocationListUrl, mStoredRevocationListFile, false); mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1); } @Test - public void updateLastRevocationCheckData_correctlySavesStatus() throws Exception { + public void silentlyStoreRevocationList_storesCorrectly() throws Exception { + copyFromAssetToFile( + REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRemoteRevocationListFile); mCertificateRevocationStatusManager = new CertificateRevocationStatusManager( - mContext, mNonExistentRevocationListUrl, mRevocationStatusFile, false); - Map<String, Boolean> areCertificatesRevoked = new HashMap<>(); - for (X509Certificate certificate : mCertificates1) { - areCertificatesRevoked.put(getSerialNumber(certificate), false); - } + mContext, mRevocationListUrl, mStoredRevocationListFile, false); + byte[] revocationList = + mCertificateRevocationStatusManager.fetchRemoteRevocationListBytes(); - mCertificateRevocationStatusManager.updateLastRevocationCheckData(areCertificatesRevoked); + mCertificateRevocationStatusManager.silentlyStoreRevocationList(revocationList); - // no exception - mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1); - // revoke one certificate and try again - areCertificatesRevoked.put(getSerialNumber(mCertificates1.getLast()), true); - mCertificateRevocationStatusManager.updateLastRevocationCheckData(areCertificatesRevoked); - assertThrows( - CertPathValidatorException.class, - () -> mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1)); + byte[] bytesFromRemoteList; + byte[] bytesFromStoredList; + try (FileInputStream remoteListInputStream = + new FileInputStream(mRemoteRevocationListFile)) { + bytesFromRemoteList = remoteListInputStream.readAllBytes(); + } + try (FileInputStream storedListInputStream = + new FileInputStream(mStoredRevocationListFile)) { + bytesFromStoredList = storedListInputStream.readAllBytes(); + } + assertThat(bytesFromStoredList).isEqualTo(bytesFromRemoteList); } @Test - public void updateLastRevocationCheckDataForAllPreviouslySeenCertificates_updatesCorrectly() + public void checkRevocationStatus_recentlyChecked_doesNotFetchRemoteCrl() throws Exception { copyFromAssetToFile( - REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRevocationListFile); + REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRemoteRevocationListFile); mCertificateRevocationStatusManager = new CertificateRevocationStatusManager( - mContext, mRevocationListUrl, mRevocationStatusFile, false); - // populate the revocation status file + mContext, mRevocationListUrl, mStoredRevocationListFile, false); + mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1); + // indirectly verifies the remote list is not fetched by simulating a remote revocation + copyFromAssetToFile( + REVOCATION_LIST_WITH_CERTIFICATES_USED_IN_THIS_TEST, mRemoteRevocationListFile); + + // no exception mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1); - // Sleep for 2 second so that the current time changes - SystemClock.sleep(2000); - LocalDateTime timestampBeforeUpdate = LocalDateTime.now(); - JSONObject revocationList = mCertificateRevocationStatusManager.fetchRemoteRevocationList(); - List<String> otherCertificatesToCheck = new ArrayList<>(); - String serialNumber1 = "1234567"; // not revoked - String serialNumber2 = "8350192447815228107"; // revoked - String serialNumber3 = "987654"; // not revoked - otherCertificatesToCheck.add(serialNumber1); - otherCertificatesToCheck.add(serialNumber2); - otherCertificatesToCheck.add(serialNumber3); - - mCertificateRevocationStatusManager - .updateLastRevocationCheckDataForAllPreviouslySeenCertificates( - revocationList, otherCertificatesToCheck); - - Map<String, LocalDateTime> lastRevocationCheckData = - mCertificateRevocationStatusManager.getLastRevocationCheckData(); - assertThat(lastRevocationCheckData.get(serialNumber1)).isAtLeast(timestampBeforeUpdate); - assertThat(lastRevocationCheckData).doesNotContainKey(serialNumber2); // revoked - assertThat(lastRevocationCheckData.get(serialNumber3)).isAtLeast(timestampBeforeUpdate); - // validate that the existing certificates on the file got updated too - for (X509Certificate certificate : mCertificates1) { - assertThat(lastRevocationCheckData.get(getSerialNumber(certificate))) - .isAtLeast(timestampBeforeUpdate); - } } @Test - public void checkRevocationStatus_allCertificatesRecentlyChecked_doesNotFetchRemoteCrl() + public void checkRevocationStatus_recentlyCheckedAndRevoked_exception() throws Exception { copyFromAssetToFile( - REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRevocationListFile); + REVOCATION_LIST_WITH_CERTIFICATES_USED_IN_THIS_TEST, mRemoteRevocationListFile); mCertificateRevocationStatusManager = new CertificateRevocationStatusManager( - mContext, mRevocationListUrl, mRevocationStatusFile, false); - mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1); - // indirectly verifies the remote list is not fetched by simulating a remote revocation - copyFromAssetToFile( - REVOCATION_LIST_WITH_CERTIFICATES_USED_IN_THIS_TEST, mRevocationListFile); + mContext, mRevocationListUrl, mStoredRevocationListFile, false); + assertThrows( + CertPathValidatorException.class, + () -> mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1)); - // no exception - mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1); + assertThrows( + CertPathValidatorException.class, + () -> mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1)); } @Test - public void checkRevocationStatus_allCertificatesBarelyRecentlyChecked_doesNotFetchRemoteCrl() + public void checkRevocationStatus_barelyRecentlyChecked_doesNotFetchRemoteCrl() throws Exception { copyFromAssetToFile( - REVOCATION_LIST_WITH_CERTIFICATES_USED_IN_THIS_TEST, mRevocationListFile); + REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRemoteRevocationListFile); mCertificateRevocationStatusManager = new CertificateRevocationStatusManager( - mContext, mRevocationListUrl, mRevocationStatusFile, false); - Map<String, LocalDateTime> lastCheckedDates = new HashMap<>(); - LocalDateTime barelyRecently = - LocalDateTime.now() - .minusHours( - CertificateRevocationStatusManager.NUM_HOURS_BEFORE_NEXT_CHECK - 1); - for (X509Certificate certificate : mCertificates1) { - lastCheckedDates.put(getSerialNumber(certificate), barelyRecently); - } - mCertificateRevocationStatusManager.storeLastRevocationCheckData(lastCheckedDates); + mContext, mRevocationListUrl, mStoredRevocationListFile, false); + mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1); + // set the last modified date of the stored list to a barely recent date + LocalDateTime now = LocalDateTime.now(); + LocalDateTime barelyRecentDate = + now.minusHours(CertificateRevocationStatusManager.NUM_HOURS_BEFORE_NEXT_FETCH - 1); + mStoredRevocationListFile.setLastModified( + barelyRecentDate.toEpochSecond(OffsetDateTime.now().getOffset()) * 1000); + // indirectly verifies the remote list is not fetched by simulating a remote revocation + copyFromAssetToFile( + REVOCATION_LIST_WITH_CERTIFICATES_USED_IN_THIS_TEST, mRemoteRevocationListFile); // Indirectly verify the remote CRL is not checked by checking there is no exception despite - // a certificate being revoked. This test differs from the next only in the lastCheckedDate, - // one before the NUM_HOURS_BEFORE_NEXT_CHECK cutoff and one after + // a certificate being revoked. This test differs from the next only in the stored list last + // modified date, one before the NUM_HOURS_BEFORE_NEXT_FETCH cutoff and one after mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1); } @@ -322,21 +300,20 @@ public class CertificateRevocationStatusManagerTest { public void checkRevocationStatus_certificatesRevokedAfterCheck_throwsException() throws Exception { copyFromAssetToFile( - REVOCATION_LIST_WITH_CERTIFICATES_USED_IN_THIS_TEST, mRevocationListFile); + REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRemoteRevocationListFile); mCertificateRevocationStatusManager = new CertificateRevocationStatusManager( - mContext, mRevocationListUrl, mRevocationStatusFile, false); - Map<String, LocalDateTime> lastCheckedDates = new HashMap<>(); - // To save network use, we do not check the remote CRL if all the certificates are recently - // checked, so we set the lastCheckDate to some time not recent. - LocalDateTime notRecently = - LocalDateTime.now() - .minusHours( - CertificateRevocationStatusManager.NUM_HOURS_BEFORE_NEXT_CHECK + 1); - for (X509Certificate certificate : mCertificates1) { - lastCheckedDates.put(getSerialNumber(certificate), notRecently); - } - mCertificateRevocationStatusManager.storeLastRevocationCheckData(lastCheckedDates); + mContext, mRevocationListUrl, mStoredRevocationListFile, false); + mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1); + // set the last modified date of the stored list to a barely not recent date + LocalDateTime now = LocalDateTime.now(); + LocalDateTime barelyNotRecentDate = + now.minusHours(CertificateRevocationStatusManager.NUM_HOURS_BEFORE_NEXT_FETCH + 1); + mStoredRevocationListFile.setLastModified( + barelyNotRecentDate.toEpochSecond(OffsetDateTime.now().getOffset()) * 1000); + // simulate a remote revocation + copyFromAssetToFile( + REVOCATION_LIST_WITH_CERTIFICATES_USED_IN_THIS_TEST, mRemoteRevocationListFile); assertThrows( CertPathValidatorException.class, @@ -362,8 +339,4 @@ public class CertificateRevocationStatusManagerTest { fileOutputStream.write(data); } } - - private String getSerialNumber(X509Certificate certificate) { - return certificate.getSerialNumber().toString(16); - } } diff --git a/tests/Codegen/OWNERS b/tests/Codegen/OWNERS index da723b3b67da..e69de29bb2d1 100644 --- a/tests/Codegen/OWNERS +++ b/tests/Codegen/OWNERS @@ -1 +0,0 @@ -eugenesusla@google.com
\ No newline at end of file diff --git a/tests/EnforcePermission/OWNERS b/tests/EnforcePermission/OWNERS index 39550a394f33..160849e5616f 100644 --- a/tests/EnforcePermission/OWNERS +++ b/tests/EnforcePermission/OWNERS @@ -1,3 +1,2 @@ # Bug component: 315013 tweek@google.com -brufino@google.com diff --git a/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml b/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml index 685ae9a5fef2..c5e7188e6efe 100644 --- a/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml +++ b/tests/FlickerTests/ActivityEmbedding/AndroidTestTemplate.xml @@ -47,6 +47,8 @@ <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/> <!-- Disable AOD --> <option name="run-command" value="settings put secure doze_always_on 0"/> + <!-- Disable explore hub mode --> + <option name="run-command" value="settings put secure glanceable_hub_enabled 0"/> <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> <option name="run-command" value="settings put system show_touches 1"/> <option name="run-command" value="settings put system pointer_location 1"/> diff --git a/tests/FlickerTests/AppClose/AndroidTestTemplate.xml b/tests/FlickerTests/AppClose/AndroidTestTemplate.xml index 5f92d7fe830b..22bd458e2751 100644 --- a/tests/FlickerTests/AppClose/AndroidTestTemplate.xml +++ b/tests/FlickerTests/AppClose/AndroidTestTemplate.xml @@ -47,6 +47,8 @@ <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/> <!-- Disable AOD --> <option name="run-command" value="settings put secure doze_always_on 0"/> + <!-- Disable explore hub mode --> + <option name="run-command" value="settings put secure glanceable_hub_enabled 0"/> <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> <option name="run-command" value="settings put system show_touches 1"/> <option name="run-command" value="settings put system pointer_location 1"/> diff --git a/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml b/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml index 1b90e99a8ba2..541ce26d1435 100644 --- a/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml +++ b/tests/FlickerTests/AppLaunch/AndroidTestTemplate.xml @@ -47,6 +47,8 @@ <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/> <!-- Disable AOD --> <option name="run-command" value="settings put secure doze_always_on 0"/> + <!-- Disable explore hub mode --> + <option name="run-command" value="settings put secure glanceable_hub_enabled 0"/> <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> <option name="run-command" value="settings put system show_touches 1"/> <option name="run-command" value="settings put system pointer_location 1"/> diff --git a/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml b/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml index ffdbb02984a7..d2e02193f0fb 100644 --- a/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml +++ b/tests/FlickerTests/FlickerService/AndroidTestTemplate.xml @@ -47,6 +47,8 @@ <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/> <!-- Disable AOD --> <option name="run-command" value="settings put secure doze_always_on 0"/> + <!-- Disable explore hub mode --> + <option name="run-command" value="settings put secure glanceable_hub_enabled 0"/> <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> <option name="run-command" value="settings put system show_touches 1"/> <option name="run-command" value="settings put system pointer_location 1"/> diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/transitions/flicker/LaunchTaskPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/transitions/flicker/LaunchTaskPortrait.kt new file mode 100644 index 000000000000..c82ce8a4cb1d --- /dev/null +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/transitions/flicker/LaunchTaskPortrait.kt @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm.flicker.service.transitions.flicker + +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner +import com.android.server.wm.flicker.service.transitions.scenarios.LaunchTask +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(FlickerServiceJUnit4ClassRunner::class) +class LaunchTaskPortrait : LaunchTask(Rotation.ROTATION_0) { + @ExpectedScenarios(["TASK_TRANSITION_SCENARIO", "OPEN_NEW_TASK_APP_SCENARIO"]) + @Test + override fun openNewTask() = super.openNewTask() + + companion object { + @JvmStatic + @FlickerConfigProvider + fun flickerConfigProvider(): FlickerConfig = + FlickerConfig() + .use(FlickerServiceConfig.DEFAULT) + .use(TASK_TRANSITION_SCENARIO) + .use(OPEN_NEW_TASK_APP_SCENARIO) + } +}
\ No newline at end of file diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/transitions/scenarios/LaunchTask.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/transitions/scenarios/LaunchTask.kt new file mode 100644 index 000000000000..147477d728be --- /dev/null +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/transitions/scenarios/LaunchTask.kt @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm.flicker.service.transitions.scenarios + +import android.app.Instrumentation +import android.tools.Rotation +import android.tools.flicker.AssertionInvocationGroup +import android.tools.flicker.assertors.assertions.AppWindowCoversFullScreenAtStart +import android.tools.flicker.assertors.assertions.AppWindowOnTopAtEnd +import android.tools.flicker.assertors.assertions.AppWindowOnTopAtStart +import android.tools.flicker.assertors.assertions.BackgroundShowsInTransition +import android.tools.flicker.assertors.assertions.LayerBecomesInvisible +import android.tools.flicker.assertors.assertions.LayerBecomesVisible +import android.tools.flicker.assertors.assertions.LayerIsNeverVisible +import android.tools.flicker.assertors.assertions.AppWindowIsNeverVisible +import android.tools.flicker.config.AssertionTemplates +import android.tools.flicker.config.FlickerConfigEntry +import android.tools.flicker.config.ScenarioId +import android.tools.flicker.config.appclose.Components.CLOSING_APPS +import android.tools.flicker.config.appclose.Components.CLOSING_CHANGES +import android.tools.flicker.config.applaunch.Components.OPENING_CHANGES +import android.tools.flicker.config.common.Components.LAUNCHER +import android.tools.flicker.config.common.Components.WALLPAPER +import android.tools.flicker.extractors.TaggedCujTransitionMatcher +import android.tools.flicker.extractors.TaggedScenarioExtractorBuilder +import android.tools.flicker.rules.ChangeDisplayOrientationRule +import android.tools.traces.events.CujType +import android.tools.traces.parsers.WindowManagerStateHelper +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import com.android.launcher3.tapl.LauncherInstrumentation +import com.android.server.wm.flicker.helpers.NewTasksAppHelper +import org.junit.After +import org.junit.Before +import org.junit.Test + + +/** + * This tests performs a transition between tasks + */ +abstract class LaunchTask(val rotation: Rotation = Rotation.ROTATION_0) { + protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val wmHelper = WindowManagerStateHelper(instrumentation) + private val device = UiDevice.getInstance(instrumentation) + private val tapl = LauncherInstrumentation() + + private val launchNewTaskApp = NewTasksAppHelper(instrumentation) + + @Before + fun setup() { + tapl.setEnableRotation(true) + ChangeDisplayOrientationRule.setRotation(rotation) + tapl.setExpectedRotation(rotation.value) + launchNewTaskApp.launchViaIntent(wmHelper) + } + + @Test + open fun openNewTask() { + launchNewTaskApp.openNewTask(device, wmHelper) + } + + @After + fun tearDown() { + launchNewTaskApp.exit(wmHelper) + } + + companion object { + /** + * General task transition scenario that can be reused for any trace + */ + val TASK_TRANSITION_SCENARIO = + FlickerConfigEntry( + scenarioId = ScenarioId("TASK_TRANSITION_SCENARIO"), + extractor = TaggedScenarioExtractorBuilder() + .setTargetTag(CujType.CUJ_DEFAULT_TASK_TO_TASK_ANIMATION) + .setTransitionMatcher( + TaggedCujTransitionMatcher(associatedTransitionRequired = true) + ) + .build(), + assertions = listOf( + // Opening changes replace the closing ones + LayerBecomesInvisible(CLOSING_CHANGES), + AppWindowOnTopAtStart(CLOSING_CHANGES), + LayerBecomesVisible(OPENING_CHANGES), + AppWindowOnTopAtEnd(OPENING_CHANGES), + + // There is a background color and it's covering the transition area + BackgroundShowsInTransition(CLOSING_CHANGES) + ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }) + ) + + /** + * Scenario that is making assertions that are valid for the new task app but that do not + * apply to other task transitions in general + */ + val OPEN_NEW_TASK_APP_SCENARIO = + FlickerConfigEntry( + scenarioId = ScenarioId("OPEN_NEW_TASK_APP_SCENARIO"), + extractor = TaggedScenarioExtractorBuilder() + .setTargetTag(CujType.CUJ_DEFAULT_TASK_TO_TASK_ANIMATION) + .setTransitionMatcher( + TaggedCujTransitionMatcher(associatedTransitionRequired = true) + ) + .build(), + assertions = AssertionTemplates.COMMON_ASSERTIONS + + listOf( + // Wallpaper and launcher never visible + LayerIsNeverVisible(WALLPAPER, mustExist = true), + LayerIsNeverVisible(LAUNCHER, mustExist = true), + AppWindowIsNeverVisible(LAUNCHER, mustExist = true), + // App window covers the display at start + AppWindowCoversFullScreenAtStart(CLOSING_APPS) + ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }) + ) + } +}
\ No newline at end of file diff --git a/tests/FlickerTests/IME/AndroidTestTemplate.xml b/tests/FlickerTests/IME/AndroidTestTemplate.xml index ac704e5e7c39..e112c82f0661 100644 --- a/tests/FlickerTests/IME/AndroidTestTemplate.xml +++ b/tests/FlickerTests/IME/AndroidTestTemplate.xml @@ -49,6 +49,8 @@ <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/> <!-- Disable AOD --> <option name="run-command" value="settings put secure doze_always_on 0"/> + <!-- Disable explore hub mode --> + <option name="run-command" value="settings put secure glanceable_hub_enabled 0"/> <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> <option name="run-command" value="settings put system show_touches 1"/> <option name="run-command" value="settings put system pointer_location 1"/> diff --git a/tests/FlickerTests/Notification/AndroidTestTemplate.xml b/tests/FlickerTests/Notification/AndroidTestTemplate.xml index e2ac5a9579ae..e5700c03cf77 100644 --- a/tests/FlickerTests/Notification/AndroidTestTemplate.xml +++ b/tests/FlickerTests/Notification/AndroidTestTemplate.xml @@ -47,6 +47,8 @@ <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/> <!-- Disable AOD --> <option name="run-command" value="settings put secure doze_always_on 0"/> + <!-- Disable explore hub mode --> + <option name="run-command" value="settings put secure glanceable_hub_enabled 0"/> <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> <option name="run-command" value="settings put system show_touches 1"/> <option name="run-command" value="settings put system pointer_location 1"/> diff --git a/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml b/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml index 1a4feb6e9eca..4c41a4c01180 100644 --- a/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml +++ b/tests/FlickerTests/QuickSwitch/AndroidTestTemplate.xml @@ -47,6 +47,8 @@ <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/> <!-- Disable AOD --> <option name="run-command" value="settings put secure doze_always_on 0"/> + <!-- Disable explore hub mode --> + <option name="run-command" value="settings put secure glanceable_hub_enabled 0"/> <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> <option name="run-command" value="settings put system show_touches 1"/> <option name="run-command" value="settings put system pointer_location 1"/> diff --git a/tests/FlickerTests/Rotation/AndroidTestTemplate.xml b/tests/FlickerTests/Rotation/AndroidTestTemplate.xml index 1b2007deae27..27fc249e36b9 100644 --- a/tests/FlickerTests/Rotation/AndroidTestTemplate.xml +++ b/tests/FlickerTests/Rotation/AndroidTestTemplate.xml @@ -47,6 +47,8 @@ <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/> <!-- Disable AOD --> <option name="run-command" value="settings put secure doze_always_on 0"/> + <!-- Disable explore hub mode --> + <option name="run-command" value="settings put secure glanceable_hub_enabled 0"/> <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/> <option name="run-command" value="settings put system show_touches 1"/> <option name="run-command" value="settings put system pointer_location 1"/> diff --git a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt index d7f91e009c92..2093ccc86653 100644 --- a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt +++ b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt @@ -156,19 +156,6 @@ class SeamlessAppRotationTest(flicker: LegacyFlickerTest) : RotationTransition(f flicker.assertLayers { isVisible(testApp) } } - /** Checks that [testApp] layer covers the entire screen during the whole transition */ - @Presubmit - @Test - fun appLayerRotates() { - flicker.assertLayers { - this.invoke("entireScreenCovered") { entry -> - entry.entry.displays.map { display -> - entry.visibleRegion(testApp).coversExactly(display.layerStackSpace) - } - } - } - } - /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is full screen") @@ -225,7 +212,6 @@ class SeamlessAppRotationTest(flicker: LegacyFlickerTest) : RotationTransition(f visibleLayersShownMoreThanOneConsecutiveEntry() visibleWindowsShownMoreThanOneConsecutiveEntry() - runAndIgnoreAssumptionViolation { appLayerRotates() } runAndIgnoreAssumptionViolation { appLayerAlwaysVisible() } runAndIgnoreAssumptionViolation { navBarLayerIsVisibleAtStartAndEnd() } runAndIgnoreAssumptionViolation { navBarWindowIsAlwaysVisible() } diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt index 55d6fd9b4a73..6d8ea409f6f2 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt @@ -28,10 +28,13 @@ import android.tools.device.apphelpers.IStandardAppHelper import android.tools.helpers.SYSTEMUI_PACKAGE import android.tools.traces.parsers.WindowManagerStateHelper import android.tools.traces.wm.WindowingMode +import android.view.KeyEvent.KEYCODE_DPAD_DOWN +import android.view.KeyEvent.KEYCODE_DPAD_UP import android.view.KeyEvent.KEYCODE_EQUALS import android.view.KeyEvent.KEYCODE_LEFT_BRACKET import android.view.KeyEvent.KEYCODE_MINUS import android.view.KeyEvent.KEYCODE_RIGHT_BRACKET +import android.view.KeyEvent.META_CTRL_ON import android.view.KeyEvent.META_META_ON import android.view.WindowInsets import android.view.WindowManager @@ -151,19 +154,42 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : ?: error("Unable to find resource $MAXIMIZE_BUTTON_VIEW\n") } - /** Click maximise button on the app header for the given app. */ + /** Maximize a given app to fill the stable bounds. */ fun maximiseDesktopApp( wmHelper: WindowManagerStateHelper, device: UiDevice, - usingKeyboard: Boolean = false + trigger: MaximizeDesktopAppTrigger = MaximizeDesktopAppTrigger.MAXIMIZE_MENU, ) { - if (usingKeyboard) { - val keyEventHelper = KeyEventHelper(getInstrumentation()) - keyEventHelper.press(KEYCODE_EQUALS, META_META_ON) - } else { - val caption = getCaptionForTheApp(wmHelper, device) - val maximizeButton = getMaximizeButtonForTheApp(caption) - maximizeButton.click() + val caption = getCaptionForTheApp(wmHelper, device)!! + val maximizeButton = getMaximizeButtonForTheApp(caption) + + when (trigger) { + MaximizeDesktopAppTrigger.MAXIMIZE_MENU -> maximizeButton.click() + MaximizeDesktopAppTrigger.DOUBLE_TAP_APP_HEADER -> { + caption.click() + Thread.sleep(50) + caption.click() + } + + MaximizeDesktopAppTrigger.KEYBOARD_SHORTCUT -> { + val keyEventHelper = KeyEventHelper(getInstrumentation()) + keyEventHelper.press(KEYCODE_EQUALS, META_META_ON) + } + + MaximizeDesktopAppTrigger.MAXIMIZE_BUTTON_IN_MENU -> { + maximizeButton.longClick() + wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() + val buttonResId = MAXIMIZE_BUTTON_IN_MENU + val maximizeMenu = getDesktopAppViewByRes(MAXIMIZE_MENU) + val maximizeButtonInMenu = + maximizeMenu + ?.wait( + Until.findObject(By.res(SYSTEMUI_PACKAGE, buttonResId)), + TIMEOUT.toMillis() + ) + ?: error("Unable to find object with resource id $buttonResId") + maximizeButtonInMenu.click() + } } wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() } @@ -472,6 +498,22 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : device.drag(startX, startY, endX, endY, 100) } + fun enterDesktopModeViaKeyboard( + wmHelper: WindowManagerStateHelper, + ) { + val keyEventHelper = KeyEventHelper(getInstrumentation()) + keyEventHelper.press(KEYCODE_DPAD_DOWN, META_META_ON or META_CTRL_ON) + wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() + } + + fun exitDesktopModeToFullScreenViaKeyboard( + wmHelper: WindowManagerStateHelper, + ) { + val keyEventHelper = KeyEventHelper(getInstrumentation()) + keyEventHelper.press(KEYCODE_DPAD_UP, META_META_ON or META_CTRL_ON) + wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() + } + fun enterDesktopModeFromAppHandleMenu( wmHelper: WindowManagerStateHelper, device: UiDevice @@ -550,6 +592,13 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : rightSideMatching } + enum class MaximizeDesktopAppTrigger { + MAXIMIZE_MENU, + DOUBLE_TAP_APP_HEADER, + KEYBOARD_SHORTCUT, + MAXIMIZE_BUTTON_IN_MENU + } + private companion object { val TIMEOUT: Duration = Duration.ofSeconds(3) const val SNAP_RESIZE_DRAG_INSET: Int = 5 // inset to avoid dragging to display edge @@ -561,6 +610,7 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : const val DESKTOP_MODE_BUTTON: String = "desktop_button" const val SNAP_LEFT_BUTTON: String = "maximize_menu_snap_left_button" const val SNAP_RIGHT_BUTTON: String = "maximize_menu_snap_right_button" + const val MAXIMIZE_BUTTON_IN_MENU: String = "maximize_menu_size_toggle_button" const val MINIMIZE_BUTTON_VIEW: String = "minimize_window" const val HEADER_EMPTY_VIEW: String = "caption_handle" val caption: BySelector diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml index 7c24a4adca3d..98af8b2f53b5 100644 --- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml +++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml @@ -39,7 +39,6 @@ android:value="true" /> <activity android:name=".SimpleActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.SimpleActivity" - android:theme="@style/CutoutShortEdges" android:label="SimpleActivity" android:exported="true"> <intent-filter> @@ -49,7 +48,6 @@ </activity> <activity android:name=".ImeActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivity" - android:theme="@style/CutoutShortEdges" android:label="ImeActivity" android:exported="true"> <intent-filter> @@ -58,7 +56,6 @@ </intent-filter> </activity> <activity android:name=".ImeActivityAutoFocus" - android:theme="@style/CutoutShortEdges" android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivityAutoFocus" android:windowSoftInputMode="stateVisible" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" @@ -81,7 +78,6 @@ </activity> <activity android:name=".SeamlessRotationActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.SeamlessRotationActivity" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" android:showWhenLocked="true" android:label="SeamlessActivity" @@ -92,7 +88,6 @@ </intent-filter> </activity> <activity android:name=".NonResizeableActivity" - android:theme="@style/CutoutShortEdges" android:resizeableActivity="false" android:taskAffinity="com.android.server.wm.flicker.testapp.NonResizeableActivity" android:label="NonResizeableActivity" @@ -174,7 +169,6 @@ </activity> <activity android:name=".LaunchNewActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.LaunchNewActivity" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize" android:label="LaunchNewActivity" android:exported="true"> @@ -185,7 +179,6 @@ </activity> <activity android:name=".LaunchNewTaskActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.LaunchNewTaskActivity" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize" android:label="LaunchNewTaskActivity" android:exported="true"> @@ -207,7 +200,6 @@ </activity> <activity android:name=".PortraitOnlyActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.PortraitOnlyActivity" - android:theme="@style/CutoutShortEdges" android:screenOrientation="portrait" android:configChanges="orientation|screenSize" android:exported="true"> @@ -219,7 +211,6 @@ <activity android:name=".ImeEditorPopupDialogActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.ImeEditorPopupDialogActivity" android:configChanges="orientation|screenSize" - android:theme="@style/CutoutShortEdges" android:label="ImeEditorPopupDialogActivity" android:exported="true"> <intent-filter> @@ -229,7 +220,6 @@ </activity> <activity android:name=".ShowWhenLockedActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.ShowWhenLockedActivity" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize" android:label="ShowWhenLockedActivity" android:showWhenLocked="true" @@ -241,7 +231,6 @@ </activity> <activity android:name=".NotificationActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.NotificationActivity" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize" android:label="NotificationActivity" android:exported="true"> @@ -254,7 +243,6 @@ android:name=".ActivityEmbeddingMainActivity" android:label="ActivityEmbedding Main" android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:exported="true"> <intent-filter> @@ -266,7 +254,6 @@ android:name=".ActivityEmbeddingTrampolineActivity" android:label="ActivityEmbedding Trampoline" android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:exported="false"> </activity> @@ -274,7 +261,6 @@ android:name=".ActivityEmbeddingSecondaryActivity" android:label="ActivityEmbedding Secondary" android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:supportsPictureInPicture="true" android:exported="false"/> @@ -282,21 +268,18 @@ android:name=".ActivityEmbeddingThirdActivity" android:label="ActivityEmbedding Third" android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:exported="false"/> <activity android:name=".ActivityEmbeddingAlwaysExpandActivity" android:label="ActivityEmbedding AlwaysExpand" android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:exported="false"/> <activity android:name=".ActivityEmbeddingPlaceholderPrimaryActivity" android:label="ActivityEmbedding Placeholder Primary" android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:exported="false"> </activity> @@ -304,7 +287,6 @@ android:name=".ActivityEmbeddingPlaceholderSecondaryActivity" android:label="ActivityEmbedding Placeholder Secondary" android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding" - android:theme="@style/CutoutShortEdges" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" android:exported="false"/> <activity android:name=".MailActivity" @@ -334,7 +316,6 @@ android:supportsPictureInPicture="true" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" android:taskAffinity="com.android.server.wm.flicker.testapp.PipActivity" - android:theme="@style/CutoutShortEdges" android:launchMode="singleTop" android:label="PipActivity" android:exported="true"> @@ -350,7 +331,6 @@ <activity android:name=".BottomHalfPipLaunchingActivity" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" android:taskAffinity="com.android.server.wm.flicker.testapp.BottomHalfPipLaunchingActivity" - android:theme="@style/CutoutShortEdges" android:label="BottomHalfPipLaunchingActivity" android:exported="true"> <intent-filter> @@ -371,7 +351,6 @@ <activity android:name=".SplitScreenActivity" android:resizeableActivity="true" android:taskAffinity="com.android.server.wm.flicker.testapp.SplitScreenActivity" - android:theme="@style/CutoutShortEdges" android:label="SplitScreenPrimaryActivity" android:exported="true" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"> @@ -383,7 +362,6 @@ <activity android:name=".SplitScreenSecondaryActivity" android:resizeableActivity="true" android:taskAffinity="com.android.server.wm.flicker.testapp.SplitScreenSecondaryActivity" - android:theme="@style/CutoutShortEdges" android:label="SplitScreenSecondaryActivity" android:exported="true" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"> @@ -396,7 +374,6 @@ </activity> <activity android:name=".SendNotificationActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.SendNotificationActivity" - android:theme="@style/CutoutShortEdges" android:label="SendNotificationActivity" android:exported="true"> <intent-filter> @@ -408,7 +385,6 @@ android:name=".LaunchBubbleActivity" android:label="LaunchBubbleActivity" android:exported="true" - android:theme="@style/CutoutShortEdges" android:launchMode="singleTop"> <intent-filter> <action android:name="android.intent.action.MAIN"/> @@ -420,7 +396,6 @@ android:name=".BubbleActivity" android:label="BubbleActivity" android:exported="false" - android:theme="@style/CutoutShortEdges" android:resizeableActivity="true"/> <activity android:name=".TransferSplashscreenActivity" @@ -468,4 +443,4 @@ </service> </application> <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/> -</manifest> +</manifest>
\ No newline at end of file diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bottom_half_pip.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bottom_half_pip.xml index 2f9c3aa82057..15e2a798b2cf 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bottom_half_pip.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bottom_half_pip.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:orientation="vertical" android:background="@android:color/holo_blue_bright"> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bubble.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bubble.xml index 7c7b2cacaefb..4bc70996eba8 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bubble.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bubble.xml @@ -16,6 +16,7 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:fitsSystemWindows="true" android:layout_width="match_parent" android:layout_height="match_parent"> <Button diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml index f0dfdfce035f..e98ffd045d3d 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml @@ -19,5 +19,6 @@ android:id="@+id/root_activity_layout" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:orientation="vertical"> </LinearLayout> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml index 939ba81a47ea..16c906d9ee42 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:background="@android:color/holo_orange_light"> <LinearLayout diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml index 6d4de995bd73..eedb910b2b4e 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml @@ -19,6 +19,7 @@ android:id="@+id/secondary_activity_layout" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:orientation="vertical"> <Button @@ -49,4 +50,4 @@ android:layout_height="48dp" android:text="Enter pip" /> -</LinearLayout>
\ No newline at end of file +</LinearLayout> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml index 507c1b622613..5e5203cb0545 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml @@ -17,6 +17,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_green_light" + android:fitsSystemWindows="true" android:focusableInTouchMode="true" android:orientation="vertical"> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_launch_new.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_launch_new.xml index fe7bced690f9..2ab5fe7b9d6c 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_launch_new.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_launch_new.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:background="@android:color/holo_orange_light"> <Button android:id="@+id/launch_second_activity" diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml index 8a97433ede04..fcef791afe2e 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml @@ -19,6 +19,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" + android:fitsSystemWindows="true" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml index 6d5a9dd29248..aeb8423680a3 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:orientation="vertical" android:background="@android:color/holo_orange_light"> @@ -29,4 +30,4 @@ android:text="NonResizeableActivity" android:textAppearance="?android:attr/textAppearanceLarge"/> -</LinearLayout>
\ No newline at end of file +</LinearLayout> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml index 365a0ea017f6..d66b3d74e114 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:orientation="vertical" android:background="@android:color/holo_blue_bright"> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_simple.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_simple.xml index 5d94e5177dcc..42213d6812da 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_simple.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_simple.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:background="@android:color/holo_orange_light"> </LinearLayout> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen.xml index 79e88e49b99e..16c3bc07d55c 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:orientation="vertical" android:background="@android:color/holo_green_light"> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen_secondary.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen_secondary.xml index ed9feaf1eade..7643cf5de216 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen_secondary.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen_secondary.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:orientation="vertical" android:background="@android:color/holo_blue_light"> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml index c34d2003ef42..79e7bb5de96e 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:gravity="center" android:orientation="vertical" android:background="@android:color/holo_orange_light"> @@ -39,4 +40,4 @@ android:gravity="center_vertical|center_horizontal" android:text="Start Media Projection with extra intent" android:textAppearance="?android:attr/textAppearanceLarge"/> -</LinearLayout>
\ No newline at end of file +</LinearLayout> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml index 0b4693dec6e1..4d12168ca8db 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml @@ -19,6 +19,7 @@ android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:background="@android:color/holo_orange_light"> <SurfaceView diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent.xml index 0730ded66ce4..32df5f015414 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent.xml @@ -15,6 +15,7 @@ ~ limitations under the License. --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:fitsSystemWindows="true" android:layout_width="match_parent" android:layout_height="match_parent"> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent_launch.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent_launch.xml index ff4ead95f16e..a0c87fd17fc3 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent_launch.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent_launch.xml @@ -17,6 +17,7 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:orientation="vertical" android:background="@android:color/black"> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/notification_button.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/notification_button.xml index 78072006f681..da58b3f43c73 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/notification_button.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/notification_button.xml @@ -18,10 +18,12 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:background="@android:color/holo_orange_light"> <Button android:id="@+id/post_notification" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_gravity="center_horizontal|center_vertical" android:text="Post Notification" /> </LinearLayout> diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml index 8f75d175d00a..ec3135c0a42d 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:background="@android:color/holo_orange_light"> <Button android:id="@+id/launch_new_task" diff --git a/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml b/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml index 837d050b73ff..ca3244820893 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml @@ -36,10 +36,6 @@ <item name="android:windowLayoutInDisplayCutoutMode">default</item> </style> - <style name="CutoutShortEdges" parent="@style/DefaultTheme"> - <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item> - </style> - <style name="CutoutNever" parent="@style/DefaultTheme"> <item name="android:windowLayoutInDisplayCutoutMode">never</item> </style> @@ -78,4 +74,4 @@ <!-- Here we want to match the duration of our AVD --> <item name="android:windowSplashScreenAnimationDuration">900</item> </style> -</resources> +</resources>
\ No newline at end of file diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java index 4418b5a5ff82..30bf616cfe74 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java @@ -30,7 +30,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.util.Log; -import android.view.WindowManager; public class ImeActivity extends Activity { @@ -64,10 +63,6 @@ public class ImeActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - WindowManager.LayoutParams p = getWindow().getAttributes(); - p.layoutInDisplayCutoutMode = WindowManager.LayoutParams - .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; - getWindow().setAttributes(p); setContentView(R.layout.activity_ime); final var filter = new IntentFilter(); diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeEditorPopupDialogActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeEditorPopupDialogActivity.java index 95f933f97bb2..887a15c9ea90 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeEditorPopupDialogActivity.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeEditorPopupDialogActivity.java @@ -30,8 +30,6 @@ public class ImeEditorPopupDialogActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); WindowManager.LayoutParams p = getWindow().getAttributes(); - p.layoutInDisplayCutoutMode = WindowManager.LayoutParams - .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; p.softInputMode = SOFT_INPUT_STATE_ALWAYS_HIDDEN; getWindow().setAttributes(p); LinearLayout layout = new LinearLayout(this); diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewActivity.java index e5710c850f07..97d7a64d5ebf 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewActivity.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewActivity.java @@ -19,17 +19,12 @@ package com.android.server.wm.flicker.testapp; import android.app.Activity; import android.content.Intent; import android.os.Bundle; -import android.view.WindowManager; import android.widget.Button; public class LaunchNewActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - WindowManager.LayoutParams p = getWindow().getAttributes(); - p.layoutInDisplayCutoutMode = WindowManager.LayoutParams - .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; - getWindow().setAttributes(p); setContentView(R.layout.activity_launch_new); Button button = findViewById(R.id.launch_second_activity); diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java index 1809781b33e6..402a393e7028 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java @@ -21,17 +21,12 @@ import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import android.app.Activity; import android.content.Intent; import android.os.Bundle; -import android.view.WindowManager; import android.widget.Button; public class LaunchNewTaskActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - WindowManager.LayoutParams p = getWindow().getAttributes(); - p.layoutInDisplayCutoutMode = WindowManager.LayoutParams - .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; - getWindow().setAttributes(p); setContentView(R.layout.task_button); Button button = findViewById(R.id.launch_new_task); diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NotificationActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NotificationActivity.java index d6427abcc65a..61254385e980 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NotificationActivity.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NotificationActivity.java @@ -45,14 +45,10 @@ public class NotificationActivity extends Activity { requestPermissions(new String[] { POST_NOTIFICATIONS }, 0); } - WindowManager.LayoutParams p = getWindow().getAttributes(); - p.layoutInDisplayCutoutMode = WindowManager.LayoutParams - .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; - getWindow().setAttributes(p); setContentView(R.layout.notification_button); - Button button = findViewById(R.id.post_notification); - button.setOnClickListener(v -> postNotification()); + ((Button) findViewById(R.id.post_notification)) + .setOnClickListener(v -> postNotification()); createNotificationChannel(); } diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java index ee25ab2fb66c..e030dcf0db9b 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java @@ -47,8 +47,6 @@ import android.util.DisplayMetrics; import android.util.Log; import android.util.Rational; import android.view.View; -import android.view.Window; -import android.view.WindowManager; import android.widget.CheckBox; import android.widget.RadioButton; @@ -145,12 +143,6 @@ public class PipActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - final Window window = getWindow(); - final WindowManager.LayoutParams layoutParams = window.getAttributes(); - layoutParams.layoutInDisplayCutoutMode = WindowManager.LayoutParams - .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; - window.setAttributes(layoutParams); - setContentView(R.layout.activity_pip); findViewById(R.id.media_session_start) diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitOnlyActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitOnlyActivity.java index b1876b5e5511..552d843676bb 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitOnlyActivity.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitOnlyActivity.java @@ -18,16 +18,11 @@ package com.android.server.wm.flicker.testapp; import android.app.Activity; import android.os.Bundle; -import android.view.WindowManager; public class PortraitOnlyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - WindowManager.LayoutParams p = getWindow().getAttributes(); - p.layoutInDisplayCutoutMode = WindowManager.LayoutParams - .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; - getWindow().setAttributes(p); setContentView(R.layout.activity_simple); } } diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java index ce7a0059fa2d..e98c34db0cd9 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java @@ -61,8 +61,6 @@ public class SeamlessRotationActivity extends Activity { private void enableSeamlessRotation() { WindowManager.LayoutParams p = getWindow().getAttributes(); p.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS; - p.layoutInDisplayCutoutMode = WindowManager.LayoutParams - .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ShowWhenLockedActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ShowWhenLockedActivity.java index 6f94b74ccf41..a533c9052574 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ShowWhenLockedActivity.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ShowWhenLockedActivity.java @@ -18,16 +18,11 @@ package com.android.server.wm.flicker.testapp; import android.app.Activity; import android.os.Bundle; -import android.view.WindowManager; public class ShowWhenLockedActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - WindowManager.LayoutParams p = getWindow().getAttributes(); - p.layoutInDisplayCutoutMode = WindowManager.LayoutParams - .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; - getWindow().setAttributes(p); setContentView(R.layout.activity_simple); } } diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SimpleActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SimpleActivity.java index 699abf87d341..c56eefe32189 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SimpleActivity.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SimpleActivity.java @@ -18,16 +18,11 @@ package com.android.server.wm.flicker.testapp; import android.app.Activity; import android.os.Bundle; -import android.view.WindowManager; public class SimpleActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - WindowManager.LayoutParams p = getWindow().getAttributes(); - p.layoutInDisplayCutoutMode = WindowManager.LayoutParams - .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; - getWindow().setAttributes(p); setContentView(R.layout.activity_simple); } } diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp index 1f0bd61b5c3f..544f94b49ee7 100644 --- a/tests/Input/Android.bp +++ b/tests/Input/Android.bp @@ -15,6 +15,7 @@ android_test { "modules-utils-testable-device-config-defaults", ], srcs: [ + "src/**/*.aidl", "src/**/*.java", "src/**/*.kt", ], diff --git a/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt b/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt index e99c81493394..794fd0255726 100644 --- a/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt +++ b/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt @@ -214,9 +214,5 @@ class KeyGestureEventHandlerTest { ): Boolean { return handler(event, focusedToken) } - - override fun isKeyGestureSupported(gestureType: Int): Boolean { - return true - } } } diff --git a/tests/Input/src/com/android/server/input/BatteryControllerTests.kt b/tests/Input/src/com/android/server/input/BatteryControllerTests.kt index 044f11d6904c..890c346ea015 100644 --- a/tests/Input/src/com/android/server/input/BatteryControllerTests.kt +++ b/tests/Input/src/com/android/server/input/BatteryControllerTests.kt @@ -184,6 +184,8 @@ class BatteryControllerTests { @get:Rule val rule = MockitoJUnit.rule()!! @get:Rule + val context = TestableContext(ApplicationProvider.getApplicationContext()) + @get:Rule val inputManagerRule = MockInputManagerRule() @Mock @@ -194,7 +196,6 @@ class BatteryControllerTests { private lateinit var bluetoothBatteryManager: BluetoothBatteryManager private lateinit var batteryController: BatteryController - private lateinit var context: TestableContext private lateinit var testLooper: TestLooper private lateinit var devicesChangedListener: IInputDevicesChangedListener private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession @@ -202,7 +203,6 @@ class BatteryControllerTests { @Before fun setup() { - context = TestableContext(ApplicationProvider.getApplicationContext()) testLooper = TestLooper() val inputManager = InputManager(context) context.addMockSystemService(InputManager::class.java, inputManager) diff --git a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt index a2f6f0051116..7ec8f9ce9864 100644 --- a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt +++ b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt @@ -76,7 +76,7 @@ import org.mockito.Mockito.spy import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions -import org.mockito.Mockito.verifyZeroInteractions +import org.mockito.Mockito.verifyNoInteractions import org.mockito.Mockito.`when` import org.mockito.stubbing.OngoingStubbing @@ -160,7 +160,7 @@ class InputManagerServiceTests { testLooper = TestLooper() service = InputManagerService(object : InputManagerService.Injector( - context, testLooper.looper, uEventManager) { + context, testLooper.looper, testLooper.looper, uEventManager) { override fun getNativeService( service: InputManagerService? ): NativeInputManagerService { @@ -209,7 +209,7 @@ class InputManagerServiceTests { @Test fun testStart() { - verifyZeroInteractions(native) + verifyNoInteractions(native) service.start() verify(native).start() @@ -217,7 +217,7 @@ class InputManagerServiceTests { @Test fun testInputSettingsUpdatedOnSystemRunning() { - verifyZeroInteractions(native) + verifyNoInteractions(native) runWithShellPermissionIdentity { service.systemRunning() diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt index 88e84966634b..4f1fb6487b19 100644 --- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt +++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt @@ -32,6 +32,7 @@ import android.hardware.input.InputGestureData import android.hardware.input.InputManager import android.hardware.input.InputManagerGlobal import android.hardware.input.KeyGestureEvent +import android.os.Handler import android.os.IBinder import android.os.Process import android.os.SystemClock @@ -48,9 +49,11 @@ import android.view.WindowManagerPolicyConstants.FLAG_INTERACTIVE import androidx.test.core.app.ApplicationProvider import com.android.dx.mockito.inline.extended.ExtendedMockito import com.android.internal.R +import com.android.internal.accessibility.AccessibilityShortcutController import com.android.internal.annotations.Keep import com.android.internal.util.FrameworkStatsLog import com.android.modules.utils.testing.ExtendedMockitoRule +import com.android.server.input.InputManagerService.WindowManagerCallbacks import java.io.File import java.io.FileOutputStream import java.io.InputStream @@ -67,6 +70,8 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito +import org.mockito.kotlin.never +import org.mockito.kotlin.times /** * Tests for {@link KeyGestureController}. @@ -102,6 +107,7 @@ class KeyGestureControllerTests { const val SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY = 0 const val SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL = 1 const val SETTINGS_KEY_BEHAVIOR_NOTHING = 2 + const val TEST_PID = 10 } @JvmField @@ -116,11 +122,10 @@ class KeyGestureControllerTests { @Rule val rule = SetFlagsRule() - @Mock - private lateinit var iInputManager: IInputManager - - @Mock - private lateinit var packageManager: PackageManager + @Mock private lateinit var iInputManager: IInputManager + @Mock private lateinit var packageManager: PackageManager + @Mock private lateinit var wmCallbacks: WindowManagerCallbacks + @Mock private lateinit var accessibilityShortcutController: AccessibilityShortcutController private var currentPid = 0 private lateinit var context: Context @@ -207,8 +212,34 @@ class KeyGestureControllerTests { private fun setupKeyGestureController() { keyGestureController = - KeyGestureController(context, testLooper.looper, inputDataStore) - Mockito.`when`(iInputManager.getAppLaunchBookmarks()) + KeyGestureController( + context, + testLooper.looper, + testLooper.looper, + inputDataStore, + object : KeyGestureController.Injector() { + override fun getAccessibilityShortcutController( + context: Context?, + handler: Handler? + ): AccessibilityShortcutController { + return accessibilityShortcutController + } + }) + Mockito.`when`(iInputManager.registerKeyGestureHandler(Mockito.any())) + .thenAnswer { + val args = it.arguments + if (args[0] != null) { + keyGestureController.registerKeyGestureHandler( + args[0] as IKeyGestureHandler, + TEST_PID + ) + } + } + keyGestureController.setWindowManagerCallbacks(wmCallbacks) + Mockito.`when`(wmCallbacks.isKeyguardLocked(Mockito.anyInt())).thenReturn(false) + Mockito.`when`(accessibilityShortcutController + .isAccessibilityShortcutAvailable(Mockito.anyBoolean())).thenReturn(true) + Mockito.`when`(iInputManager.appLaunchBookmarks) .thenReturn(keyGestureController.appLaunchBookmarks) keyGestureController.systemRunning() testLooper.dispatchAll() @@ -371,18 +402,6 @@ class KeyGestureControllerTests { intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) ), TestData( - "META + CTRL + N -> Open Notes", - intArrayOf( - KeyEvent.KEYCODE_META_LEFT, - KeyEvent.KEYCODE_CTRL_LEFT, - KeyEvent.KEYCODE_N - ), - KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES, - intArrayOf(KeyEvent.KEYCODE_N), - KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON, - intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) - ), - TestData( "META + S -> Take Screenshot", intArrayOf( KeyEvent.KEYCODE_META_LEFT, @@ -394,14 +413,6 @@ class KeyGestureControllerTests { intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) ), TestData( - "META + DEL -> Back", - intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_DEL), - KeyGestureEvent.KEY_GESTURE_TYPE_BACK, - intArrayOf(KeyEvent.KEYCODE_DEL), - KeyEvent.META_META_ON, - intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) - ), - TestData( "META + ESC -> Back", intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_ESCAPE), KeyGestureEvent.KEY_GESTURE_TYPE_BACK, @@ -1290,9 +1301,9 @@ class KeyGestureControllerTests { ) ), TestData( - "BACK + DPAD_DOWN -> TV Accessibility Chord", + "BACK + DPAD_DOWN -> Accessibility Chord(for TV)", intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN), - KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD, + KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD, intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN), 0, intArrayOf( @@ -1642,6 +1653,52 @@ class KeyGestureControllerTests { ) } + @Test + fun testAccessibilityShortcutChordPressed() { + setupKeyGestureController() + + sendKeys( + intArrayOf(KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN), + // Assuming this value is always greater than the accessibility shortcut timeout, which + // currently defaults to 3000ms + timeDelayMs = 10000 + ) + Mockito.verify(accessibilityShortcutController, times(1)).performAccessibilityShortcut() + } + + @Test + fun testAccessibilityTvShortcutChordPressed() { + setupKeyGestureController() + + sendKeys( + intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN), + timeDelayMs = 10000 + ) + Mockito.verify(accessibilityShortcutController, times(1)).performAccessibilityShortcut() + } + + @Test + fun testAccessibilityShortcutChordPressedForLessThanTimeout() { + setupKeyGestureController() + + sendKeys( + intArrayOf(KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN), + timeDelayMs = 0 + ) + Mockito.verify(accessibilityShortcutController, never()).performAccessibilityShortcut() + } + + @Test + fun testAccessibilityTvShortcutChordPressedForLessThanTimeout() { + setupKeyGestureController() + + sendKeys( + intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN), + timeDelayMs = 0 + ) + Mockito.verify(accessibilityShortcutController, never()).performAccessibilityShortcut() + } + private fun testKeyGestureInternal(test: TestData) { val handledEvents = mutableListOf<KeyGestureEvent>() val handler = KeyGestureHandler { event, _ -> @@ -1703,7 +1760,11 @@ class KeyGestureControllerTests { assertEquals("Test: $testName should not produce Key gesture", 0, handledEvents.size) } - private fun sendKeys(testKeys: IntArray, assertNotSentToApps: Boolean = false) { + private fun sendKeys( + testKeys: IntArray, + assertNotSentToApps: Boolean = false, + timeDelayMs: Long = 0 + ) { var metaState = 0 val now = SystemClock.uptimeMillis() for (key in testKeys) { @@ -1719,6 +1780,11 @@ class KeyGestureControllerTests { testLooper.dispatchAll() } + if (timeDelayMs > 0) { + testLooper.moveTimeForward(timeDelayMs) + testLooper.dispatchAll() + } + for (key in testKeys.reversed()) { val upEvent = KeyEvent( now, now, KeyEvent.ACTION_UP, key, 0 /*repeat*/, metaState, @@ -1762,9 +1828,5 @@ class KeyGestureControllerTests { override fun handleKeyGesture(event: AidlKeyGestureEvent, token: IBinder?): Boolean { return handler(event, token) } - - override fun isKeyGestureSupported(gestureType: Int): Boolean { - return true - } } } diff --git a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewControllerTests.java b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewControllerTests.java index 5875520cd259..20528f23cc8c 100644 --- a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewControllerTests.java +++ b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewControllerTests.java @@ -23,7 +23,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.Context; import android.graphics.Rect; import android.hardware.input.InputManager; import android.testing.AndroidTestingRunner; @@ -60,9 +59,12 @@ public class TouchpadDebugViewControllerTests { private static final String TAG = "TouchpadDebugViewController"; @Rule + public final TestableContext mTestableContext = + new TestableContext(InstrumentationRegistry.getInstrumentation().getContext()); + + @Rule public final MockitoRule mockito = MockitoJUnit.rule(); - private Context mContext; private TouchpadDebugViewController mTouchpadDebugViewController; @Mock private InputManager mInputManagerMock; @@ -74,8 +76,6 @@ public class TouchpadDebugViewControllerTests { @Before public void setup() throws Exception { - mContext = InstrumentationRegistry.getInstrumentation().getContext(); - TestableContext mTestableContext = new TestableContext(mContext); mTestableContext.addMockSystemService(WindowManager.class, mWindowManagerMock); Rect bounds = new Rect(0, 0, 2560, 1600); diff --git a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java index 60fa52f85e34..1c366a134300 100644 --- a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java +++ b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java @@ -26,7 +26,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.Context; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; @@ -51,6 +50,7 @@ import com.android.server.input.TouchpadHardwareProperties; import com.android.server.input.TouchpadHardwareState; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -70,6 +70,10 @@ public class TouchpadDebugViewTest { private TouchpadDebugView mTouchpadDebugView; private WindowManager.LayoutParams mWindowLayoutParams; + @Rule + public final TestableContext mTestableContext = + new TestableContext(InstrumentationRegistry.getInstrumentation().getContext()); + @Mock WindowManager mWindowManager; @Mock @@ -77,14 +81,10 @@ public class TouchpadDebugViewTest { Rect mWindowBounds; WindowMetrics mWindowMetrics; - TestableContext mTestableContext; @Before public void setUp() { MockitoAnnotations.initMocks(this); - Context context = InstrumentationRegistry.getInstrumentation().getContext(); - mTestableContext = new TestableContext(context); - mTestableContext.addMockSystemService(WindowManager.class, mWindowManager); mTestableContext.addMockSystemService(InputManager.class, mInputManager); diff --git a/tests/Input/src/com/android/test/input/AnrTest.kt b/tests/Input/src/com/android/test/input/AnrTest.kt index cd6ab30d8678..f8cb86b7b1fe 100644 --- a/tests/Input/src/com/android/test/input/AnrTest.kt +++ b/tests/Input/src/com/android/test/input/AnrTest.kt @@ -15,33 +15,37 @@ */ package com.android.test.input -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.filters.MediumTest - import android.app.ActivityManager import android.app.ApplicationExitInfo -import android.content.Context -import android.graphics.Rect +import android.app.Instrumentation +import android.content.Intent import android.hardware.display.DisplayManager import android.os.Build +import android.os.Bundle +import android.os.IBinder import android.os.IInputConstants.UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS import android.os.SystemClock -import android.provider.Settings -import android.provider.Settings.Global.HIDE_ERROR_DIALOGS -import android.server.wm.CtsWindowInfoUtils.waitForStableWindowGeometry +import android.server.wm.CtsWindowInfoUtils.getWindowCenter +import android.server.wm.CtsWindowInfoUtils.waitForWindowOnTop import android.testing.PollingCheck - +import android.view.InputEvent +import android.view.MotionEvent +import android.view.MotionEvent.ACTION_DOWN +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.MediumTest +import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiObject2 import androidx.test.uiautomator.Until - +import com.android.cts.input.BlockingQueueEventVerifier import com.android.cts.input.DebugInputRule +import com.android.cts.input.ShowErrorDialogsRule import com.android.cts.input.UinputTouchScreen - +import com.android.cts.input.inputeventmatchers.withMotionAction import java.time.Duration - +import java.util.concurrent.LinkedBlockingQueue +import java.util.function.Supplier import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue @@ -52,13 +56,34 @@ import org.junit.Test import org.junit.runner.RunWith /** + * Click on the center of the window identified by the provided window token. + * The click is performed using "UinputTouchScreen" device. + * If the touchscreen device is closed too soon, it may cause the click to be dropped. Therefore, + * the provided runnable can ensure that the click is delivered before the device is closed, thus + * avoiding this race. + */ +private fun clickOnWindow( + token: IBinder, + displayId: Int, + instrumentation: Instrumentation, + waitForEvent: Runnable, +) { + val displayManager = instrumentation.context.getSystemService(DisplayManager::class.java) + val display = displayManager.getDisplay(displayId) + val point = getWindowCenter({ token }, display.displayId) + UinputTouchScreen(instrumentation, display).use { touchScreen -> + touchScreen.touchDown(point.x, point.y).lift() + // If the device is allowed to close without waiting here, the injected click may be dropped + waitForEvent.run() + } +} + +/** * This test makes sure that an unresponsive gesture monitor gets an ANR. * * The gesture monitor must be registered from a different process than the instrumented process. - * Otherwise, when the test runs, you will get: - * Test failed to run to completion. - * Reason: 'Instrumentation run failed due to 'keyDispatchingTimedOut''. - * Check device logcat for details + * Otherwise, when the test runs, you will get: Test failed to run to completion. Reason: + * 'Instrumentation run failed due to 'keyDispatchingTimedOut''. Check device logcat for details * RUNNER ERROR: Instrumentation run failed due to 'keyDispatchingTimedOut' */ @MediumTest @@ -66,32 +91,43 @@ import org.junit.runner.RunWith class AnrTest { companion object { private const val TAG = "AnrTest" - private const val ALL_PIDS = 0 private const val NO_MAX = 0 } private val instrumentation = InstrumentationRegistry.getInstrumentation() - private var hideErrorDialogs = 0 private lateinit var PACKAGE_NAME: String - private val DISPATCHING_TIMEOUT = (UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS * - Build.HW_TIMEOUT_MULTIPLIER) + private val DISPATCHING_TIMEOUT = + (UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS * Build.HW_TIMEOUT_MULTIPLIER) + private var remoteWindowToken: IBinder? = null + private var remoteDisplayId: Int? = null + private var remotePid: Int? = null + private val remoteInputEvents = LinkedBlockingQueue<InputEvent>() + private val verifier = BlockingQueueEventVerifier(remoteInputEvents) + + val binder = + object : IAnrTestService.Stub() { + override fun provideActivityInfo(token: IBinder, displayId: Int, pid: Int) { + remoteWindowToken = token + remoteDisplayId = displayId + remotePid = pid + } + + override fun notifyMotion(event: MotionEvent) { + remoteInputEvents.add(event) + } + } - @get:Rule - val debugInputRule = DebugInputRule() + @get:Rule val showErrorDialogs = ShowErrorDialogsRule() + + @get:Rule val debugInputRule = DebugInputRule() @Before fun setUp() { - val contentResolver = instrumentation.targetContext.contentResolver - hideErrorDialogs = Settings.Global.getInt(contentResolver, HIDE_ERROR_DIALOGS, 0) - Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, 0) + startUnresponsiveActivity() PACKAGE_NAME = UnresponsiveGestureMonitorActivity::class.java.getPackage()!!.getName() } - @After - fun tearDown() { - val contentResolver = instrumentation.targetContext.contentResolver - Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, hideErrorDialogs) - } + @After fun tearDown() {} @Test @DebugInputRule.DebugInput(bug = 339924248) @@ -115,7 +151,7 @@ class AnrTest { val timestamp = System.currentTimeMillis() val uiDevice: UiDevice = UiDevice.getInstance(instrumentation) val closeAppButton: UiObject2? = - uiDevice.wait(Until.findObject(By.res("android:id/aerr_close")), 20000) + uiDevice.wait(Until.findObject(By.res("android:id/aerr_close")), 20000) if (closeAppButton == null) { fail("Could not find anr dialog/close button") return @@ -123,10 +159,10 @@ class AnrTest { closeAppButton.click() /** * We must wait for the app to be fully closed before exiting this test. This is because - * another test may again invoke 'am start' for the same activity. - * If the 1st process that got ANRd isn't killed by the time second 'am start' runs, - * the killing logic will apply to the newly launched 'am start' instance, and the second - * test will fail because the unresponsive activity will never be launched. + * another test may again invoke 'am start' for the same activity. If the 1st process that + * got ANRd isn't killed by the time second 'am start' runs, the killing logic will apply to + * the newly launched 'am start' instance, and the second test will fail because the + * unresponsive activity will never be launched. */ waitForNewExitReasonAfter(timestamp) } @@ -135,7 +171,7 @@ class AnrTest { // Find anr dialog and tap on wait val uiDevice: UiDevice = UiDevice.getInstance(instrumentation) val waitButton: UiObject2? = - uiDevice.wait(Until.findObject(By.res("android:id/aerr_wait")), 20000) + uiDevice.wait(Until.findObject(By.res("android:id/aerr_wait")), 20000) if (waitButton == null) { fail("Could not find anr dialog/wait button") return @@ -147,7 +183,7 @@ class AnrTest { lateinit var infos: List<ApplicationExitInfo> instrumentation.runOnMainSync { val am = instrumentation.getContext().getSystemService(ActivityManager::class.java)!! - infos = am.getHistoricalProcessExitReasons(PACKAGE_NAME, ALL_PIDS, NO_MAX) + infos = am.getHistoricalProcessExitReasons(PACKAGE_NAME, remotePid!!, NO_MAX) } return infos } @@ -162,37 +198,32 @@ class AnrTest { assertEquals(ApplicationExitInfo.REASON_ANR, reasons[0].reason) } - private fun clickOnObject(obj: UiObject2) { - val displayManager = - instrumentation.context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager - val display = displayManager.getDisplay(obj.getDisplayId()) - val rect: Rect = obj.visibleBounds - UinputTouchScreen(instrumentation, display).use { touchScreen -> - touchScreen - .touchDown(rect.centerX(), rect.centerY()) - .lift() - } - } - private fun triggerAnr() { - startUnresponsiveActivity() - val uiDevice: UiDevice = UiDevice.getInstance(instrumentation) - val obj: UiObject2? = uiDevice.wait(Until.findObject(By.pkg(PACKAGE_NAME)), 10000) - - if (obj == null) { - fail("Could not find unresponsive activity") - return - } - - clickOnObject(obj) + clickOnWindow( + remoteWindowToken!!, + remoteDisplayId!!, + instrumentation, + ) { verifier.assertReceivedMotion(withMotionAction(ACTION_DOWN)) } SystemClock.sleep(DISPATCHING_TIMEOUT.toLong()) // default ANR timeout for gesture monitors } private fun startUnresponsiveActivity() { - val flags = " -W -n " - val startCmd = "am start $flags $PACKAGE_NAME/.UnresponsiveGestureMonitorActivity" - instrumentation.uiAutomation.executeShellCommand(startCmd) - waitForStableWindowGeometry(Duration.ofSeconds(5)) + val intent = + Intent(instrumentation.targetContext, UnresponsiveGestureMonitorActivity::class.java) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_NEW_DOCUMENT + val bundle = Bundle() + bundle.putBinder("serviceBinder", binder) + intent.putExtra("serviceBundle", bundle) + instrumentation.targetContext.startActivity(intent) + // first, wait for the token to become valid + PollingCheck.check( + "UnresponsiveGestureMonitorActivity failed to call 'provideActivityInfo'", + Duration.ofSeconds(5).toMillis()) { remoteWindowToken != null } + // next, wait for the window of the activity to get on top + // we could combine the two checks above, but the current setup makes it easier to detect + // errors + assertTrue("Remote activity window did not become visible", + waitForWindowOnTop(Duration.ofSeconds(5), Supplier { remoteWindowToken })) } } diff --git a/tests/Input/src/com/android/test/input/IAnrTestService.aidl b/tests/Input/src/com/android/test/input/IAnrTestService.aidl new file mode 100644 index 000000000000..e3caf06b742b --- /dev/null +++ b/tests/Input/src/com/android/test/input/IAnrTestService.aidl @@ -0,0 +1,17 @@ +package com.android.test.input; + +import android.view.MotionEvent; + +interface IAnrTestService { + /** + * Provide the activity information. This includes: + * windowToken: the windowToken of the activity window + * displayId: the display id on which the activity is positioned + * pid: the pid of the activity + */ + void provideActivityInfo(IBinder windowToken, int displayId, int pid); + /** + * Provide the MotionEvent received by the remote activity. + */ + void notifyMotion(in MotionEvent event); +} diff --git a/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt index 1842f0a64a83..1e44617af111 100644 --- a/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt +++ b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt @@ -23,20 +23,24 @@ import android.app.Activity import android.hardware.input.InputManager import android.os.Bundle import android.os.Looper +import android.os.Process import android.util.Log import android.view.InputChannel import android.view.InputEvent import android.view.InputEventReceiver import android.view.InputMonitor +import android.view.MotionEvent -class UnresponsiveReceiver(channel: InputChannel, looper: Looper) : - InputEventReceiver(channel, looper) { +class UnresponsiveReceiver(channel: InputChannel, looper: Looper, val service: IAnrTestService) : + InputEventReceiver(channel, looper) { companion object { const val TAG = "UnresponsiveReceiver" } + override fun onInputEvent(event: InputEvent) { Log.i(TAG, "Received $event") // Not calling 'finishInputEvent' in order to trigger the ANR + service.notifyMotion(event as MotionEvent) } } @@ -44,14 +48,27 @@ class UnresponsiveGestureMonitorActivity : Activity() { companion object { const val MONITOR_NAME = "unresponsive gesture monitor" } + private lateinit var mInputEventReceiver: InputEventReceiver private lateinit var mInputMonitor: InputMonitor + private lateinit var service: IAnrTestService override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + val bundle = intent.getBundleExtra("serviceBundle")!! + service = IAnrTestService.Stub.asInterface(bundle.getBinder("serviceBinder")) val inputManager = checkNotNull(getSystemService(InputManager::class.java)) mInputMonitor = inputManager.monitorGestureInput(MONITOR_NAME, displayId) - mInputEventReceiver = UnresponsiveReceiver( - mInputMonitor.getInputChannel(), Looper.myLooper()!!) + mInputEventReceiver = + UnresponsiveReceiver(mInputMonitor.getInputChannel(), Looper.myLooper()!!, service) + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + service.provideActivityInfo( + window.decorView.windowToken, + display.displayId, + Process.myPid(), + ) } } diff --git a/tests/PackageWatchdog/Android.bp b/tests/PackageWatchdog/Android.bp index 44e545bac0ce..46cb5b7482e9 100644 --- a/tests/PackageWatchdog/Android.bp +++ b/tests/PackageWatchdog/Android.bp @@ -28,6 +28,7 @@ android_test { static_libs: [ "PlatformProperties", "androidx.test.rules", + "androidx.test.runner", "flag-junit", "frameworks-base-testutils", "junit", @@ -54,4 +55,8 @@ android_test { "mts-crashrecovery", ], min_sdk_version: "36", + + // Test coverage system runs on different devices. Need to + // compile for all architecture. + compile_multilib: "both", } diff --git a/tests/PackageWatchdog/AndroidManifest.xml b/tests/PackageWatchdog/AndroidManifest.xml index 540edb41f66f..334d50fe6d10 100644 --- a/tests/PackageWatchdog/AndroidManifest.xml +++ b/tests/PackageWatchdog/AndroidManifest.xml @@ -15,7 +15,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.tests.packagewatchdog" > + package="com.android.server" > <application android:debuggable="true"> <uses-library android:name="android.test.runner" /> @@ -23,6 +23,6 @@ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.tests.packagewatchdog" - android:label="PackageWatchdog Test"/> + android:targetPackage="com.android.server" + android:label="PackageWatchdog Test"/> </manifest> diff --git a/tests/PackageWatchdog/AndroidTest.xml b/tests/PackageWatchdog/AndroidTest.xml new file mode 100644 index 000000000000..45a88cdf5abe --- /dev/null +++ b/tests/PackageWatchdog/AndroidTest.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> +<configuration description="Runs PackageWatchdog Tests."> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="PackageWatchdogTest.apk" /> + </target_preparer> + + <option name="test-suite-tag" value="apct" /> + <option name="test-tag" value="PackageWatchdogTest" /> + + <!-- Only run this tests in MTS if the Crashrecovery Mainline module is installed. --> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController"> + <option name="mainline-module-package-name" value="com.google.android.crashrecovery" /> + </object> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.server" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> + <option name="hidden-api-checks" value="false"/> + </test> +</configuration> diff --git a/tests/SoundTriggerTestApp/OWNERS b/tests/SoundTriggerTestApp/OWNERS index a0fcfc52704d..1e41886fe716 100644 --- a/tests/SoundTriggerTestApp/OWNERS +++ b/tests/SoundTriggerTestApp/OWNERS @@ -1,2 +1 @@ include /media/java/android/media/soundtrigger/OWNERS -mdooley@google.com diff --git a/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java index be0c7daebb57..e62a89b17927 100644 --- a/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java +++ b/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java @@ -19,6 +19,7 @@ package com.android.internal.protolog; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.contains; import static org.mockito.ArgumentMatchers.endsWith; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.times; @@ -157,13 +158,15 @@ public class ProtoLogCommandHandlerTest { cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "enable", "MY_GROUP" }); - Mockito.verify(mProtoLogConfigurationService).enableProtoLogToLogcat("MY_GROUP"); + Mockito.verify(mProtoLogConfigurationService) + .enableProtoLogToLogcat(Mockito.any(), eq("MY_GROUP")); cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "enable", "MY_GROUP", "MY_OTHER_GROUP" }); Mockito.verify(mProtoLogConfigurationService) - .enableProtoLogToLogcat("MY_GROUP", "MY_OTHER_GROUP"); + .enableProtoLogToLogcat(Mockito.any(), + eq("MY_GROUP"), eq("MY_OTHER_GROUP")); } @Test @@ -173,13 +176,15 @@ public class ProtoLogCommandHandlerTest { cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "disable", "MY_GROUP" }); - Mockito.verify(mProtoLogConfigurationService).disableProtoLogToLogcat("MY_GROUP"); + Mockito.verify(mProtoLogConfigurationService) + .disableProtoLogToLogcat(Mockito.any(), eq("MY_GROUP")); cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "disable", "MY_GROUP", "MY_OTHER_GROUP" }); Mockito.verify(mProtoLogConfigurationService) - .disableProtoLogToLogcat("MY_GROUP", "MY_OTHER_GROUP"); + .disableProtoLogToLogcat(Mockito.any(), + eq("MY_GROUP"), eq("MY_OTHER_GROUP")); } @Test diff --git a/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java index 3be725101252..1f3f91ebf557 100644 --- a/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java +++ b/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java @@ -62,6 +62,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.PrintWriter; import java.util.List; /** @@ -234,7 +235,7 @@ public class ProtoLogConfigurationServiceTest { service.registerClient(mMockClient, args); Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse(); - service.enableProtoLogToLogcat(TEST_GROUP); + service.enableProtoLogToLogcat(Mockito.mock(PrintWriter.class), TEST_GROUP); Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue(); Mockito.verify(mMockClient).toggleLogcat(eq(true), @@ -251,7 +252,7 @@ public class ProtoLogConfigurationServiceTest { service.registerClient(mMockClient, args); Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue(); - service.disableProtoLogToLogcat(TEST_GROUP); + service.disableProtoLogToLogcat(Mockito.mock(PrintWriter.class), TEST_GROUP); Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse(); Mockito.verify(mMockClient).toggleLogcat(eq(false), @@ -269,7 +270,7 @@ public class ProtoLogConfigurationServiceTest { service.registerClient(mMockClient, args); Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse(); - service.enableProtoLogToLogcat(OTHER_TEST_GROUP); + service.enableProtoLogToLogcat(Mockito.mock(PrintWriter.class), OTHER_TEST_GROUP); Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse(); Mockito.verify(mMockClient, never()).toggleLogcat(anyBoolean(), any()); @@ -280,7 +281,7 @@ public class ProtoLogConfigurationServiceTest { final ProtoLogConfigurationService service = new ProtoLogConfigurationServiceImpl(); Truth.assertThat(service.getGroups()).asList().doesNotContain(TEST_GROUP); - service.enableProtoLogToLogcat(TEST_GROUP); + service.enableProtoLogToLogcat(Mockito.mock(PrintWriter.class), TEST_GROUP); Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue(); final RegisterClientArgs args = new RegisterClientArgs(); diff --git a/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java b/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java index 51d57f0a0de9..f5d4b0c5e345 100644 --- a/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java +++ b/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java @@ -24,15 +24,20 @@ import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.content.Context; +import android.hardware.usb.IUsbManagerInternal; import android.hardware.usb.IUsbOperationInternal; import android.hardware.usb.flags.Flags; import android.hardware.usb.UsbPort; @@ -70,7 +75,9 @@ public class UsbServiceTest { @Mock private IUsbOperationInternal mCallback; - private static final String TEST_PORT_ID = "123"; + private static final String TEST_PORT_ID = "1"; + + private static final String TEST_PORT_ID_2 = "2"; private static final int TEST_TRANSACTION_ID = 1; @@ -84,7 +91,7 @@ public class UsbServiceTest { private UsbService mUsbService; - private UsbManagerInternal mUsbManagerInternal; + private IUsbManagerInternal mIUsbManagerInternal; @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -101,9 +108,9 @@ public class UsbServiceTest { mUsbService = new UsbService(mContext, mUsbPortManager, mUsbAlsaManager, mUserManager, mUsbSettingsManager); - mUsbManagerInternal = LocalServices.getService(UsbManagerInternal.class); - assertWithMessage("LocalServices.getService(UsbManagerInternal.class)") - .that(mUsbManagerInternal).isNotNull(); + mIUsbManagerInternal = LocalServices.getService(IUsbManagerInternal.class); + assertWithMessage("LocalServices.getService(IUsbManagerInternal.class)") + .that(mIUsbManagerInternal).isNotNull(); } private void assertToggleUsbSuccessfully(int requester, boolean enable, @@ -255,30 +262,42 @@ public class UsbServiceTest { assertToggleUsbSuccessfully(TEST_INTERNAL_REQUESTER_REASON_1, true, false); } - /** - * Verify USB Manager internal calls mPortManager to get UsbPorts - */ @Test - public void usbManagerInternal_getPorts_callsPortManager() { - when(mUsbPortManager.getPorts()).thenReturn(new UsbPort[] {}); - - UsbPort[] ports = mUsbManagerInternal.getPorts(); - - verify(mUsbPortManager).getPorts(); - assertEquals(ports.length, 0); + public void usbManagerInternal_enableUsbDataSignal_successfullyEnabled() { + assertTrue(runInternalUsbDataSignalTest(true, true, true)); } @Test - public void usbManagerInternal_enableUsbData_successfullyEnable() { - boolean desiredEnableState = true; + public void usbManagerInternal_enableUsbDataSignal_successfullyDisabled() { + assertTrue(runInternalUsbDataSignalTest(false, true, true)); + } - assertTrue(mUsbManagerInternal.enableUsbData(TEST_PORT_ID, desiredEnableState, - TEST_TRANSACTION_ID, mCallback, TEST_INTERNAL_REQUESTER_REASON_1)); + @Test + public void usbManagerInternal_enableUsbDataSignal_returnsFalseIfOnePortFails() { + assertFalse(runInternalUsbDataSignalTest(true, true, false)); + } - verify(mUsbPortManager).enableUsbData(TEST_PORT_ID, - desiredEnableState, TEST_TRANSACTION_ID, mCallback, null); - verifyZeroInteractions(mCallback); - clearInvocations(mUsbPortManager); - clearInvocations(mCallback); + private boolean runInternalUsbDataSignalTest(boolean desiredEnableState, boolean portOneSuccess, + boolean portTwoSuccess) { + UsbPort port = mock(UsbPort.class); + UsbPort port2 = mock(UsbPort.class); + when(port.getId()).thenReturn(TEST_PORT_ID); + when(port2.getId()).thenReturn(TEST_PORT_ID_2); + when(mUsbPortManager.getPorts()).thenReturn(new UsbPort[] { port, port2 }); + when(mUsbPortManager.enableUsbData(eq(TEST_PORT_ID), + eq(desiredEnableState), anyInt(), any(IUsbOperationInternal.class), isNull())) + .thenReturn(portOneSuccess); + when(mUsbPortManager.enableUsbData(eq(TEST_PORT_ID_2), + eq(desiredEnableState), anyInt(), any(IUsbOperationInternal.class), isNull())) + .thenReturn(portTwoSuccess); + try { + boolean result = mIUsbManagerInternal.enableUsbDataSignal(desiredEnableState, + TEST_INTERNAL_REQUESTER_REASON_1); + clearInvocations(mUsbPortManager); + return result; + } catch(RemoteException e) { + fail("RemoteException thrown when calling enableUsbDataSignal"); + return false; + } } } diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java index 1273826c8ef8..649241aaaa8c 100644 --- a/tests/testables/src/android/testing/TestableLooper.java +++ b/tests/testables/src/android/testing/TestableLooper.java @@ -75,16 +75,7 @@ public class TestableLooper { * Baklava introduces new {@link TestLooperManager} APIs that we can use instead of reflection. */ private static boolean isAtLeastBaklava() { - Method[] methods = TestLooperManager.class.getMethods(); - for (Method method : methods) { - if (method.getName().equals("peekWhen")) { - return true; - } - } - return false; - // TODO(shayba): delete the above, uncomment the below. - // SDK_INT has not yet ramped to Baklava in all 25Q2 builds. - // return Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA; + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA; } static { @@ -273,7 +264,7 @@ public class TestableLooper { messages.add(message); } - // Repost all Messages back to the queuewith a new time. + // Repost all Messages back to the queue with a new time. while (true) { Message message = messages.poll(); if (message == null) { diff --git a/tests/utils/testutils/java/android/os/test/TestLooper.java b/tests/utils/testutils/java/android/os/test/TestLooper.java index 4d379e45a81a..bb54a26036db 100644 --- a/tests/utils/testutils/java/android/os/test/TestLooper.java +++ b/tests/utils/testutils/java/android/os/test/TestLooper.java @@ -68,16 +68,7 @@ public class TestLooper { * Baklava introduces new {@link TestLooperManager} APIs that we can use instead of reflection. */ private static boolean isAtLeastBaklava() { - Method[] methods = TestLooperManager.class.getMethods(); - for (Method method : methods) { - if (method.getName().equals("peekWhen")) { - return true; - } - } - return false; - // TODO(shayba): delete the above, uncomment the below. - // SDK_INT has not yet ramped to Baklava in all 25Q2 builds. - // return Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA; + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA; } static { diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp index 661ed07a5669..5ad1d1dce324 100644 --- a/tests/vcn/Android.bp +++ b/tests/vcn/Android.bp @@ -17,8 +17,9 @@ android_test { // For access hidden connectivity methods in tests defaults: ["framework-connectivity-test-defaults"], - // TODO: b/374174952 Use 36 after Android B finalization - min_sdk_version: "35", + // Tethering module is released in R so this test needs to be installable + // on R + min_sdk_version: "30", srcs: [ "java/**/*.java", diff --git a/tests/vcn/AndroidManifest.xml b/tests/vcn/AndroidManifest.xml index 08effbd1f7cf..6e8b4ac48816 100644 --- a/tests/vcn/AndroidManifest.xml +++ b/tests/vcn/AndroidManifest.xml @@ -17,7 +17,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.frameworks.tests.vcn"> <!-- TODO: b/374174952 Use 36 after Android B finalization --> - <uses-sdk android:minSdkVersion="35" android:targetSdkVersion="35" /> + <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="35" /> <application> <uses-library android:name="android.test.runner" /> diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index a97f9a837bab..3cccbc419425 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -41,6 +41,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -1088,6 +1089,10 @@ public class VcnManagementServiceTest { @Test public void testGetRestrictedTransportsFromCarrierConfig() { + assumeTrue( + "Configuring restricted transport types is only allowed on a debuggable build", + Build.isDebuggable()); + final Set<Integer> restrictedTransports = new ArraySet<>(); restrictedTransports.add(TRANSPORT_CELLULAR); restrictedTransports.add(TRANSPORT_WIFI); @@ -1109,6 +1114,10 @@ public class VcnManagementServiceTest { @Test public void testGetRestrictedTransportsFromCarrierConfig_noRestrictPolicyConfigured() { + assumeTrue( + "Configuring restricted transport types is only allowed on a debuggable build", + Build.isDebuggable()); + final Set<Integer> restrictedTransports = Collections.singleton(TRANSPORT_WIFI); final PersistableBundleWrapper carrierConfig = @@ -1123,6 +1132,10 @@ public class VcnManagementServiceTest { @Test public void testGetRestrictedTransportsFromCarrierConfig_noCarrierConfig() { + assumeTrue( + "Configuring restricted transport types is only allowed on a debuggable build", + Build.isDebuggable()); + final Set<Integer> restrictedTransports = Collections.singleton(TRANSPORT_WIFI); final TelephonySubscriptionSnapshot lastSnapshot = @@ -1134,6 +1147,10 @@ public class VcnManagementServiceTest { @Test public void testGetRestrictedTransportsFromCarrierConfigAndVcnConfig() { + assumeTrue( + "Configuring restricted transport types is only allowed on a debuggable build", + Build.isDebuggable()); + // Configure restricted transport in CarrierConfig final Set<Integer> restrictedTransportInCarrierConfig = Collections.singleton(TRANSPORT_WIFI); |