Merge "Merge "Always clone golden files before editing them." into qt-dev am: 8be3ae5838 am: d6db09d156" into qt-r1-dev-plus-aosp
am: 5455f6d3ba
Change-Id: I92440bdf578653d34871b4e0ac2fcac3709cb444
diff --git a/.gitignore b/.gitignore
index 33bfd97..ff66172 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,6 @@
*.iml
*.class
*.sw*
+
+# Jars added by Idea's "Konfigure kotlin in project" action
+**/lib/kotlin-*.jar
\ No newline at end of file
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index b5af652..08f52f1 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1305,6 +1305,16 @@
android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
</activity>
+ <activity android:name=".security.ProtectedConfirmationTest"
+ android:label="@string/sec_protected_confirmation_test"
+ android:configChanges="keyboardHidden|orientation|screenSize" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_security" />
+ </activity>
+
<activity android:name=".security.ScreenLockBoundKeysTest"
android:label="@string/sec_lock_bound_key_test"
android:configChanges="keyboardHidden|orientation|screenSize" >
diff --git a/apps/CtsVerifier/res/layout/sec_protected_confirmation_main.xml b/apps/CtsVerifier/res/layout/sec_protected_confirmation_main.xml
new file mode 100644
index 0000000..ffa8d46
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/sec_protected_confirmation_main.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="10dip"
+ >
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/sec_protected_confirmation_tee_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="10dp"
+ android:orientation="horizontal"
+ android:layout_centerInParent="true"
+ android:gravity="center"
+ >
+
+ <Button android:id="@+id/sec_start_test_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/sec_protected_confirmation_tee_test"
+ />
+
+ <ImageView android:id="@+id/sec_protected_confirmation_tee_test_success"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fs_good"
+ />
+
+ </LinearLayout>
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/sec_protected_confirmation_strongbox_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="10dp"
+ android:orientation="horizontal"
+ android:layout_centerHorizontal="true"
+ android:layout_below="@id/sec_protected_confirmation_tee_layout"
+ android:gravity="center"
+ >
+
+ <Button android:id="@+id/sec_start_test_strongbox_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/sec_protected_confirmation_strongbox_test"
+ />
+
+ <ImageView android:id="@+id/sec_protected_confirmation_strongbox_test_success"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fs_good"
+ />
+
+ </LinearLayout>
+
+ <include android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ layout="@layout/pass_fail_buttons"
+ />
+
+</RelativeLayout>
+
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 4bf8b9f..4a3a08f 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -211,6 +211,23 @@
are unusable without an authentication.
</string>
+ <!-- Strings for protected confirmation test -->
+ <string name="sec_protected_confirmation_test">Android Protected Confirmation Test</string>
+ <string name="sec_protected_confirmation_test_info">
+ This test ensures that - if Android Protected Confirmation is supported by the device under
+ test - the user is able to see the confirmation message and confirm it. It also assures that
+ Keymaster signs a message with a confirmation key only if the message was previously
+ confirmed by the user.
+ </string>
+ <string name="sec_protected_confirmation_not_supported_title">Android Protected Confirmation not supported</string>
+ <string name="sec_protected_confirmation_not_supported_info">
+ Android Protected Confirmation is not implemented by this device. This is okay because this
+ is an optional feature. Set this test to passed and continue.
+ </string>
+ <string name="sec_protected_confirmation_message">This is a CtsVerifier test message!</string>
+ <string name="sec_protected_confirmation_tee_test">Start Tee Test</string>
+ <string name="sec_protected_confirmation_strongbox_test">Start Strongbox Test</string>
+
<!-- Strings for BluetoothActivity -->
<string name="bluetooth_test">Bluetooth Test</string>
<string name="bluetooth_test_info">
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/ProtectedConfirmationTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/security/ProtectedConfirmationTest.java
new file mode 100644
index 0000000..62c7772
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/ProtectedConfirmationTest.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.security;
+
+import android.content.pm.PackageManager;
+import android.icu.util.Calendar;
+import android.os.Bundle;
+import android.security.ConfirmationAlreadyPresentingException;
+import android.security.ConfirmationCallback;
+import android.security.ConfirmationNotAvailableException;
+import android.security.ConfirmationPrompt;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.Toast;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.UnrecoverableEntryException;
+import java.security.cert.CertificateException;
+import java.util.Date;
+
+public class ProtectedConfirmationTest extends PassFailButtons.Activity {
+
+ /**
+ * Alias for our key in the Android Key Store.
+ */
+ private static final String KEY_NAME = "my_confirmation_key";
+ private boolean teeTestSuccess = false;
+ private boolean strongboxTestSuccess = false;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.sec_protected_confirmation_main);
+ setPassFailButtonClickListeners();
+
+ boolean protectedConfirmationSupported =
+ ConfirmationPrompt.isSupported(getApplicationContext());
+ if (protectedConfirmationSupported) {
+ setInfoResources(R.string.sec_protected_confirmation_test,
+ R.string.sec_protected_confirmation_test_info, -1);
+ getPassButton().setEnabled(false);
+ } else {
+ setInfoResources(R.string.sec_protected_confirmation_not_supported_title,
+ R.string.sec_protected_confirmation_not_supported_info, -1);
+ getPassButton().setEnabled(true);
+ return;
+ }
+ boolean hasStrongbox = this.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE);
+
+ findViewById(R.id.sec_protected_confirmation_tee_test_success)
+ .setVisibility(View.INVISIBLE);
+ findViewById(R.id.sec_protected_confirmation_strongbox_test_success)
+ .setVisibility(View.INVISIBLE);
+ Button startTestButton = (Button) findViewById(R.id.sec_start_test_button);
+ startTestButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showToast("Test running...");
+ v.post(new Runnable() {
+ @Override
+ public void run() {
+ createKey(false /* useStrongbox */);
+ if (trySign(getString(R.string.sec_protected_confirmation_message)
+ .getBytes())) {
+ showToast("Test failed. Key could sign without confirmation.");
+ } else {
+ showConfirmationPrompt(
+ getString(R.string.sec_protected_confirmation_message),
+ false /* useStrongbox */);
+ }
+ }
+ });
+ }
+
+ });
+
+ Button startStrongboxTestButton =
+ (Button) findViewById(R.id.sec_start_test_strongbox_button);
+ if (hasStrongbox) {
+ startStrongboxTestButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showToast("Test running...");
+ v.post(new Runnable() {
+ @Override
+ public void run() {
+ createKey(true /* useStrongbox */);
+ if (trySign(getString(R.string.sec_protected_confirmation_message)
+ .getBytes())) {
+ showToast("Test failed. Key could sign without confirmation.");
+ } else {
+ showConfirmationPrompt(
+ getString(R.string.sec_protected_confirmation_message),
+ true /* useStrongbox */);
+ }
+ }
+ });
+ }
+
+ });
+ } else {
+ startStrongboxTestButton.setVisibility(View.GONE);
+ // since strongbox is available we mark the strongbox test as passed so that the tee
+ // test alone can make the test pass.
+ strongboxTestSuccess = true;
+ }
+
+ }
+
+ /**
+ * Creates an asymmetric signing key in AndroidKeyStore which can only be used for signing
+ * user confirmed messages.
+ */
+ private void createKey(boolean useStrongbox) {
+ Calendar calendar = Calendar.getInstance();
+ Date validityStart = calendar.getTime();
+ calendar.add(Calendar.YEAR, 1);
+ Date validityEnd = calendar.getTime();
+ try {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance(
+ KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
+ KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
+ KEY_NAME,
+ KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY);
+ builder.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512);
+ builder.setAttestationChallenge("CtsVerifierTest".getBytes());
+ builder.setUserConfirmationRequired(true);
+ builder.setIsStrongBoxBacked(useStrongbox);
+ builder.setKeyValidityStart(validityStart);
+ builder.setKeyValidityEnd(validityEnd);
+ kpg.initialize(builder.build());
+ kpg.generateKeyPair();
+ } catch (NoSuchAlgorithmException | NoSuchProviderException |
+ InvalidAlgorithmParameterException e) {
+ throw new RuntimeException("Failed to create confirmation key", e);
+ }
+ }
+
+ private boolean trySign(byte[] dataThatWasConfirmed) {
+ try {
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+ KeyStore.Entry key = keyStore.getEntry(KEY_NAME, null);
+ Signature s = Signature.getInstance("SHA256withECDSA");
+ s.initSign(((KeyStore.PrivateKeyEntry) key).getPrivateKey());
+ s.update(dataThatWasConfirmed);
+ s.sign();
+ } catch (CertificateException | KeyStoreException | IOException | NoSuchAlgorithmException |
+ UnrecoverableEntryException | InvalidKeyException e) {
+ throw new RuntimeException("Failed to load confirmation key", e);
+ } catch (SignatureException e) {
+ return false;
+ }
+ return true;
+ }
+
+ private void showConfirmationPrompt(String confirmationMessage, boolean useStrongbox) {
+ ConfirmationPrompt.Builder builder = new ConfirmationPrompt.Builder(this);
+ builder.setPromptText(confirmationMessage);
+ builder.setExtraData(new byte[]{0x1, 0x02, 0x03});
+ ConfirmationPrompt prompt = builder.build();
+ try {
+ prompt.presentPrompt(getMainExecutor(),
+ new ConfirmationCallback() {
+ @Override
+ public void onConfirmed(byte[] dataThatWasConfirmed) {
+ super.onConfirmed(dataThatWasConfirmed);
+ if (trySign(dataThatWasConfirmed)) {
+ markTestSuccess(useStrongbox);
+ } else {
+ showToast("Failed to sign confirmed message");
+ }
+ }
+
+ @Override
+ public void onDismissed() {
+ super.onDismissed();
+ showToast("User dismissed the dialog.");
+ }
+
+ @Override
+ public void onCanceled() {
+ super.onCanceled();
+ showToast("Confirmation dialog was canceled.");
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ super.onError(e);
+ throw new RuntimeException("Confirmation Callback encountered an error",
+ e);
+ }
+ });
+ } catch (ConfirmationAlreadyPresentingException | ConfirmationNotAvailableException e) {
+ throw new RuntimeException("Error trying to present the confirmation prompt", e);
+ }
+ }
+
+ private void showToast(String message) {
+ Toast.makeText(this, message, Toast.LENGTH_LONG)
+ .show();
+ }
+
+ private void markTestSuccess(boolean strongbox) {
+ if (strongbox) {
+ if (!strongboxTestSuccess) {
+ findViewById(R.id.sec_protected_confirmation_strongbox_test_success)
+ .setVisibility(View.VISIBLE);
+ }
+ strongboxTestSuccess = true;
+ } else {
+ if (!teeTestSuccess) {
+ findViewById(R.id.sec_protected_confirmation_tee_test_success)
+ .setVisibility(View.VISIBLE);
+ }
+ teeTestSuccess = true;
+ }
+ if (strongboxTestSuccess && teeTestSuccess) {
+ showToast("Test passed.");
+ getPassButton().setEnabled(true);
+ }
+ }
+}
+
diff --git a/apps/VpnApp/latest/Android.mk b/apps/VpnApp/latest/Android.mk
index 0431bef..02da681 100755
--- a/apps/VpnApp/latest/Android.mk
+++ b/apps/VpnApp/latest/Android.mk
@@ -30,6 +30,6 @@
LOCAL_PRIVATE_PLATFORM_APIS := true
# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := arcts cts vts general-tests
include $(BUILD_CTS_PACKAGE)
diff --git a/common/device-side/test-app/Android.bp b/common/device-side/test-app/Android.bp
index 14e711a..74f549d 100644
--- a/common/device-side/test-app/Android.bp
+++ b/common/device-side/test-app/Android.bp
@@ -30,7 +30,7 @@
"compatibility-common-util-devicesidelib",
"compatibility-device-info-tests",
"compatibility-device-info",
- "compatibility-device-util-tests",
+ "compatibility-device-util-tests-axt",
"compatibility-device-util-axt",
],
diff --git a/common/device-side/util-axt/Android.bp b/common/device-side/util-axt/Android.bp
index fe2b1b7..169184a 100644
--- a/common/device-side/util-axt/Android.bp
+++ b/common/device-side/util-axt/Android.bp
@@ -12,14 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// temporary compatibility-device-util variant that brings in androidx.test transitively, instead
-// of android.support.test target. Will be removed after androidx.test CTS conversion is complete.
java_library_static {
name: "compatibility-device-util-axt",
sdk_version: "test_current",
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"src/**/*.aidl",
],
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/ExceptionUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/ExceptionUtils.java
new file mode 100644
index 0000000..0899966
--- /dev/null
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/ExceptionUtils.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.function.Function;
+
+/**
+ * Utilities to deal with exceptions
+ */
+public class ExceptionUtils {
+ private ExceptionUtils() {}
+
+ /**
+ * Rethrow a given exception, optionally wrapping it in a {@link RuntimeException}
+ */
+ public static RuntimeException propagate(@NonNull Throwable t) {
+ if (t == null) {
+ throw new NullPointerException();
+ }
+ propagateIfInstanceOf(t, Error.class);
+ propagateIfInstanceOf(t, RuntimeException.class);
+ throw new RuntimeException(t);
+ }
+
+ /**
+ * Rethrow a given exception, if it's of type {@code E}
+ */
+ public static <E extends Throwable> void propagateIfInstanceOf(
+ @Nullable Throwable t, Class<E> c) throws E {
+ if (t != null && c.isInstance(t)) {
+ throw c.cast(t);
+ }
+ }
+
+ /**
+ * Gets the root {@link Throwable#getCause() cause} of {@code t}
+ */
+ public static @NonNull Throwable getRootCause(@NonNull Throwable t) {
+ while (t.getCause() != null) t = t.getCause();
+ return t;
+ }
+
+ /**
+ * Appends {@code cause} at the end of the causal chain of {@code t}
+ *
+ * @return {@code t} for convenience
+ */
+ public static @NonNull Throwable appendCause(@NonNull Throwable t, @Nullable Throwable cause) {
+ if (cause != null) {
+ getRootCause(t).initCause(cause);
+ }
+ return t;
+ }
+
+ /**
+ * Runs the given {@code action}, and if any exceptions are thrown in the process, applies
+ * given {@code exceptionTransformer}, rethrowing the result.
+ */
+ public static <R> R wrappingExceptions(
+ Function<Throwable, Throwable> exceptionTransformer, ThrowingSupplier<R> action) {
+ try {
+ return action.get();
+ } catch (Throwable t) {
+ Throwable transformed;
+ try {
+ transformed = exceptionTransformer.apply(t);
+ } catch (Throwable t2) {
+ transformed = new RuntimeException("Failed to apply exception transformation",
+ ExceptionUtils.appendCause(t2, t));
+ }
+ throw ExceptionUtils.propagate(transformed);
+ }
+ }
+
+ /**
+ * @see #wrappingExceptions(Function, ThrowingSupplier)
+ */
+ public static void wrappingExceptions(
+ Function<Throwable, Throwable> exceptionTransformer, ThrowingRunnable action) {
+ wrappingExceptions(exceptionTransformer, () -> {
+ action.run();
+ return null;
+ });
+ }
+}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/FutureResultActivity.kt b/common/device-side/util-axt/src/com/android/compatibility/common/util/FutureResultActivity.kt
new file mode 100644
index 0000000..49397a5
--- /dev/null
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/FutureResultActivity.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 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.compatibility.common.util
+
+import android.app.Activity
+import android.content.Intent
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * An [Activity] that exposes a special [startActivityForResult],
+ * returning future resultCode as a [CompletableFuture]
+ */
+class FutureResultActivity : Activity() {
+
+ companion object {
+
+ /** requestCode -> Future<resultCode> */
+ private val requests = ConcurrentHashMap<Int, CompletableFuture<Int>>()
+ private val nextRequestCode = AtomicInteger(0)
+
+ fun doAndAwaitStart(act: () -> Unit): CompletableFuture<Int> {
+ val requestCode = nextRequestCode.get()
+ act()
+ PollingCheck.waitFor(60_000) {
+ nextRequestCode.get() >= requestCode + 1
+ }
+ return requests[requestCode]!!
+ }
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ requests[requestCode]!!.complete(resultCode)
+ }
+
+ fun startActivityForResult(intent: Intent): CompletableFuture<Int> {
+ val requestCode = nextRequestCode.getAndIncrement()
+ val future = CompletableFuture<Int>()
+ requests[requestCode] = future
+ startActivityForResult(intent, requestCode)
+ return future
+ }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ThrowingRunnable.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/ThrowingSupplier.java
similarity index 65%
rename from common/device-side/util/src/com/android/compatibility/common/util/ThrowingRunnable.java
rename to common/device-side/util-axt/src/com/android/compatibility/common/util/ThrowingSupplier.java
index 0588cff..f1e0006 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/ThrowingRunnable.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/ThrowingSupplier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,12 +15,16 @@
*/
package com.android.compatibility.common.util;
+import java.util.function.Supplier;
+
/**
- * Similar to {@link Runnable} but has {@code throws Exception}.
+ * Similar to {@link Supplier} but has {@code throws Exception}.
+ *
+ * @param <T> type of the value produced
*/
-public interface ThrowingRunnable {
+public interface ThrowingSupplier<T> {
/**
- * Similar to {@link Runnable#run} but has {@code throws Exception}.
+ * Similar to {@link Supplier#get} but has {@code throws Exception}.
*/
- void run() throws Exception;
+ T get() throws Exception;
}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiDumpUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiDumpUtils.java
new file mode 100644
index 0000000..a36c1eb
--- /dev/null
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiDumpUtils.java
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import static android.text.TextUtils.isEmpty;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import android.view.accessibility.AccessibilityWindowInfo;
+
+import androidx.test.InstrumentationRegistry;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.ToIntFunction;
+import java.util.stream.Stream;
+
+/**
+ * Utilities to dump the view hierrarchy as an indented tree
+ *
+ * @see #dumpNodes(AccessibilityNodeInfo, StringBuilder)
+ * @see #wrapWithUiDump(Throwable)
+ */
+@SuppressWarnings({"PointlessBitwiseExpression"})
+public class UiDumpUtils {
+ private UiDumpUtils() {}
+
+ private static final boolean CONCISE = false;
+ private static final boolean SHOW_ACTIONS = false;
+ private static final boolean IGNORE_INVISIBLE = false;
+
+ private static final int IGNORED_ACTIONS = 0
+ | AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS
+ | AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS
+ | AccessibilityNodeInfo.ACTION_FOCUS
+ | AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+ | AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+ | AccessibilityNodeInfo.ACTION_SELECT
+ | AccessibilityNodeInfo.ACTION_SET_SELECTION
+ | AccessibilityNodeInfo.ACTION_CLEAR_SELECTION
+ | AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT
+ | AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT
+ ;
+
+ private static final int SPECIALLY_HANDLED_ACTIONS = 0
+ | AccessibilityNodeInfo.ACTION_CLICK
+ | AccessibilityNodeInfo.ACTION_LONG_CLICK
+ | AccessibilityNodeInfo.ACTION_EXPAND
+ | AccessibilityNodeInfo.ACTION_COLLAPSE
+ | AccessibilityNodeInfo.ACTION_FOCUS
+ | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS
+ | AccessibilityNodeInfo.ACTION_SCROLL_FORWARD
+ | AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD
+ | AccessibilityNodeInfo.ACTION_SET_TEXT
+ ;
+
+ /** name -> typical_value */
+ private static Map<String, Boolean> sNodeFlags = new LinkedHashMap<>();
+ static {
+ sNodeFlags.put("focused", false);
+ sNodeFlags.put("selected", false);
+ sNodeFlags.put("contextClickable", false);
+ sNodeFlags.put("dismissable", false);
+ sNodeFlags.put("enabled", true);
+ sNodeFlags.put("password", false);
+ sNodeFlags.put("visibleToUser", true);
+ sNodeFlags.put("contentInvalid", false);
+ sNodeFlags.put("heading", false);
+ sNodeFlags.put("showingHintText", false);
+
+ // Less important flags below
+ // Too spammy to report all, but can uncomment what's necessary
+
+// sNodeFlags.put("focusable", true);
+// sNodeFlags.put("accessibilityFocused", false);
+// sNodeFlags.put("screenReaderFocusable", true);
+// sNodeFlags.put("clickable", false);
+// sNodeFlags.put("longClickable", false);
+// sNodeFlags.put("checkable", false);
+// sNodeFlags.put("checked", false);
+// sNodeFlags.put("editable", false);
+// sNodeFlags.put("scrollable", false);
+// sNodeFlags.put("importantForAccessibility", true);
+// sNodeFlags.put("multiLine", false);
+ }
+
+ /** action -> pictogram */
+ private static Map<AccessibilityAction, String> sNodeActions = new LinkedHashMap<>();
+ static {
+ sNodeActions.put(AccessibilityAction.ACTION_PASTE, "\uD83D\uDCCB");
+ sNodeActions.put(AccessibilityAction.ACTION_CUT, "✂");
+ sNodeActions.put(AccessibilityAction.ACTION_COPY, "⎘");
+ sNodeActions.put(AccessibilityAction.ACTION_SCROLL_BACKWARD, "←");
+ sNodeActions.put(AccessibilityAction.ACTION_SCROLL_LEFT, "←");
+ sNodeActions.put(AccessibilityAction.ACTION_SCROLL_FORWARD, "→");
+ sNodeActions.put(AccessibilityAction.ACTION_SCROLL_RIGHT, "→");
+ sNodeActions.put(AccessibilityAction.ACTION_SCROLL_DOWN, "↓");
+ sNodeActions.put(AccessibilityAction.ACTION_SCROLL_UP, "↑");
+ }
+
+ private static Instrumentation sInstrumentation = InstrumentationRegistry.getInstrumentation();
+ private static UiAutomation sUiAutomation = sInstrumentation.getUiAutomation();
+
+ private static int sScreenArea;
+ static {
+ Point displaySize = new Point();
+ sInstrumentation.getContext()
+ .getSystemService(WindowManager.class)
+ .getDefaultDisplay()
+ .getRealSize(displaySize);
+ sScreenArea = displaySize.x * displaySize.y;
+ }
+
+
+ /**
+ * Wraps the given exception, with one containing UI hierrarchy {@link #dumpNodes dump}
+ * in its message.
+ *
+ * <p>
+ * Can be used together with {@link ExceptionUtils#wrappingExceptions}, e.g:
+ * {@code
+ * ExceptionUtils.wrappingExceptions(UiDumpUtils::wrapWithUiDump, () -> {
+ * // UI-testing code
+ * });
+ * }
+ */
+ public static UiDumpWrapperException wrapWithUiDump(Throwable cause) {
+ return (cause instanceof UiDumpWrapperException)
+ ? (UiDumpWrapperException) cause
+ : new UiDumpWrapperException(cause);
+ }
+
+ /**
+ * Dumps UI hierarchy with a given {@code root} as indented text tree into {@code out}.
+ */
+ public static void dumpNodes(AccessibilityNodeInfo root, StringBuilder out) {
+ if (root == null) {
+ appendNode(out, root);
+ return;
+ }
+
+ out.append("--- ").append(root.getPackageName()).append(" ---\n|");
+
+ recursively(root, AccessibilityNodeInfo::getChildCount, AccessibilityNodeInfo::getChild,
+ node -> {
+ if (appendNode(out, node)) {
+ out.append("\n|");
+ }
+ },
+ action -> node -> {
+ out.append(" ");
+ action.accept(node);
+ });
+ }
+
+ private static <T> void recursively(T node,
+ ToIntFunction<T> getChildCount, BiFunction<T, Integer, T> getChildAt,
+ Consumer<T> action, Function<Consumer<T>, Consumer<T>> actionChange) {
+ if (node == null) return;
+
+ action.accept(node);
+ Consumer<T> childAction = actionChange.apply(action);
+
+ int size = getChildCount.applyAsInt(node);
+ for (int i = 0; i < size; i++) {
+ recursively(getChildAt.apply(node, i),
+ getChildCount, getChildAt, childAction, actionChange);
+ }
+ }
+
+ private static StringBuilder appendWindow(AccessibilityWindowInfo window, StringBuilder out) {
+ if (window == null) {
+ out.append("<null window>");
+ } else {
+ if (!isEmpty(window.getTitle())) {
+ out.append(window.getTitle());
+ if (CONCISE) return out;
+ out.append(" ");
+ }
+ out.append(valueToString(
+ AccessibilityWindowInfo.class, "TYPE_", window.getType())).append(" ");
+ if (CONCISE) return out;
+ appendArea(out, window::getBoundsInScreen);
+
+ Rect bounds = new Rect();
+ window.getBoundsInScreen(bounds);
+ out.append(bounds.width()).append("x").append(bounds.height()).append(" ");
+ if (window.isInPictureInPictureMode()) out.append("#PIP ");
+ }
+ return out;
+ }
+
+ private static void appendArea(StringBuilder out, Consumer<Rect> getBoundsInScreen) {
+ Rect rect = new Rect();
+ getBoundsInScreen.accept(rect);
+ out.append("size:");
+ out.append(toStringRounding((float) area(rect) * 100 / sScreenArea)).append("% ");
+ }
+
+ private static boolean appendNode(StringBuilder out, AccessibilityNodeInfo node) {
+ if (node == null) {
+ out.append("<null node>");
+ return true;
+ }
+
+ if (IGNORE_INVISIBLE && !node.isVisibleToUser()) return false;
+
+ boolean markedClickable = false;
+ boolean markedNonFocusable = false;
+
+ try {
+ if (node.isFocused() || node.isAccessibilityFocused()) {
+ out.append(">");
+ }
+
+ if ((node.getActions() & AccessibilityNodeInfo.ACTION_EXPAND) != 0) {
+ out.append("[+] ");
+ }
+ if ((node.getActions() & AccessibilityNodeInfo.ACTION_COLLAPSE) != 0) {
+ out.append("[-] ");
+ }
+
+ CharSequence txt = node.getText();
+ if (node.isCheckable()) {
+ out.append("[").append(node.isChecked() ? "X" : "_").append("] ");
+ } else if (node.isEditable()) {
+ if (txt == null) txt = "";
+ out.append("[");
+ appendTextWithCursor(out, node, txt);
+ out.append("] ");
+ } else if (node.isClickable()) {
+ markedClickable = true;
+ out.append("[");
+ } else if (!node.isImportantForAccessibility()) {
+ markedNonFocusable = true;
+ out.append("(");
+ }
+
+ if (appendNodeText(out, node)) return true;
+ } finally {
+ backspaceIf(' ', out);
+ if (markedClickable) {
+ out.append("]");
+ if (node.isLongClickable()) out.append("+");
+ out.append(" ");
+ }
+ if (markedNonFocusable) out.append(") ");
+
+ if (CONCISE) out.append(" ");
+
+ for (Map.Entry<String, Boolean> prop : sNodeFlags.entrySet()) {
+ boolean value = call(node, boolGetter(prop.getKey()));
+ if (value != prop.getValue()) {
+ out.append("#");
+ if (!value) out.append("not_");
+ out.append(prop.getKey()).append(" ");
+ }
+ }
+
+ if (SHOW_ACTIONS) {
+ LinkedHashSet<String> symbols = new LinkedHashSet<>();
+ for (AccessibilityAction accessibilityAction : node.getActionList()) {
+ String symbol = sNodeActions.get(accessibilityAction);
+ if (symbol != null) symbols.add(symbol);
+ }
+ merge(symbols, "←", "→", "↔");
+ merge(symbols, "↑", "↓", "↕");
+ symbols.forEach(out::append);
+ if (!symbols.isEmpty()) out.append(" ");
+
+ getActions(node)
+ .map(a -> "[" + actionToString(a) + "] ")
+ .forEach(out::append);
+ }
+
+ Bundle extras = node.getExtras();
+ for (String extra : extras.keySet()) {
+ if (extra.equals("AccessibilityNodeInfo.chromeRole")) continue;
+ if (extra.equals("AccessibilityNodeInfo.roleDescription")) continue;
+ String value = "" + extras.get(extra);
+ if (value.isEmpty()) continue;
+ out.append(extra).append(":").append(value).append(" ");
+ }
+ }
+ return true;
+ }
+
+ private static StringBuilder appendTextWithCursor(StringBuilder out, AccessibilityNodeInfo node,
+ CharSequence txt) {
+ out.append(txt);
+ insertAtEnd(out, txt.length() - 1 - node.getTextSelectionStart(), "ꕯ");
+ if (node.getTextSelectionEnd() != node.getTextSelectionStart()) {
+ insertAtEnd(out, txt.length() - 1 - node.getTextSelectionEnd(), "ꕯ");
+ }
+ return out;
+ }
+
+ private static boolean appendNodeText(StringBuilder out, AccessibilityNodeInfo node) {
+ CharSequence txt = node.getText();
+
+ Bundle extras = node.getExtras();
+ if (extras.containsKey("AccessibilityNodeInfo.roleDescription")) {
+ out.append("<").append(extras.getString("AccessibilityNodeInfo.chromeRole"))
+ .append("> ");
+ } else if (extras.containsKey("AccessibilityNodeInfo.chromeRole")) {
+ out.append("<").append(extras.getString("AccessibilityNodeInfo.chromeRole"))
+ .append("> ");
+ }
+
+ if (CONCISE) {
+ if (!isEmpty(node.getContentDescription())) {
+ out.append(escape(node.getContentDescription()));
+ return true;
+ }
+ if (!isEmpty(node.getPaneTitle())) {
+ out.append(escape(node.getPaneTitle()));
+ return true;
+ }
+ if (!isEmpty(txt) && !node.isEditable()) {
+ out.append('"');
+ if (node.getTextSelectionStart() > 0 || node.getTextSelectionEnd() > 0) {
+ appendTextWithCursor(out, node, txt);
+ } else {
+ out.append(escape(txt));
+ }
+ out.append('"');
+ return true;
+ }
+ if (!isEmpty(node.getViewIdResourceName())) {
+ out.append("@").append(fromLast("/", node.getViewIdResourceName()));
+ return true;
+ }
+ }
+
+ if (node.getParent() == null && node.getWindow() != null) {
+ appendWindow(node.getWindow(), out);
+ if (CONCISE) return true;
+ out.append(" ");
+ }
+
+ if (!extras.containsKey("AccessibilityNodeInfo.chromeRole")) {
+ out.append(fromLast(".", node.getClassName())).append(" ");
+ }
+ ifNotEmpty(node.getViewIdResourceName(),
+ s -> out.append("@").append(fromLast("/", s)).append(" "));
+ ifNotEmpty(node.getPaneTitle(), s -> out.append("## ").append(s).append(" "));
+ ifNotEmpty(txt, s -> out.append("\"").append(s).append("\" "));
+
+ ifNotEmpty(node.getContentDescription(), s -> out.append("//").append(s).append(" "));
+
+ appendArea(out, node::getBoundsInScreen);
+ return false;
+ }
+
+ private static <T> String valueToString(Class<?> clazz, String prefix, T value) {
+ String s = flagsToString(clazz, prefix, value, Objects::equals);
+ if (s.isEmpty()) s = "" + value;
+ return s;
+ }
+
+ private static <T> String flagsToString(Class<?> clazz, String prefix, T flags,
+ BiPredicate<T, T> test) {
+ return mkStr(sb -> {
+ consts(clazz, prefix)
+ .filter(f -> box(f.getType()).isInstance(flags))
+ .forEach(c -> {
+ try {
+ if (test.test(flags, read(null, c))) {
+ sb.append(c.getName().substring(prefix.length())).append("|");
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Error while dealing with " + c, e);
+ }
+ });
+ backspace(sb);
+ });
+ }
+
+ private static Class box(Class c) {
+ return c == int.class ? Integer.class : c;
+ }
+
+ private static Stream<Field> consts(Class<?> clazz, String prefix) {
+ return Arrays.stream(clazz.getDeclaredFields())
+ .filter(f -> isConst(f) && f.getName().startsWith(prefix));
+ }
+
+ private static boolean isConst(Field f) {
+ return Modifier.isStatic(f.getModifiers()) && Modifier.isFinal(f.getModifiers());
+ }
+
+ private static Character last(StringBuilder sb) {
+ return sb.length() == 0 ? null : sb.charAt(sb.length() - 1);
+ }
+
+ private static StringBuilder backspaceIf(char c, StringBuilder sb) {
+ if (Objects.equals(last(sb), c)) backspace(sb);
+ return sb;
+ }
+
+ private static StringBuilder backspace(StringBuilder sb) {
+ if (sb.length() != 0) {
+ sb.deleteCharAt(sb.length() - 1);
+ }
+ return sb;
+ }
+
+ private static String toStringRounding(float f) {
+ return f >= 5.0 ? "" + (int) f : String.format("%.1f", f);
+ }
+
+ private static int area(Rect r) {
+ return Math.abs((r.right - r.left) * (r.bottom - r.top));
+ }
+
+ private static String escape(CharSequence s) {
+ return mkStr(out -> {
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (c < 127 || c == 0xa0 || c >= 0x2000 && c < 0x2070) {
+ out.append(c);
+ } else {
+ out.append("\\u").append(Integer.toHexString(c));
+ }
+ }
+ });
+ }
+
+ private static Stream<AccessibilityAction> getActions(
+ AccessibilityNodeInfo node) {
+ if (node == null) return Stream.empty();
+ return node.getActionList().stream()
+ .filter(a -> !AccessibilityAction.ACTION_SHOW_ON_SCREEN.equals(a)
+ && (a.getId()
+ & ~IGNORED_ACTIONS
+ & ~SPECIALLY_HANDLED_ACTIONS
+ ) != 0);
+ }
+
+ private static String actionToString(AccessibilityAction a) {
+ if (!isEmpty(a.getLabel())) return a.getLabel().toString();
+ return valueToString(AccessibilityAction.class, "ACTION_", a);
+ }
+
+ private static void merge(Set<String> symbols, String a, String b, String ab) {
+ if (symbols.contains(a) && symbols.contains(b)) {
+ symbols.add(ab);
+ symbols.remove(a);
+ symbols.remove(b);
+ }
+ }
+
+ private static String fromLast(String substr, CharSequence whole) {
+ String wholeStr = whole.toString();
+ int idx = wholeStr.lastIndexOf(substr);
+ if (idx < 0) return wholeStr;
+ return wholeStr.substring(idx + substr.length());
+ }
+
+ private static String boolGetter(String propName) {
+ return "is" + Character.toUpperCase(propName.charAt(0)) + propName.substring(1);
+ }
+
+ private static <T> T read(Object o, Field f) {
+ try {
+ f.setAccessible(true);
+ return (T) f.get(o);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static <T> T call(Object o, String methodName, Object... args) {
+ Class clazz = o instanceof Class ? (Class) o : o.getClass();
+ try {
+ Method method = clazz.getDeclaredMethod(methodName, mapToTypes(args));
+ method.setAccessible(true);
+ //noinspection unchecked
+ return (T) method.invoke(o, args);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(
+ newlineSeparated(Arrays.asList(clazz.getDeclaredMethods())), e);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static Class[] mapToTypes(Object[] args) {
+ return Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);
+ }
+
+ private static void ifNotEmpty(CharSequence t, Consumer<CharSequence> f) {
+ if (!isEmpty(t)) {
+ f.accept(t);
+ }
+ }
+
+ private static StringBuilder insertAtEnd(StringBuilder sb, int pos, String s) {
+ return sb.insert(sb.length() - 1 - pos, s);
+ }
+
+ private static <T, R> R fold(List<T> l, R init, BiFunction<R, T, R> combine) {
+ R result = init;
+ for (T t : l) {
+ result = combine.apply(result, t);
+ }
+ return result;
+ }
+
+ private static <T> String toString(List<T> l, String sep, Function<T, String> elemToStr) {
+ return fold(l, "", (a, b) -> a + sep + elemToStr.apply(b));
+ }
+
+ private static <T> String toString(List<T> l, String sep) {
+ return toString(l, sep, String::valueOf);
+ }
+
+ private static String newlineSeparated(List<?> l) {
+ return toString(l, "\n");
+ }
+
+ private static String mkStr(Consumer<StringBuilder> build) {
+ StringBuilder t = new StringBuilder();
+ build.accept(t);
+ return t.toString();
+ }
+
+ private static class UiDumpWrapperException extends RuntimeException {
+ private UiDumpWrapperException(Throwable cause) {
+ super(cause.getMessage() + "\n\nWhile displaying the following UI:\n"
+ + mkStr(sb -> dumpNodes(sUiAutomation.getRootInActiveWindow(), sb)), cause);
+ }
+ }
+}
diff --git a/common/device-side/util/Android.bp b/common/device-side/util/Android.bp
deleted file mode 100644
index e1552b6..0000000
--- a/common/device-side/util/Android.bp
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (C) 2018 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.
-
-java_library_static {
- name: "compatibility-device-util",
- sdk_version: "test_current",
-
- srcs: [
- "src/**/*.java",
- "src/**/*.aidl",
- ],
-
- static_libs: [
- "androidx.test.rules",
- "compatibility-common-util-devicesidelib",
- "android-support-test",
- "ub-uiautomator",
- "mockito-target-minus-junit4",
- "androidx.annotation_annotation",
- "truth-prebuilt",
- ],
-
- libs: [
- "android.test.runner.stubs",
- "android.test.base.stubs",
- ],
-
- jarjar_rules: "protobuf-jarjar-rules.txt",
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ActivitiesWatcher.java b/common/device-side/util/src/com/android/compatibility/common/util/ActivitiesWatcher.java
deleted file mode 100644
index a2b0152..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/ActivitiesWatcher.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import android.app.Activity;
-import android.app.Application.ActivityLifecycleCallbacks;
-import android.os.Bundle;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import java.util.Map;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Helper object used to watch for activities lifecycle events.
- *
- * <p><b>NOTE:</b> currently it's limited to just one occurrence of each event.
- *
- * <p>These limitations will be fixed as needed (A.K.A. K.I.S.S. :-)
- */
-public final class ActivitiesWatcher implements ActivityLifecycleCallbacks {
-
- private static final String TAG = ActivitiesWatcher.class.getSimpleName();
-
- private final Map<String, ActivityWatcher> mWatchers = new ArrayMap<>();
- private final long mTimeoutMs;
-
- /**
- * Default constructor.
- *
- * @param timeoutMs how long to wait for given lifecycle event before timing out.
- */
- public ActivitiesWatcher(long timeoutMs) {
- mTimeoutMs = timeoutMs;
- }
-
- @Override
- public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
- Log.v(TAG, "onActivityCreated(): " + activity);
- notifyWatcher(activity, ActivityLifecycle.CREATED);
- }
-
- @Override
- public void onActivityStarted(Activity activity) {
- Log.v(TAG, "onActivityStarted(): " + activity);
- notifyWatcher(activity, ActivityLifecycle.STARTED);
- }
-
- @Override
- public void onActivityResumed(Activity activity) {
- Log.v(TAG, "onActivityResumed(): " + activity);
- notifyWatcher(activity, ActivityLifecycle.RESUMED);
- }
-
- @Override
- public void onActivityPaused(Activity activity) {
- Log.v(TAG, "onActivityPaused(): " + activity);
- notifyWatcher(activity, ActivityLifecycle.PAUSED);
- }
-
- @Override
- public void onActivityStopped(Activity activity) {
- Log.v(TAG, "onActivityStopped(): " + activity);
- notifyWatcher(activity, ActivityLifecycle.STOPPED);
- }
-
- @Override
- public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
- Log.v(TAG, "onActivitySaveInstanceState(): " + activity);
- notifyWatcher(activity, ActivityLifecycle.SAVE_INSTANCE);
- }
-
- @Override
- public void onActivityDestroyed(Activity activity) {
- Log.v(TAG, "onActivityDestroyed(): " + activity);
- notifyWatcher(activity, ActivityLifecycle.DESTROYED);
- }
-
- /**
- * Gets a watcher for the given activity.
- *
- * @throws IllegalStateException if already registered.
- */
- public ActivityWatcher watch(@NonNull Class<? extends Activity> clazz) {
- return watch(clazz.getName());
- }
-
- @Override
- public String toString() {
- return "[ActivitiesWatcher: activities=" + mWatchers.keySet() + "]";
- }
-
- /**
- * Gets a watcher for the given activity.
- *
- * @throws IllegalStateException if already registered.
- */
- public ActivityWatcher watch(@NonNull String className) {
- if (mWatchers.containsKey(className)) {
- throw new IllegalStateException("Already watching " + className);
- }
- Log.d(TAG, "Registering watcher for " + className);
- final ActivityWatcher watcher = new ActivityWatcher(mTimeoutMs);
- mWatchers.put(className, watcher);
- return watcher;
- }
-
- private void notifyWatcher(@NonNull Activity activity, @NonNull ActivityLifecycle lifecycle) {
- final String className = activity.getComponentName().getClassName();
- final ActivityWatcher watcher = mWatchers.get(className);
- if (watcher != null) {
- Log.d(TAG, "notifying watcher of " + className + " of " + lifecycle);
- watcher.notify(lifecycle);
- } else {
- Log.v(TAG, lifecycle + ": no watcher for " + className);
- }
- }
-
- /**
- * Object used to watch for acitivity lifecycle events.
- *
- * <p><b>NOTE: </b>currently it only supports one occurrence for each event.
- */
- public static final class ActivityWatcher {
- private final CountDownLatch mCreatedLatch = new CountDownLatch(1);
- private final CountDownLatch mStartedLatch = new CountDownLatch(1);
- private final CountDownLatch mResumedLatch = new CountDownLatch(1);
- private final CountDownLatch mPausedLatch = new CountDownLatch(1);
- private final CountDownLatch mStoppedLatch = new CountDownLatch(1);
- private final CountDownLatch mSaveInstanceLatch = new CountDownLatch(1);
- private final CountDownLatch mDestroyedLatch = new CountDownLatch(1);
- private final long mTimeoutMs;
-
- private ActivityWatcher(long timeoutMs) {
- mTimeoutMs = timeoutMs;
- }
-
- /**
- * Blocks until the given lifecycle event happens.
- *
- * @throws IllegalStateException if it times out while waiting.
- * @throws InterruptedException if interrupted while waiting.
- */
- public void waitFor(@NonNull ActivityLifecycle lifecycle) throws InterruptedException {
- final CountDownLatch latch = getLatch(lifecycle);
- final boolean called = latch.await(mTimeoutMs, TimeUnit.MILLISECONDS);
- if (!called) {
- throw new IllegalStateException(lifecycle + " not called in " + mTimeoutMs + " ms");
- }
- }
-
- private CountDownLatch getLatch(@NonNull ActivityLifecycle lifecycle) {
- switch (lifecycle) {
- case CREATED:
- return mCreatedLatch;
- case STARTED:
- return mStartedLatch;
- case RESUMED:
- return mResumedLatch;
- case PAUSED:
- return mPausedLatch;
- case STOPPED:
- return mStoppedLatch;
- case SAVE_INSTANCE:
- return mSaveInstanceLatch;
- case DESTROYED:
- return mDestroyedLatch;
- default:
- throw new IllegalArgumentException("unsupported lifecycle: " + lifecycle);
- }
- }
-
- private void notify(@NonNull ActivityLifecycle lifecycle) {
- getLatch(lifecycle).countDown();
- }
- }
-
- /**
- * Supported activity lifecycle.
- */
- public enum ActivityLifecycle {
- CREATED,
- STARTED,
- RESUMED,
- PAUSED,
- STOPPED,
- SAVE_INSTANCE,
- DESTROYED
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ActivityLauncher.java b/common/device-side/util/src/com/android/compatibility/common/util/ActivityLauncher.java
deleted file mode 100644
index 20d9331..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/ActivityLauncher.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.util;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.support.test.rule.ActivityTestRule;
-
-import androidx.annotation.NonNull;
-
-import com.android.compatibility.common.util.ActivitiesWatcher.ActivityWatcher;
-
-/**
- * Helper used to launch an activity and watch for its lifecycle events.
- *
- * @param <A> activity type
- */
-public final class ActivityLauncher<A extends Activity> {
-
- private final ActivityWatcher mWatcher;
- private final ActivityTestRule<A> mActivityTestRule;
- private final Intent mLaunchIntent;
-
- public ActivityLauncher(@NonNull Context context, @NonNull ActivitiesWatcher watcher,
- @NonNull Class<A> activityClass) {
- mWatcher = watcher.watch(activityClass);
- mActivityTestRule = new ActivityTestRule<>(activityClass);
- mLaunchIntent = new Intent(context, activityClass);
- }
-
- /**
- * Gets a watcher for the activity lifecycle events.
- */
- @NonNull
- public ActivityWatcher getWatcher() {
- return mWatcher;
- }
-
- /**
- * Launches the activity.
- */
- @NonNull
- public A launchActivity() {
- return mActivityTestRule.launchActivity(mLaunchIntent);
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/AdoptShellPermissionsRule.java b/common/device-side/util/src/com/android/compatibility/common/util/AdoptShellPermissionsRule.java
deleted file mode 100644
index f7b50b4..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/AdoptShellPermissionsRule.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import android.app.UiAutomation;
-import android.support.test.InstrumentationRegistry;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * Custom JUnit4 rule that runs a test adopting Shell's permissions, revoking them at the end.
- *
- * <p>NOTE: should only be used in the cases where *every* test in a class requires the permission.
- * For a more fine-grained access, use
- * {@link SystemUtil#runWithShellPermissionIdentity(ThrowingRunnable)}
- * or {@link SystemUtil#callWithShellPermissionIdentity(java.util.concurrent.Callable)} instead.
- */
-public class AdoptShellPermissionsRule implements TestRule {
-
- private final UiAutomation mUiAutomation;
-
- private final String[] mPermissions;
-
- public AdoptShellPermissionsRule() {
- this(InstrumentationRegistry.getInstrumentation().getUiAutomation());
- }
-
- public AdoptShellPermissionsRule(@NonNull UiAutomation uiAutomation) {
- this(uiAutomation, (String[]) null);
- }
-
- public AdoptShellPermissionsRule(@NonNull UiAutomation uiAutomation,
- @Nullable String... permissions) {
- mUiAutomation = uiAutomation;
- mPermissions = permissions;
- }
-
- @Override
- public Statement apply(Statement base, Description description) {
- return new Statement() {
-
- @Override
- public void evaluate() throws Throwable {
- if (mPermissions != null) {
- mUiAutomation.adoptShellPermissionIdentity(mPermissions);
- } else {
- mUiAutomation.adoptShellPermissionIdentity();
- }
- try {
- base.evaluate();
- } finally {
- mUiAutomation.dropShellPermissionIdentity();
- }
- }
- };
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/AmUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/AmUtils.java
deleted file mode 100644
index f3e178b..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/AmUtils.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-public class AmUtils {
- private static final String TAG = "CtsAmUtils";
-
- private static final String DUMPSYS_ACTIVITY_PROCESSES = "dumpsys activity --proto processes";
-
- private AmUtils() {
- }
-
- /** Run "adb shell am make-uid-idle PACKAGE" */
- public static void runMakeUidIdle(String packageName) {
- SystemUtil.runShellCommandForNoOutput("am make-uid-idle " + packageName);
- }
-
- /** Run "adb shell am kill PACKAGE" */
- public static void runKill(String packageName) throws Exception {
- runKill(packageName, false /* wait */);
- }
-
- public static void runKill(String packageName, boolean wait) throws Exception {
- SystemUtil.runShellCommandForNoOutput("am kill --user cur " + packageName);
-
- if (!wait) {
- return;
- }
-
- TestUtils.waitUntil("package process was not killed:" + packageName,
- () -> !isProcessRunning(packageName));
- }
-
- private static boolean isProcessRunning(String packageName) {
- final String output = SystemUtil.runShellCommand("ps -A -o NAME");
- String[] packages = output.split("\\n");
- for (int i = packages.length -1; i >=0; --i) {
- if (packages[i].equals(packageName)) {
- return true;
- }
- }
- return false;
- }
-
- /** Run "adb shell am set-standby-bucket" */
- public static void setStandbyBucket(String packageName, int value) {
- SystemUtil.runShellCommandForNoOutput("am set-standby-bucket " + packageName
- + " " + value);
- }
-
- /** Wait until all broad queues are idle. */
- public static void waitForBroadcastIdle() {
- SystemUtil.runCommandAndPrintOnLogcat(TAG, "am wait-for-broadcast-idle");
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ApiLevelUtil.java b/common/device-side/util/src/com/android/compatibility/common/util/ApiLevelUtil.java
deleted file mode 100644
index 943ebc7..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/ApiLevelUtil.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import android.os.Build;
-
-import java.lang.reflect.Field;
-
-/**
- * Device-side compatibility utility class for reading device API level.
- */
-public class ApiLevelUtil {
-
- public static boolean isBefore(int version) {
- return Build.VERSION.SDK_INT < version;
- }
-
- public static boolean isBefore(String version) {
- return Build.VERSION.SDK_INT < resolveVersionString(version);
- }
-
- public static boolean isAfter(int version) {
- return Build.VERSION.SDK_INT > version;
- }
-
- public static boolean isAfter(String version) {
- return Build.VERSION.SDK_INT > resolveVersionString(version);
- }
-
- public static boolean isAtLeast(int version) {
- return Build.VERSION.SDK_INT >= version;
- }
-
- public static boolean isAtLeast(String version) {
- return Build.VERSION.SDK_INT >= resolveVersionString(version);
- }
-
- public static boolean isAtMost(int version) {
- return Build.VERSION.SDK_INT <= version;
- }
-
- public static boolean isAtMost(String version) {
- return Build.VERSION.SDK_INT <= resolveVersionString(version);
- }
-
- public static int getApiLevel() {
- return Build.VERSION.SDK_INT;
- }
-
- public static boolean codenameEquals(String name) {
- return Build.VERSION.CODENAME.equalsIgnoreCase(name.trim());
- }
-
- public static boolean codenameStartsWith(String prefix) {
- return Build.VERSION.CODENAME.startsWith(prefix);
- }
-
- public static String getCodename() {
- return Build.VERSION.CODENAME;
- }
-
- protected static int resolveVersionString(String versionString) {
- // Attempt 1: Parse version string as an integer, e.g. "23" for M
- try {
- return Integer.parseInt(versionString);
- } catch (NumberFormatException e) { /* ignore for alternate approaches below */ }
- // Attempt 2: Find matching field in VersionCodes utility class, return value
- try {
- Field versionField = VersionCodes.class.getField(versionString.toUpperCase());
- return versionField.getInt(null); // no instance for VERSION_CODES, use null
- } catch (IllegalAccessException | NoSuchFieldException e) { /* ignore */ }
- // Attempt 3: Find field within android.os.Build.VERSION_CODES
- try {
- Field versionField = Build.VERSION_CODES.class.getField(versionString.toUpperCase());
- return versionField.getInt(null); // no instance for VERSION_CODES, use null
- } catch (IllegalAccessException | NoSuchFieldException e) {
- throw new RuntimeException(
- String.format("Failed to parse version string %s", versionString), e);
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/AppOpsUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/AppOpsUtils.java
deleted file mode 100644
index 939d6da..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/AppOpsUtils.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2018 Google Inc.
- *
- * 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.compatibility.common.util;
-
-import static android.app.AppOpsManager.MODE_ALLOWED;
-import static android.app.AppOpsManager.MODE_DEFAULT;
-import static android.app.AppOpsManager.MODE_ERRORED;
-import static android.app.AppOpsManager.MODE_IGNORED;
-
-import android.app.AppOpsManager;
-import android.support.test.InstrumentationRegistry;
-
-import java.io.IOException;
-
-/**
- * Utilities for controlling App Ops settings, and testing whether ops are logged.
- */
-public class AppOpsUtils {
-
- /**
- * Resets a package's app ops configuration to the device default. See AppOpsManager for the
- * default op settings.
- *
- * <p>
- * It's recommended to call this in setUp() and tearDown() of your test so the test starts and
- * ends with a reproducible default state, and so doesn't affect other tests.
- *
- * <p>
- * Some app ops are configured to be non-resettable, which means that the state of these will
- * not be reset even when calling this method.
- */
- public static String reset(String packageName) throws IOException {
- return runCommand("appops reset " + packageName);
- }
-
- /**
- * Sets the app op mode (e.g. allowed, denied) for a single package and operation.
- */
- public static String setOpMode(String packageName, String opStr, int mode)
- throws IOException {
- String modeStr;
- switch (mode) {
- case MODE_ALLOWED:
- modeStr = "allow";
- break;
- case MODE_ERRORED:
- modeStr = "deny";
- break;
- case MODE_IGNORED:
- modeStr = "ignore";
- break;
- case MODE_DEFAULT:
- modeStr = "default";
- break;
- default:
- throw new IllegalArgumentException("Unexpected app op type");
- }
- String command = "appops set " + packageName + " " + opStr + " " + modeStr;
- return runCommand(command);
- }
-
- /**
- * Get the app op mode (e.g. MODE_ALLOWED, MODE_DEFAULT) for a single package and operation.
- */
- public static int getOpMode(String packageName, String opStr)
- throws IOException {
- String opState = getOpState(packageName, opStr);
- if (opState.contains(" allow")) {
- return MODE_ALLOWED;
- } else if (opState.contains(" deny")) {
- return MODE_ERRORED;
- } else if (opState.contains(" ignore")) {
- return MODE_IGNORED;
- } else if (opState.contains(" default")) {
- return MODE_DEFAULT;
- } else {
- throw new IllegalStateException("Unexpected app op mode returned " + opState);
- }
- }
-
- /**
- * Returns whether an allowed operation has been logged by the AppOpsManager for a
- * package. Operations are noted when the app attempts to perform them and calls e.g.
- * {@link AppOpsManager#noteOperation}.
- *
- * @param opStr The public string constant of the operation (e.g. OPSTR_READ_SMS).
- */
- public static boolean allowedOperationLogged(String packageName, String opStr)
- throws IOException {
- return getOpState(packageName, opStr).contains(" time=");
- }
-
- /**
- * Returns whether a rejected operation has been logged by the AppOpsManager for a
- * package. Operations are noted when the app attempts to perform them and calls e.g.
- * {@link AppOpsManager#noteOperation}.
- *
- * @param opStr The public string constant of the operation (e.g. OPSTR_READ_SMS).
- */
- public static boolean rejectedOperationLogged(String packageName, String opStr)
- throws IOException {
- return getOpState(packageName, opStr).contains(" rejectTime=");
- }
-
- /**
- * Returns the app op state for a package. Includes information on when the operation was last
- * attempted to be performed by the package.
- *
- * Format: "SEND_SMS: allow; time=+23h12m54s980ms ago; rejectTime=+1h10m23s180ms"
- */
- private static String getOpState(String packageName, String opStr) throws IOException {
- return runCommand("appops get " + packageName + " " + opStr);
- }
-
- private static String runCommand(String command) throws IOException {
- return SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), command);
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/AppStandbyUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/AppStandbyUtils.java
deleted file mode 100644
index 6eeaae2..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/AppStandbyUtils.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import android.util.Log;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class AppStandbyUtils {
- private static final String TAG = "CtsAppStandbyUtils";
-
- /**
- * Returns if app standby is enabled.
- *
- * @return true if enabled; or false if disabled.
- */
- public static boolean isAppStandbyEnabled() {
- final String result = SystemUtil.runShellCommand(
- "dumpsys usagestats is-app-standby-enabled").trim();
- return Boolean.parseBoolean(result);
- }
-
- /**
- * Sets enabled state for app standby feature for runtime switch.
- *
- * App standby feature has 2 switches. This one affects the switch at runtime. If the build
- * switch is off, enabling the runtime switch will not enable App standby.
- *
- * @param enabled if App standby is enabled.
- */
- public static void setAppStandbyEnabledAtRuntime(boolean enabled) {
- final String value = enabled ? "1" : "0";
- Log.d(TAG, "Setting AppStandby " + (enabled ? "enabled" : "disabled") + " at runtime.");
- SettingsUtils.putGlobalSetting("app_standby_enabled", value);
- }
-
- /**
- * Returns if app standby is enabled at runtime. Note {@link #isAppStandbyEnabled()} may still
- * return {@code false} if this method returns {@code true}, because app standby can be disabled
- * at build time as well.
- *
- * @return true if enabled at runtime; or false if disabled at runtime.
- */
- public static boolean isAppStandbyEnabledAtRuntime() {
- final String result =
- SystemUtil.runShellCommand("settings get global app_standby_enabled").trim();
- final boolean boolResult = result.equals("1") || result.equals("null");
- Log.d(TAG, "AppStandby is " + (boolResult ? "enabled" : "disabled") + " at runtime.");
- return boolResult;
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BatteryUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/BatteryUtils.java
deleted file mode 100644
index 272bc67..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BatteryUtils.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import static com.android.compatibility.common.util.SettingsUtils.putGlobalSetting;
-import static com.android.compatibility.common.util.TestUtils.waitUntil;
-
-import android.content.pm.PackageManager;
-import android.os.BatteryManager;
-import android.os.PowerManager;
-import android.provider.Settings.Global;
-import android.support.test.InstrumentationRegistry;
-import android.util.Log;
-
-import org.junit.Assume;
-
-public class BatteryUtils {
- private static final String TAG = "CtsBatteryUtils";
-
- private BatteryUtils() {
- }
-
- public static BatteryManager getBatteryManager() {
- return InstrumentationRegistry.getContext().getSystemService(BatteryManager.class);
- }
-
- public static PowerManager getPowerManager() {
- return InstrumentationRegistry.getContext().getSystemService(PowerManager.class);
- }
-
- /** Make the target device think it's off charger. */
- public static void runDumpsysBatteryUnplug() {
- SystemUtil.runShellCommandForNoOutput("cmd battery unplug");
-
- Log.d(TAG, "Battery UNPLUGGED");
- }
-
- /**
- * Set the battery level to {@code level} percent. The valid range is [0, 100].
- */
- public static void runDumpsysBatterySetLevel(int level) throws Exception {
- SystemUtil.runShellCommandForNoOutput(("cmd battery set level " + level));
-
- Log.d(TAG, "Battery level set to " + level);
- }
-
- /**
- * Set whether the device is plugged in to a charger or not.
- */
- public static void runDumpsysBatterySetPluggedIn(boolean pluggedIn) throws Exception {
- SystemUtil.runShellCommandForNoOutput(("cmd battery set ac " + (pluggedIn ? "1" : "0")));
-
- Log.d(TAG, "Battery AC set to " + pluggedIn);
- }
-
- /** Reset the effect of all the previous {@code runDumpsysBattery*} call */
- public static void runDumpsysBatteryReset() {
- SystemUtil.runShellCommandForNoOutput(("cmd battery reset"));
-
- Log.d(TAG, "Battery RESET");
- }
-
- /**
- * Enable / disable battery saver. Note {@link #runDumpsysBatteryUnplug} must have been
- * executed before enabling BS.
- */
- public static void enableBatterySaver(boolean enabled) throws Exception {
- if (enabled) {
- SystemUtil.runShellCommandForNoOutput("cmd power set-mode 1");
- putGlobalSetting(Global.LOW_POWER_MODE, "1");
- waitUntil("Battery saver still off", () -> getPowerManager().isPowerSaveMode());
- waitUntil("Location mode still " + getPowerManager().getLocationPowerSaveMode(),
- () -> (PowerManager.LOCATION_MODE_NO_CHANGE
- != getPowerManager().getLocationPowerSaveMode()));
-
- Thread.sleep(500);
- waitUntil("Force all apps standby still off",
- () -> SystemUtil.runShellCommand("dumpsys alarm")
- .contains(" Force all apps standby: true\n"));
-
- } else {
- SystemUtil.runShellCommandForNoOutput("cmd power set-mode 0");
- putGlobalSetting(Global.LOW_POWER_MODE, "0");
- putGlobalSetting(Global.LOW_POWER_MODE_STICKY, "0");
- waitUntil("Battery saver still on", () -> !getPowerManager().isPowerSaveMode());
- waitUntil("Location mode still " + getPowerManager().getLocationPowerSaveMode(),
- () -> (PowerManager.LOCATION_MODE_NO_CHANGE
- == getPowerManager().getLocationPowerSaveMode()));
-
- Thread.sleep(500);
- waitUntil("Force all apps standby still on",
- () -> SystemUtil.runShellCommand("dumpsys alarm")
- .contains(" Force all apps standby: false\n"));
- }
-
- AmUtils.waitForBroadcastIdle();
- Log.d(TAG, "Battery saver turned " + (enabled ? "ON" : "OFF"));
- }
-
- /**
- * Turn on/off screen.
- */
- public static void turnOnScreen(boolean on) throws Exception {
- if (on) {
- SystemUtil.runShellCommandForNoOutput("input keyevent KEYCODE_WAKEUP");
- waitUntil("Device still not interactive", () -> getPowerManager().isInteractive());
-
- } else {
- SystemUtil.runShellCommandForNoOutput("input keyevent KEYCODE_SLEEP");
- waitUntil("Device still interactive", () -> !getPowerManager().isInteractive());
- }
- AmUtils.waitForBroadcastIdle();
- Log.d(TAG, "Screen turned " + (on ? "ON" : "OFF"));
- }
-
- /** @return true if the device supports battery saver. */
- public static boolean isBatterySaverSupported() {
- final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
- return !pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
- }
-
- /** "Assume" the current device supports battery saver. */
- public static void assumeBatterySaverFeature() {
- Assume.assumeTrue("Device doesn't support battery saver", isBatterySaverSupported());
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BeforeAfterRule.java b/common/device-side/util/src/com/android/compatibility/common/util/BeforeAfterRule.java
deleted file mode 100644
index be75671..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BeforeAfterRule.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * Custom JUnit4 rule that provides "before" / "after" callbacks, which is useful to use with
- * {@link org.junit.rules.RuleChain}.
- */
-public class BeforeAfterRule implements TestRule {
- @Override
- public Statement apply(Statement base, Description description) {
- return new Statement() {
-
- @Override
- public void evaluate() throws Throwable {
- onBefore(base, description);
- try {
- base.evaluate();
- } finally {
- onAfter(base, description);
- }
- }
- };
- }
-
- protected void onBefore(Statement base, Description description) throws Throwable {
- }
-
- protected void onAfter(Statement base, Description description) throws Throwable {
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BitmapUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/BitmapUtils.java
deleted file mode 100644
index 7f94d6f..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BitmapUtils.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2016 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.compatibility.common.util;
-
-import android.app.WallpaperManager;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.CompressFormat;
-import android.graphics.Color;
-import android.util.Log;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.lang.reflect.Method;
-import java.util.Random;
-
-public class BitmapUtils {
- private static final String TAG = "BitmapUtils";
-
- private BitmapUtils() {}
-
- // Compares two bitmaps by pixels.
- public static boolean compareBitmaps(Bitmap bmp1, Bitmap bmp2) {
- if (bmp1 == bmp2) {
- return true;
- }
-
- if (bmp1 == null || bmp2 == null) {
- return false;
- }
-
- if ((bmp1.getWidth() != bmp2.getWidth()) || (bmp1.getHeight() != bmp2.getHeight())) {
- return false;
- }
-
- for (int i = 0; i < bmp1.getWidth(); i++) {
- for (int j = 0; j < bmp1.getHeight(); j++) {
- if (bmp1.getPixel(i, j) != bmp2.getPixel(i, j)) {
- return false;
- }
- }
- }
- return true;
- }
-
- public static Bitmap generateRandomBitmap(int width, int height) {
- final Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- final Random generator = new Random();
- for (int x = 0; x < width; x++) {
- for (int y = 0; y < height; y++) {
- bmp.setPixel(x, y, generator.nextInt(Integer.MAX_VALUE));
- }
- }
- return bmp;
- }
-
- public static Bitmap generateWhiteBitmap(int width, int height) {
- final Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- bmp.eraseColor(Color.WHITE);
- return bmp;
- }
-
- public static Bitmap getWallpaperBitmap(Context context) throws Exception {
- WallpaperManager wallpaperManager = WallpaperManager.getInstance(context);
- Class<?> noparams[] = {};
- Class<?> wmClass = wallpaperManager.getClass();
- Method methodGetBitmap = wmClass.getDeclaredMethod("getBitmap", noparams);
- return (Bitmap) methodGetBitmap.invoke(wallpaperManager, null);
- }
-
- public static ByteArrayInputStream bitmapToInputStream(Bitmap bmp) {
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- bmp.compress(CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
- byte[] bitmapData = bos.toByteArray();
- return new ByteArrayInputStream(bitmapData);
- }
-
- private static void logIfBitmapSolidColor(String fileName, Bitmap bitmap) {
- int firstColor = bitmap.getPixel(0, 0);
- for (int x = 0; x < bitmap.getWidth(); x++) {
- for (int y = 0; y < bitmap.getHeight(); y++) {
- if (bitmap.getPixel(x, y) != firstColor) {
- return;
- }
- }
- }
-
- Log.w(TAG, String.format("%s entire bitmap color is %x", fileName, firstColor));
- }
-
- public static void saveBitmap(Bitmap bitmap, String directoryName, String fileName) {
- new File(directoryName).mkdirs(); // create dirs if needed
-
- Log.d(TAG, "Saving file: " + fileName + " in directory: " + directoryName);
-
- if (bitmap == null) {
- Log.d(TAG, "File not saved, bitmap was null");
- return;
- }
-
- logIfBitmapSolidColor(fileName, bitmap);
-
- File file = new File(directoryName, fileName);
- try (FileOutputStream fileStream = new FileOutputStream(file)) {
- bitmap.compress(Bitmap.CompressFormat.PNG, 0 /* ignored for PNG */, fileStream);
- fileStream.flush();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BlockedNumberService.java b/common/device-side/util/src/com/android/compatibility/common/util/BlockedNumberService.java
deleted file mode 100644
index 360c078..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BlockedNumberService.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import static android.provider.BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER;
-import static android.provider.BlockedNumberContract.BlockedNumbers.CONTENT_URI;
-
-import android.app.IntentService;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-import android.util.Log;
-
-/**
- * A service to handle interactions with the BlockedNumberProvider. The BlockedNumberProvider
- * can only be accessed by the primary user. This service can be run as a singleton service
- * which will then be able to access the BlockedNumberProvider from a test running in a
- * secondary user.
- */
-public class BlockedNumberService extends IntentService {
-
- static final String INSERT_ACTION = "android.telecom.cts.InsertBlockedNumber";
- static final String DELETE_ACTION = "android.telecom.cts.DeleteBlockedNumber";
- static final String PHONE_NUMBER_EXTRA = "number";
- static final String URI_EXTRA = "uri";
- static final String ROWS_EXTRA = "rows";
- static final String RESULT_RECEIVER_EXTRA = "resultReceiver";
-
- private static final String TAG = "CtsBlockNumberSvc";
-
- private ContentResolver mContentResolver;
-
- public BlockedNumberService() {
- super(BlockedNumberService.class.getName());
- }
-
- @Override
- public void onHandleIntent(Intent intent) {
- Log.i(TAG, "Starting BlockedNumberService service: " + intent);
- if (intent == null) {
- return;
- }
- Bundle bundle;
- mContentResolver = getContentResolver();
- switch (intent.getAction()) {
- case INSERT_ACTION:
- bundle = insertBlockedNumber(intent.getStringExtra(PHONE_NUMBER_EXTRA));
- break;
- case DELETE_ACTION:
- bundle = deleteBlockedNumber(Uri.parse(intent.getStringExtra(URI_EXTRA)));
- break;
- default:
- bundle = new Bundle();
- break;
- }
- ResultReceiver receiver = intent.getParcelableExtra(RESULT_RECEIVER_EXTRA);
- receiver.send(0, bundle);
- }
-
- private Bundle insertBlockedNumber(String number) {
- Log.i(TAG, "insertBlockedNumber: " + number);
-
- ContentValues cv = new ContentValues();
- cv.put(COLUMN_ORIGINAL_NUMBER, number);
- Uri uri = mContentResolver.insert(CONTENT_URI, cv);
- Bundle bundle = new Bundle();
- bundle.putString(URI_EXTRA, uri.toString());
- return bundle;
- }
-
- private Bundle deleteBlockedNumber(Uri uri) {
- Log.i(TAG, "deleteBlockedNumber: " + uri);
-
- int rows = mContentResolver.delete(uri, null, null);
- Bundle bundle = new Bundle();
- bundle.putInt(ROWS_EXTRA, rows);
- return bundle;
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BlockedNumberUtil.java b/common/device-side/util/src/com/android/compatibility/common/util/BlockedNumberUtil.java
deleted file mode 100644
index e5a0ce4..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BlockedNumberUtil.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import static com.android.compatibility.common.util.BlockedNumberService.DELETE_ACTION;
-import static com.android.compatibility.common.util.BlockedNumberService.INSERT_ACTION;
-import static com.android.compatibility.common.util.BlockedNumberService.PHONE_NUMBER_EXTRA;
-import static com.android.compatibility.common.util.BlockedNumberService.RESULT_RECEIVER_EXTRA;
-import static com.android.compatibility.common.util.BlockedNumberService.ROWS_EXTRA;
-import static com.android.compatibility.common.util.BlockedNumberService.URI_EXTRA;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.ResultReceiver;
-
-import junit.framework.TestCase;
-
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Utility for starting the blocked number service.
- */
-public class BlockedNumberUtil {
-
- private static final int TIMEOUT = 2;
-
- private BlockedNumberUtil() {}
-
- /** Insert a phone number into the blocked number provider and returns the resulting Uri. */
- public static Uri insertBlockedNumber(Context context, String phoneNumber) {
- Intent intent = new Intent(INSERT_ACTION);
- intent.putExtra(PHONE_NUMBER_EXTRA, phoneNumber);
-
- return Uri.parse(runBlockedNumberService(context, intent).getString(URI_EXTRA));
- }
-
- /** Remove a number from the blocked number provider and returns the number of rows deleted. */
- public static int deleteBlockedNumber(Context context, Uri uri) {
- Intent intent = new Intent(DELETE_ACTION);
- intent.putExtra(URI_EXTRA, uri.toString());
-
- return runBlockedNumberService(context, intent).getInt(ROWS_EXTRA);
- }
-
- /** Start the blocked number service. */
- static Bundle runBlockedNumberService(Context context, Intent intent) {
- // Temporarily allow background service
- SystemUtil.runShellCommand("cmd deviceidle tempwhitelist " + context.getPackageName());
-
- final Semaphore semaphore = new Semaphore(0);
- final Bundle result = new Bundle();
-
- ResultReceiver receiver = new ResultReceiver(new Handler(Looper.getMainLooper())) {
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- result.putAll(resultData);
- semaphore.release();
- }
- };
- intent.putExtra(RESULT_RECEIVER_EXTRA, receiver);
- intent.setComponent(new ComponentName(context, BlockedNumberService.class));
-
- context.startService(intent);
-
- try {
- TestCase.assertTrue(semaphore.tryAcquire(TIMEOUT, TimeUnit.SECONDS));
- } catch (InterruptedException e) {
- TestCase.fail("Timed out waiting for result from BlockedNumberService");
- }
- return result;
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java b/common/device-side/util/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java
deleted file mode 100755
index c26ddd0..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.util;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import androidx.annotation.Nullable;
-import android.util.Log;
-
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A receiver that allows caller to wait for the broadcast synchronously. Notice that you should not
- * reuse the instance. Usage is typically like this:
- * <pre>
- * BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver(context, "action");
- * try {
- * receiver.register();
- * Intent intent = receiver.awaitForBroadcast();
- * // assert the intent
- * } finally {
- * receiver.unregisterQuietly();
- * }
- * </pre>
- */
-public class BlockingBroadcastReceiver extends BroadcastReceiver {
- private static final String TAG = "BlockingBroadcast";
-
- private static final int DEFAULT_TIMEOUT_SECONDS = 30;
-
- private final BlockingQueue<Intent> mBlockingQueue;
- private final String mExpectedAction;
- private final Context mContext;
-
- public BlockingBroadcastReceiver(Context context, String expectedAction) {
- mContext = context;
- mExpectedAction = expectedAction;
- mBlockingQueue = new ArrayBlockingQueue<>(1);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (mExpectedAction.equals(intent.getAction())) {
- mBlockingQueue.add(intent);
- }
- }
-
- public void register() {
- mContext.registerReceiver(this, new IntentFilter(mExpectedAction));
- }
-
- /**
- * Wait until the broadcast and return the received broadcast intent. {@code null} is returned
- * if no broadcast with expected action is received within 30 seconds.
- */
- public @Nullable Intent awaitForBroadcast() {
- try {
- return mBlockingQueue.poll(DEFAULT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Log.e(TAG, "waitForBroadcast get interrupted: ", e);
- }
- return null;
- }
-
- /**
- * Wait until the broadcast and return the received broadcast intent. {@code null} is returned
- * if no broadcast with expected action is received within the given timeout.
- */
- public @Nullable Intent awaitForBroadcast(long timeoutMillis) {
- try {
- return mBlockingQueue.poll(timeoutMillis, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- Log.e(TAG, "waitForBroadcast get interrupted: ", e);
- }
- return null;
- }
-
- public void unregisterQuietly() {
- try {
- mContext.unregisterReceiver(this);
- } catch (Exception ex) {
- Log.e(TAG, "Failed to unregister BlockingBroadcastReceiver: ", ex);
- }
- }
-}
\ No newline at end of file
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastRpcBase.java b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastRpcBase.java
deleted file mode 100644
index 772e7d3..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastRpcBase.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.support.test.InstrumentationRegistry;
-import android.util.Log;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Base class to help broadcast-based RPC.
- */
-public abstract class BroadcastRpcBase<TRequest, TResponse> {
- private static final String TAG = "BroadcastRpc";
-
- private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
-
- static final String ACTION_REQUEST = "ACTION_REQUEST";
- static final String EXTRA_PAYLOAD = "EXTRA_PAYLOAD";
- static final String EXTRA_EXCEPTION = "EXTRA_EXCEPTION";
-
- static Handler sMainHandler = new Handler(Looper.getMainLooper());
-
- /** Implement in a subclass */
- protected abstract byte[] requestToBytes(TRequest request);
-
- /** Implement in a subclass */
- protected abstract TResponse bytesToResponse(byte[] bytes);
-
- public TResponse invoke(ComponentName targetReceiver, TRequest request) throws Exception {
- // Create a request intent.
- Log.i(TAG, "Sending to: " + targetReceiver + (VERBOSE ? "\nRequest: " + request : ""));
-
- final Intent requestIntent = new Intent(ACTION_REQUEST)
- .setComponent(targetReceiver)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
- .putExtra(EXTRA_PAYLOAD, requestToBytes(request));
-
- // Send it.
- final CountDownLatch latch = new CountDownLatch(1);
- final AtomicReference<Bundle> responseBundle = new AtomicReference<>();
-
- InstrumentationRegistry.getContext().sendOrderedBroadcast(
- requestIntent, null, new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- responseBundle.set(getResultExtras(false));
- latch.countDown();
- }
- }, sMainHandler, 0, null, null);
-
- // Wait for a reply and check it.
- final boolean responseArrived = latch.await(60, TimeUnit.SECONDS);
- assertTrue("Didn't receive broadcast result.", responseArrived);
-
- // TODO If responseArrived is false, print if the package / component is installed?
-
- assertNotNull("Didn't receive result extras", responseBundle.get());
-
- final String exception = responseBundle.get().getString(EXTRA_EXCEPTION);
- if (exception != null) {
- fail("Target throw exception: receiver=" + targetReceiver
- + "\nException: " + exception);
- }
-
- final byte[] resultPayload = responseBundle.get().getByteArray(EXTRA_PAYLOAD);
- assertNotNull("Didn't receive result payload", resultPayload);
-
- Log.i(TAG, "Response received: " + (VERBOSE ? resultPayload.toString() : ""));
-
- return bytesToResponse(resultPayload);
- }
-
- /**
- * Base class for a receiver for a broadcast-based RPC.
- */
- public abstract static class ReceiverBase<TRequest, TResponse> extends BroadcastReceiver {
- @Override
- public final void onReceive(Context context, Intent intent) {
- assertEquals(ACTION_REQUEST, intent.getAction());
-
- // Parse the request.
- final TRequest request = bytesToRequest(intent.getByteArrayExtra(EXTRA_PAYLOAD));
-
- Log.i(TAG, "Request received: " + (VERBOSE ? request.toString() : ""));
-
- Throwable exception = null;
-
- // Handle it and generate a response.
- TResponse response = null;
- try {
- response = handleRequest(context, request);
- Log.i(TAG, "Response generated: " + (VERBOSE ? response.toString() : ""));
- } catch (Throwable e) {
- exception = e;
- Log.e(TAG, "Exception thrown: " + e.getMessage(), e);
- }
-
- // Send back.
- final Bundle extras = new Bundle();
- if (response != null) {
- extras.putByteArray(EXTRA_PAYLOAD, responseToBytes(response));
- }
- if (exception != null) {
- extras.putString(EXTRA_EXCEPTION,
- exception.toString() + "\n" + Log.getStackTraceString(exception));
- }
- setResultExtras(extras);
- }
-
- /** Implement in a subclass */
- protected abstract TResponse handleRequest(Context context, TRequest request)
- throws Exception;
-
- /** Implement in a subclass */
- protected abstract byte[] responseToBytes(TResponse response);
-
- /** Implement in a subclass */
- protected abstract TRequest bytesToRequest(byte[] bytes);
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java
deleted file mode 100644
index 7500050..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2015 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.compatibility.common.util;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-public class BroadcastTestBase extends ActivityInstrumentationTestCase2<
- BroadcastTestStartActivity> {
- static final String TAG = "BroadcastTestBase";
- protected static final int TIMEOUT_MS = 20 * 1000;
-
- protected Context mContext;
- protected Bundle mResultExtras;
- private CountDownLatch mLatch;
- protected ActivityDoneReceiver mActivityDoneReceiver = null;
- private BroadcastTestStartActivity mActivity;
- private BroadcastUtils.TestcaseType mTestCaseType;
- protected boolean mHasFeature;
-
- public BroadcastTestBase() {
- super(BroadcastTestStartActivity.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mHasFeature = false;
- }
-
- @Override
- protected void tearDown() throws Exception {
- Log.v(TAG, getClass().getSimpleName() + ".tearDown(): hasFeature=" + mHasFeature
- + " receiver=" + mActivityDoneReceiver);
- if (mHasFeature && mActivityDoneReceiver != null) {
- try {
- mContext.unregisterReceiver(mActivityDoneReceiver);
- } catch (IllegalArgumentException e) {
- // This exception is thrown if mActivityDoneReceiver in
- // the above call to unregisterReceiver is never registered.
- // If so, no harm done by ignoring this exception.
- }
- mActivityDoneReceiver = null;
- }
- super.tearDown();
- }
-
- protected boolean isIntentSupported(String intentStr) {
- Intent intent = new Intent(intentStr);
- final PackageManager manager = mContext.getPackageManager();
- assertNotNull(manager);
- if (manager.resolveActivity(intent, 0) == null) {
- Log.i(TAG, "No Activity found for the intent: " + intentStr);
- return false;
- }
- return true;
- }
-
- protected void startTestActivity(String intentSuffix) {
- Intent intent = new Intent();
- intent.setAction("android.intent.action.TEST_START_ACTIVITY_" + intentSuffix);
- intent.setComponent(new ComponentName(getInstrumentation().getContext(),
- BroadcastTestStartActivity.class));
- setActivityIntent(intent);
- mActivity = getActivity();
- }
-
- protected void registerBroadcastReceiver(BroadcastUtils.TestcaseType testCaseType) throws Exception {
- mTestCaseType = testCaseType;
- mLatch = new CountDownLatch(1);
- mActivityDoneReceiver = new ActivityDoneReceiver();
- mContext.registerReceiver(mActivityDoneReceiver,
- new IntentFilter(BroadcastUtils.BROADCAST_INTENT + testCaseType.toString()));
- }
-
- protected boolean startTestAndWaitForBroadcast(BroadcastUtils.TestcaseType testCaseType,
- String pkg, String cls) throws Exception {
- Log.i(TAG, "Begin Testing: " + testCaseType);
- registerBroadcastReceiver(testCaseType);
- mActivity.startTest(testCaseType.toString(), pkg, cls);
- if (!mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- fail("Failed to receive broadcast in " + TIMEOUT_MS + "msec");
- return false;
- }
- return true;
- }
-
- class ActivityDoneReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(
- BroadcastUtils.BROADCAST_INTENT +
- BroadcastTestBase.this.mTestCaseType.toString())) {
- Bundle extras = intent.getExtras();
- Log.i(TAG, "received_broadcast for " + BroadcastUtils.toBundleString(extras));
- BroadcastTestBase.this.mResultExtras = extras;
- mLatch.countDown();
- }
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestStartActivity.java b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestStartActivity.java
deleted file mode 100644
index 4b3e85d..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestStartActivity.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2015 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.compatibility.common.util;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.content.ComponentName;
-import android.os.Bundle;
-import android.util.Log;
-
-public class BroadcastTestStartActivity extends Activity {
- static final String TAG = "BroadcastTestStartActivity";
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Log.i(TAG, " in onCreate");
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- Log.i(TAG, " in onResume");
- }
-
- void startTest(String testCaseType, String pkg, String cls) {
- Intent intent = new Intent();
- Log.i(TAG, "received_testcasetype = " + testCaseType);
- intent.putExtra(BroadcastUtils.TESTCASE_TYPE, testCaseType);
- intent.setAction("android.intent.action.VIMAIN_" + testCaseType);
- intent.setComponent(new ComponentName(pkg, cls));
- startActivity(intent);
- }
-
- @Override
- protected void onPause() {
- Log.i(TAG, " in onPause");
- super.onPause();
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- Log.i(TAG, " in onStart");
- }
-
- @Override
- protected void onRestart() {
- super.onRestart();
- Log.i(TAG, " in onRestart");
- }
-
- @Override
- protected void onStop() {
- Log.i(TAG, " in onStop");
- super.onStop();
- }
-
- @Override
- protected void onDestroy() {
- Log.i(TAG, " in onDestroy");
- super.onDestroy();
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastUtils.java
deleted file mode 100644
index a4661fc..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastUtils.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2015 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.compatibility.common.util;
-
-import android.os.Bundle;
-
-public class BroadcastUtils {
- public enum TestcaseType {
- ZEN_MODE_ON,
- ZEN_MODE_OFF,
- AIRPLANE_MODE_ON,
- AIRPLANE_MODE_OFF,
- BATTERYSAVER_MODE_ON,
- BATTERYSAVER_MODE_OFF,
- THEATER_MODE_ON,
- THEATER_MODE_OFF
- }
- public static final String TESTCASE_TYPE = "Testcase_type";
- public static final String BROADCAST_INTENT =
- "android.intent.action.FROM_UTIL_CTS_TEST_";
- public static final int NUM_MINUTES_FOR_ZENMODE = 10;
-
- public static final String toBundleString(Bundle bundle) {
- if (bundle == null) {
- return "*** Bundle is null ****";
- }
- StringBuilder buf = new StringBuilder();
- if (bundle != null) {
- buf.append("extras: ");
- for (String s : bundle.keySet()) {
- buf.append("(" + s + " = " + bundle.get(s) + "), ");
- }
- }
- return buf.toString();
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BundleUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/BundleUtils.java
deleted file mode 100644
index eda641d..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BundleUtils.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import android.os.Bundle;
-
-public class BundleUtils {
- private BundleUtils() {
- }
-
- public static Bundle makeBundle(Object... keysAndValues) {
- if ((keysAndValues.length % 2) != 0) {
- throw new IllegalArgumentException("Argument count not even.");
- }
-
- if (keysAndValues.length == 0) {
- return null;
- }
- final Bundle ret = new Bundle();
-
- for (int i = keysAndValues.length - 2; i >= 0; i -= 2) {
- final String key = keysAndValues[i].toString();
- final Object value = keysAndValues[i + 1];
-
- if (value == null) {
- ret.putString(key, null);
-
- } else if (value instanceof Boolean) {
- ret.putBoolean(key, (Boolean) value);
-
- } else if (value instanceof Integer) {
- ret.putInt(key, (Integer) value);
-
- } else if (value instanceof String) {
- ret.putString(key, (String) value);
-
- } else if (value instanceof Bundle) {
- ret.putBundle(key, (Bundle) value);
- } else {
- throw new IllegalArgumentException(
- "Type not supported yet: " + value.getClass().getName());
- }
- }
- return ret;
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java b/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java
deleted file mode 100644
index 7d7aaf0..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Execute business logic methods for device side test cases
- */
-public class BusinessLogicDeviceExecutor extends BusinessLogicExecutor {
-
- private Context mContext;
- private Object mTestObj;
-
- public BusinessLogicDeviceExecutor(Context context, Object testObj) {
- mContext = context;
- mTestObj = testObj;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected Object getTestObject() {
- return mTestObj;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void logInfo(String format, Object... args) {
- Log.i(LOG_TAG, String.format(format, args));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void logDebug(String format, Object... args) {
- Log.d(LOG_TAG, String.format(format, args));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected String formatExecutionString(String method, String... args) {
- return String.format("%s(%s)", method, TextUtils.join(", ", args));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected ResolvedMethod getResolvedMethod(Class cls, String methodName, String... args)
- throws ClassNotFoundException {
- List<Method> nameMatches = getMethodsWithName(cls, methodName);
- for (Method m : nameMatches) {
- ResolvedMethod rm = new ResolvedMethod(m);
- int paramTypesMatched = 0;
- int argsUsed = 0;
- Class[] paramTypes = m.getParameterTypes();
- for (Class paramType : paramTypes) {
- if (argsUsed == args.length && paramType.equals(String.class)) {
- // We've used up all supplied string args, so this method will not match.
- // If paramType is the Context class, we can match a paramType without needing
- // more string args. similarly, paramType "String[]" can be matched with zero
- // string args. If we add support for more paramTypes, this logic may require
- // adjustment.
- break;
- }
- if (paramType.equals(String.class)) {
- // Type "String" -- supply the next available arg
- rm.addArg(args[argsUsed++]);
- } else if (Context.class.isAssignableFrom(paramType)) {
- // Type "Context" -- supply the context from the test case
- rm.addArg(mContext);
- } else if (paramType.equals(Class.forName(STRING_ARRAY_CLASS))) {
- // Type "String[]" (or "String...") -- supply all remaining args
- rm.addArg(Arrays.copyOfRange(args, argsUsed, args.length));
- argsUsed += (args.length - argsUsed);
- } else {
- break; // Param type is unrecognized, this method will not match.
- }
- paramTypesMatched++; // A param type has been matched when reaching this point.
- }
- if (paramTypesMatched == paramTypes.length && argsUsed == args.length) {
- return rm; // Args match, methods match, so return the first method-args pairing.
- }
- // Not a match, try args for next method that matches by name.
- }
- throw new RuntimeException(String.format(
- "BusinessLogic: Failed to invoke action method %s with args: %s", methodName,
- Arrays.toString(args)));
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicTestCase.java b/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicTestCase.java
deleted file mode 100644
index d567a5f..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicTestCase.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.util;
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
-
-import android.app.Instrumentation;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.net.Uri;
-import android.os.ParcelFileDescriptor;
-import android.support.test.InstrumentationRegistry;
-import android.util.Log;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.rules.TestName;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.lang.reflect.Field;
-import java.util.Map;
-
-/**
- * Device-side base class for tests leveraging the Business Logic service.
- */
-public class BusinessLogicTestCase {
- private static final String TAG = "BusinessLogicTestCase";
-
- /* String marking the beginning of the parameter in a test name */
- private static final String PARAM_START = "[";
-
- public static final String CONTENT_PROVIDER =
- String.format("%s://android.tradefed.contentprovider", ContentResolver.SCHEME_CONTENT);
-
- /* Test name rule that tracks the current test method under execution */
- @Rule public TestName mTestCase = new TestName();
-
- protected BusinessLogic mBusinessLogic;
- protected boolean mCanReadBusinessLogic = true;
-
- @Before
- public void handleBusinessLogic() {
- loadBusinessLogic();
- executeBusinessLogic();
- }
-
- protected void executeBusinessLogic() {
- String methodName = mTestCase.getMethodName();
- assertTrue(String.format("Test \"%s\" is unable to execute as it depends on the missing "
- + "remote configuration.", methodName), mCanReadBusinessLogic);
- if (methodName.contains(PARAM_START)) {
- // Strip parameter suffix (e.g. "[0]") from method name
- methodName = methodName.substring(0, methodName.lastIndexOf(PARAM_START));
- }
- String testName = String.format("%s#%s", this.getClass().getName(), methodName);
- if (mBusinessLogic.hasLogicFor(testName)) {
- Log.i(TAG, "Finding business logic for test case: " + testName);
- BusinessLogicExecutor executor = new BusinessLogicDeviceExecutor(getContext(), this);
- mBusinessLogic.applyLogicFor(testName, executor);
- }
- }
-
- protected void loadBusinessLogic() {
- String uriPath = String.format("%s/%s", CONTENT_PROVIDER, BusinessLogic.DEVICE_FILE);
- Uri sdcardUri = Uri.parse(uriPath);
- Context appContext = InstrumentationRegistry.getTargetContext();
- try {
- ContentResolver resolver = appContext.getContentResolver();
- ParcelFileDescriptor descriptor = resolver.openFileDescriptor(sdcardUri, "r");
- mBusinessLogic = BusinessLogicFactory.createFromFile(
- new ParcelFileDescriptor.AutoCloseInputStream(descriptor));
- return;
- } catch (FileNotFoundException e) {
- // Log the error and use the fallback too
- Log.e(TAG, "Error while using content provider for config", e);
- }
- // Fallback to reading the business logic directly.
- File businessLogicFile = new File(BusinessLogic.DEVICE_FILE);
- if (businessLogicFile.canRead()) {
- mBusinessLogic = BusinessLogicFactory.createFromFile(businessLogicFile);
- } else {
- mCanReadBusinessLogic = false;
- }
- }
-
- protected static Instrumentation getInstrumentation() {
- return InstrumentationRegistry.getInstrumentation();
- }
-
- protected static Context getContext() {
- return getInstrumentation().getTargetContext();
- }
-
- public static void skipTest(String message) {
- assumeTrue(message, false);
- }
-
- public static void failTest(String message) {
- fail(message);
- }
-
- public void mapPut(String mapName, String key, String value) {
- boolean put = false;
- for (Field f : getClass().getDeclaredFields()) {
- if (f.getName().equalsIgnoreCase(mapName) && Map.class.isAssignableFrom(f.getType())) {
- try {
- ((Map) f.get(this)).put(key, value);
- put = true;
- } catch (IllegalAccessException e) {
- Log.w(String.format("failed to invoke mapPut on field \"%s\". Resuming...",
- f.getName()), e);
- // continue iterating through fields, throw exception if no other fields match
- }
- }
- }
- if (!put) {
- throw new RuntimeException(String.format("Failed to find map %s in class %s", mapName,
- getClass().getName()));
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/CTSResult.java b/common/device-side/util/src/com/android/compatibility/common/util/CTSResult.java
deleted file mode 100644
index d60155a..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/CTSResult.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2008 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.compatibility.common.util;
-
-public interface CTSResult {
- public static final int RESULT_OK = 1;
- public static final int RESULT_FAIL = 2;
- public void setResult(int resultCode);
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/CallbackAsserter.java b/common/device-side/util/src/com/android/compatibility/common/util/CallbackAsserter.java
deleted file mode 100644
index 436161a..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/CallbackAsserter.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import static junit.framework.Assert.fail;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.support.test.InstrumentationRegistry;
-import android.util.Log;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Predicate;
-
-/**
- * CallbackAsserter helps wait until a callback is called.
- */
-public class CallbackAsserter {
- private static final String TAG = "CallbackAsserter";
-
- final CountDownLatch mLatch = new CountDownLatch(1);
-
- CallbackAsserter() {
- }
-
- /**
- * Call this to assert a callback be called within the given timeout.
- */
- public final void assertCalled(String message, int timeoutSeconds) throws Exception {
- try {
- if (mLatch.await(timeoutSeconds, TimeUnit.SECONDS)) {
- return;
- }
- fail("Didn't receive callback: " + message);
- } finally {
- cleanUp();
- }
- }
-
- void cleanUp() {
- }
-
- /**
- * Create an instance for a broadcast.
- */
- public static CallbackAsserter forBroadcast(IntentFilter filter) {
- return forBroadcast(filter, null);
- }
-
- /**
- * Create an instance for a broadcast.
- */
- public static CallbackAsserter forBroadcast(IntentFilter filter, Predicate<Intent> checker) {
- return new BroadcastAsserter(filter, checker);
- }
-
- /**
- * Create an instance for a content changed notification.
- */
- public static CallbackAsserter forContentUri(Uri watchUri) {
- return forContentUri(watchUri, null);
- }
-
- /**
- * Create an instance for a content changed notification.
- */
- public static CallbackAsserter forContentUri(Uri watchUri, Predicate<Uri> checker) {
- return new ContentObserverAsserter(watchUri, checker);
- }
-
- private static class BroadcastAsserter extends CallbackAsserter {
- private final BroadcastReceiver mReceiver;
-
- BroadcastAsserter(IntentFilter filter, Predicate<Intent> checker) {
- mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (checker != null && !checker.test(intent)) {
- Log.v(TAG, "Ignoring intent: " + intent);
- return;
- }
- mLatch.countDown();
- }
- };
- InstrumentationRegistry.getContext().registerReceiver(mReceiver, filter);
- }
-
- @Override
- void cleanUp() {
- InstrumentationRegistry.getContext().unregisterReceiver(mReceiver);
- }
- }
-
- private static class ContentObserverAsserter extends CallbackAsserter {
- private final ContentObserver mObserver;
-
- ContentObserverAsserter(Uri watchUri, Predicate<Uri> checker) {
- mObserver = new ContentObserver(null) {
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- if (checker != null && !checker.test(uri)) {
- Log.v(TAG, "Ignoring notification on URI: " + uri);
- return;
- }
- mLatch.countDown();
- }
- };
- InstrumentationRegistry.getContext().getContentResolver().registerContentObserver(
- watchUri, true, mObserver);
- }
-
- @Override
- void cleanUp() {
- InstrumentationRegistry.getContext().getContentResolver().unregisterContentObserver(
- mObserver);
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ColorUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/ColorUtils.java
deleted file mode 100644
index c0da13d..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/ColorUtils.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.compatibility.common.util;
-
-import static org.junit.Assert.fail;
-
-import android.graphics.Color;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.util.function.Function;
-import java.util.function.IntUnaryOperator;
-
-public class ColorUtils {
- public static void verifyColor(int expected, int observed) {
- verifyColor(expected, observed, 0);
- }
-
- public static void verifyColor(int expected, int observed, int tolerance) {
- verifyColor("", expected, observed, tolerance);
- }
-
- /**
- * Verify that two colors match within a per-channel tolerance.
- *
- * @param s String with extra information about the test with an error.
- * @param expected Expected color.
- * @param observed Observed color.
- * @param tolerance Per-channel tolerance by which the color can mismatch.
- */
- public static void verifyColor(@NonNull String s, int expected, int observed, int tolerance) {
- s += " expected 0x" + Integer.toHexString(expected)
- + ", observed 0x" + Integer.toHexString(observed)
- + ", tolerated channel error 0x" + tolerance;
- String red = verifyChannel("red", expected, observed, tolerance, (i) -> Color.red(i));
- String green = verifyChannel("green", expected, observed, tolerance, (i) -> Color.green(i));
- String blue = verifyChannel("blue", expected, observed, tolerance, (i) -> Color.blue(i));
- String alpha = verifyChannel("alpha", expected, observed, tolerance, (i) -> Color.alpha(i));
-
- buildErrorString(s, red, green, blue, alpha);
- }
-
- private static void buildErrorString(@NonNull String s, @Nullable String red,
- @Nullable String green, @Nullable String blue, @Nullable String alpha) {
- String err = null;
- for (String channel : new String[]{red, green, blue, alpha}) {
- if (channel == null) continue;
- if (err == null) err = s;
- err += "\n\t\t" + channel;
- }
- if (err != null) {
- fail(err);
- }
- }
-
- private static String verifyChannel(String channelName, int expected, int observed,
- int tolerance, IntUnaryOperator f) {
- int e = f.applyAsInt(expected);
- int o = f.applyAsInt(observed);
- if (Math.abs(e - o) <= tolerance) {
- return null;
- }
- return "Channel " + channelName + " mismatch: expected<0x" + Integer.toHexString(e)
- + ">, observed: <0x" + Integer.toHexString(o) + ">";
- }
-
- /**
- * Verify that two colors match within a per-channel tolerance.
- *
- * @param msg String with extra information about the test with an error.
- * @param expected Expected color.
- * @param observed Observed color.
- * @param tolerance Per-channel tolerance by which the color can mismatch.
- */
- public static void verifyColor(@NonNull String msg, Color expected, Color observed,
- float tolerance) {
- if (!expected.getColorSpace().equals(observed.getColorSpace())) {
- fail("Cannot compare Colors with different color spaces! expected: " + expected
- + "\tobserved: " + observed);
- }
- msg += " expected " + expected + ", observed " + observed + ", tolerated channel error "
- + tolerance;
- String red = verifyChannel("red", expected, observed, tolerance, (c) -> c.red());
- String green = verifyChannel("green", expected, observed, tolerance, (c) -> c.green());
- String blue = verifyChannel("blue", expected, observed, tolerance, (c) -> c.blue());
- String alpha = verifyChannel("alpha", expected, observed, tolerance, (c) -> c.alpha());
-
- buildErrorString(msg, red, green, blue, alpha);
- }
-
- private static String verifyChannel(String channelName, Color expected, Color observed,
- float tolerance, Function<Color, Float> f) {
- float e = f.apply(expected);
- float o = f.apply(observed);
- float diff = Math.abs(e - o);
- if (diff <= tolerance) {
- return null;
- }
- return "Channel " + channelName + " mismatch: expected<" + e + ">, observed: <" + o
- + ">, difference: <" + diff + ">";
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ConnectivityUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/ConnectivityUtils.java
deleted file mode 100644
index 09a0a85..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/ConnectivityUtils.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-
-public class ConnectivityUtils {
- private ConnectivityUtils() {
- }
-
- /** @return true when the device has a network connection. */
- public static boolean isNetworkConnected(Context context) {
- final NetworkInfo networkInfo = context.getSystemService(ConnectivityManager.class)
- .getActiveNetworkInfo();
- return (networkInfo != null) && networkInfo.isConnected();
- }
-
- /** Assert that the device has a network connection. */
- public static void assertNetworkConnected(Context context) {
- assertTrue("Network must be connected", isNetworkConnected(context));
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/CpuFeatures.java b/common/device-side/util/src/com/android/compatibility/common/util/CpuFeatures.java
deleted file mode 100644
index 9360942..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/CpuFeatures.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2010 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.compatibility.common.util;
-
-import android.os.Build;
-
-public class CpuFeatures {
-
- public static final String ARMEABI_V7 = "armeabi-v7a";
-
- public static final String ARMEABI = "armeabi";
-
- public static final String MIPSABI = "mips";
-
- public static final String X86ABI = "x86";
-
- public static final int HWCAP_VFP = (1 << 6);
-
- public static final int HWCAP_NEON = (1 << 12);
-
- public static final int HWCAP_VFPv3 = (1 << 13);
-
- public static final int HWCAP_VFPv4 = (1 << 16);
-
- public static final int HWCAP_IDIVA = (1 << 17);
-
- public static final int HWCAP_IDIVT = (1 << 18);
-
- static {
- System.loadLibrary("cts_jni");
- }
-
- public static native boolean isArmCpu();
-
- public static native boolean isMipsCpu();
-
- public static native boolean isX86Cpu();
-
- public static native boolean isArm64Cpu();
-
- public static native boolean isMips64Cpu();
-
- public static native boolean isX86_64Cpu();
-
- public static native int getHwCaps();
-
- public static boolean isArm64CpuIn32BitMode() {
- if (!isArmCpu()) {
- return false;
- }
-
- for (String abi : Build.SUPPORTED_64_BIT_ABIS) {
- if (abi.equals("arm64-v8a")) {
- return true;
- }
- }
-
- return false;
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/CtsAndroidTestCase.java b/common/device-side/util/src/com/android/compatibility/common/util/CtsAndroidTestCase.java
deleted file mode 100644
index 1ffad1d..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/CtsAndroidTestCase.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2012 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.compatibility.common.util;
-
-import android.content.Context;
-import android.test.ActivityInstrumentationTestCase2;
-
-/**
- * This class emulates AndroidTestCase, but internally it is ActivityInstrumentationTestCase2
- * to access Instrumentation.
- * DummyActivity is not supposed to be accessed.
- */
-public class CtsAndroidTestCase extends ActivityInstrumentationTestCase2<DummyActivity> {
- public CtsAndroidTestCase() {
- super(DummyActivity.class);
- }
-
- public Context getContext() {
- return getInstrumentation().getContext();
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/CtsKeyEventUtil.java b/common/device-side/util/src/com/android/compatibility/common/util/CtsKeyEventUtil.java
deleted file mode 100644
index 97e4310..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/CtsKeyEventUtil.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2016 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.compatibility.common.util;
-
-import android.app.Instrumentation;
-import android.os.Looper;
-import android.os.SystemClock;
-import android.util.Log;
-import android.view.InputDevice;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.inputmethod.InputMethodManager;
-
-import java.lang.reflect.Field;
-
-/**
- * Utility class to send KeyEvents bypassing the IME. The code is similar to functions in
- * {@link Instrumentation} and {@link android.test.InstrumentationTestCase} classes. It uses
- * {@link InputMethodManager#dispatchKeyEventFromInputMethod(View, KeyEvent)} to send the events.
- * After sending the events waits for idle.
- */
-public final class CtsKeyEventUtil {
-
- private CtsKeyEventUtil() {}
-
- /**
- * Sends the key events corresponding to the text to the app being instrumented.
- *
- * @param instrumentation the instrumentation used to run the test.
- * @param targetView View to find the ViewRootImpl and dispatch.
- * @param text The text to be sent. Null value returns immediately.
- */
- public static void sendString(final Instrumentation instrumentation, final View targetView,
- final String text) {
- if (text == null) {
- return;
- }
-
- KeyEvent[] events = getKeyEvents(text);
-
- if (events != null) {
- for (int i = 0; i < events.length; i++) {
- // We have to change the time of an event before injecting it because
- // all KeyEvents returned by KeyCharacterMap.getEvents() have the same
- // time stamp and the system rejects too old events. Hence, it is
- // possible for an event to become stale before it is injected if it
- // takes too long to inject the preceding ones.
- sendKey(instrumentation, targetView, KeyEvent.changeTimeRepeat(
- events[i], SystemClock.uptimeMillis(), 0 /* newRepeat */));
- }
- }
- }
-
- /**
- * Sends a series of key events through instrumentation. For instance:
- * sendKeys(view, KEYCODE_DPAD_LEFT, KEYCODE_DPAD_CENTER).
- *
- * @param instrumentation the instrumentation used to run the test.
- * @param targetView View to find the ViewRootImpl and dispatch.
- * @param keys The series of key codes.
- */
- public static void sendKeys(final Instrumentation instrumentation, final View targetView,
- final int...keys) {
- final int count = keys.length;
-
- for (int i = 0; i < count; i++) {
- try {
- sendKeyDownUp(instrumentation, targetView, keys[i]);
- } catch (SecurityException e) {
- // Ignore security exceptions that are now thrown
- // when trying to send to another app, to retain
- // compatibility with existing tests.
- }
- }
- }
-
- /**
- * Sends a series of key events through instrumentation. The sequence of keys is a string
- * containing the key names as specified in KeyEvent, without the KEYCODE_ prefix. For
- * instance: sendKeys(view, "DPAD_LEFT A B C DPAD_CENTER"). Each key can be repeated by using
- * the N* prefix. For instance, to send two KEYCODE_DPAD_LEFT, use the following:
- * sendKeys(view, "2*DPAD_LEFT").
- *
- * @param instrumentation the instrumentation used to run the test.
- * @param targetView View to find the ViewRootImpl and dispatch.
- * @param keysSequence The sequence of keys.
- */
- public static void sendKeys(final Instrumentation instrumentation, final View targetView,
- final String keysSequence) {
- final String[] keys = keysSequence.split(" ");
- final int count = keys.length;
-
- for (int i = 0; i < count; i++) {
- String key = keys[i];
- int repeater = key.indexOf('*');
-
- int keyCount;
- try {
- keyCount = repeater == -1 ? 1 : Integer.parseInt(key.substring(0, repeater));
- } catch (NumberFormatException e) {
- Log.w("ActivityTestCase", "Invalid repeat count: " + key);
- continue;
- }
-
- if (repeater != -1) {
- key = key.substring(repeater + 1);
- }
-
- for (int j = 0; j < keyCount; j++) {
- try {
- final Field keyCodeField = KeyEvent.class.getField("KEYCODE_" + key);
- final int keyCode = keyCodeField.getInt(null);
- try {
- sendKeyDownUp(instrumentation, targetView, keyCode);
- } catch (SecurityException e) {
- // Ignore security exceptions that are now thrown
- // when trying to send to another app, to retain
- // compatibility with existing tests.
- }
- } catch (NoSuchFieldException e) {
- Log.w("ActivityTestCase", "Unknown keycode: KEYCODE_" + key);
- break;
- } catch (IllegalAccessException e) {
- Log.w("ActivityTestCase", "Unknown keycode: KEYCODE_" + key);
- break;
- }
- }
- }
- }
-
- /**
- * Sends an up and down key events.
- *
- * @param instrumentation the instrumentation used to run the test.
- * @param targetView View to find the ViewRootImpl and dispatch.
- * @param key The integer keycode for the event to be sent.
- */
- public static void sendKeyDownUp(final Instrumentation instrumentation, final View targetView,
- final int key) {
- sendKey(instrumentation, targetView, new KeyEvent(KeyEvent.ACTION_DOWN, key));
- sendKey(instrumentation, targetView, new KeyEvent(KeyEvent.ACTION_UP, key));
- }
-
- /**
- * Sends a key event.
- *
- * @param instrumentation the instrumentation used to run the test.
- * @param targetView View to find the ViewRootImpl and dispatch.
- * @param event KeyEvent to be send.
- */
- public static void sendKey(final Instrumentation instrumentation, final View targetView,
- final KeyEvent event) {
- validateNotAppThread();
-
- long downTime = event.getDownTime();
- long eventTime = event.getEventTime();
- int action = event.getAction();
- int code = event.getKeyCode();
- int repeatCount = event.getRepeatCount();
- int metaState = event.getMetaState();
- int deviceId = event.getDeviceId();
- int scanCode = event.getScanCode();
- int source = event.getSource();
- int flags = event.getFlags();
- if (source == InputDevice.SOURCE_UNKNOWN) {
- source = InputDevice.SOURCE_KEYBOARD;
- }
- if (eventTime == 0) {
- eventTime = SystemClock.uptimeMillis();
- }
- if (downTime == 0) {
- downTime = eventTime;
- }
-
- final KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount,
- metaState, deviceId, scanCode, flags, source);
-
- InputMethodManager imm = targetView.getContext().getSystemService(InputMethodManager.class);
- imm.dispatchKeyEventFromInputMethod(null, newEvent);
- instrumentation.waitForIdleSync();
- }
-
- /**
- * Sends a key event while holding another modifier key down, then releases both keys and
- * waits for idle sync. Useful for sending combinations like shift + tab.
- *
- * @param instrumentation the instrumentation used to run the test.
- * @param targetView View to find the ViewRootImpl and dispatch.
- * @param keyCodeToSend The integer keycode for the event to be sent.
- * @param modifierKeyCodeToHold The integer keycode of the modifier to be held.
- */
- public static void sendKeyWhileHoldingModifier(final Instrumentation instrumentation,
- final View targetView, final int keyCodeToSend,
- final int modifierKeyCodeToHold) {
- final int metaState = getMetaStateForModifierKeyCode(modifierKeyCodeToHold);
- final long downTime = SystemClock.uptimeMillis();
-
- final KeyEvent holdKeyDown = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
- modifierKeyCodeToHold, 0 /* repeat */);
- sendKey(instrumentation ,targetView, holdKeyDown);
-
- final KeyEvent keyDown = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
- keyCodeToSend, 0 /* repeat */, metaState);
- sendKey(instrumentation, targetView, keyDown);
-
- final KeyEvent keyUp = new KeyEvent(downTime, downTime, KeyEvent.ACTION_UP,
- keyCodeToSend, 0 /* repeat */, metaState);
- sendKey(instrumentation, targetView, keyUp);
-
- final KeyEvent holdKeyUp = new KeyEvent(downTime, downTime, KeyEvent.ACTION_UP,
- modifierKeyCodeToHold, 0 /* repeat */);
- sendKey(instrumentation, targetView, holdKeyUp);
-
- instrumentation.waitForIdleSync();
- }
-
- private static int getMetaStateForModifierKeyCode(int modifierKeyCode) {
- if (!KeyEvent.isModifierKey(modifierKeyCode)) {
- throw new IllegalArgumentException("Modifier key expected, but got: "
- + KeyEvent.keyCodeToString(modifierKeyCode));
- }
-
- int metaState;
- switch (modifierKeyCode) {
- case KeyEvent.KEYCODE_SHIFT_LEFT:
- metaState = KeyEvent.META_SHIFT_LEFT_ON;
- break;
- case KeyEvent.KEYCODE_SHIFT_RIGHT:
- metaState = KeyEvent.META_SHIFT_RIGHT_ON;
- break;
- case KeyEvent.KEYCODE_ALT_LEFT:
- metaState = KeyEvent.META_ALT_LEFT_ON;
- break;
- case KeyEvent.KEYCODE_ALT_RIGHT:
- metaState = KeyEvent.META_ALT_RIGHT_ON;
- break;
- case KeyEvent.KEYCODE_CTRL_LEFT:
- metaState = KeyEvent.META_CTRL_LEFT_ON;
- break;
- case KeyEvent.KEYCODE_CTRL_RIGHT:
- metaState = KeyEvent.META_CTRL_RIGHT_ON;
- break;
- case KeyEvent.KEYCODE_META_LEFT:
- metaState = KeyEvent.META_META_LEFT_ON;
- break;
- case KeyEvent.KEYCODE_META_RIGHT:
- metaState = KeyEvent.META_META_RIGHT_ON;
- break;
- case KeyEvent.KEYCODE_SYM:
- metaState = KeyEvent.META_SYM_ON;
- break;
- case KeyEvent.KEYCODE_NUM:
- metaState = KeyEvent.META_NUM_LOCK_ON;
- break;
- case KeyEvent.KEYCODE_FUNCTION:
- metaState = KeyEvent.META_FUNCTION_ON;
- break;
- default:
- // Safety net: all modifier keys need to have at least one meta state associated.
- throw new UnsupportedOperationException("No meta state associated with "
- + "modifier key: " + KeyEvent.keyCodeToString(modifierKeyCode));
- }
-
- return KeyEvent.normalizeMetaState(metaState);
- }
-
- private static KeyEvent[] getKeyEvents(final String text) {
- KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
- return keyCharacterMap.getEvents(text.toCharArray());
- }
-
- private static void validateNotAppThread() {
- if (Looper.myLooper() == Looper.getMainLooper()) {
- throw new RuntimeException(
- "This method can not be called from the main application thread");
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/CtsMockitoUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/CtsMockitoUtils.java
deleted file mode 100644
index 54985dc..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/CtsMockitoUtils.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2016 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.compatibility.common.util;
-
-import org.mockito.verification.VerificationMode;
-
-public class CtsMockitoUtils {
- private CtsMockitoUtils() {}
-
- public static VerificationMode within(long timeout) {
- return new Within(timeout);
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/CtsMouseUtil.java b/common/device-side/util/src/com/android/compatibility/common/util/CtsMouseUtil.java
deleted file mode 100644
index e53eb08..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/CtsMouseUtil.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-
-import android.app.Instrumentation;
-import android.app.UiAutomation;
-import android.os.SystemClock;
-import android.view.InputDevice;
-import android.view.MotionEvent;
-import android.view.View;
-
-import org.mockito.ArgumentMatcher;
-import org.mockito.InOrder;
-
-public final class CtsMouseUtil {
-
- private CtsMouseUtil() {}
-
- public static View.OnHoverListener installHoverListener(View view) {
- return installHoverListener(view, true);
- }
-
- public static View.OnHoverListener installHoverListener(View view, boolean result) {
- final View.OnHoverListener mockListener = mock(View.OnHoverListener.class);
- view.setOnHoverListener((v, event) -> {
- // Clone the event to work around event instance reuse in the framework.
- mockListener.onHover(v, MotionEvent.obtain(event));
- return result;
- });
- return mockListener;
- }
-
- public static void clearHoverListener(View view) {
- view.setOnHoverListener(null);
- }
-
- public static MotionEvent obtainMouseEvent(int action, View anchor, int offsetX, int offsetY) {
- final long eventTime = SystemClock.uptimeMillis();
- final int[] screenPos = new int[2];
- anchor.getLocationOnScreen(screenPos);
- final int x = screenPos[0] + offsetX;
- final int y = screenPos[1] + offsetY;
- MotionEvent event = MotionEvent.obtain(eventTime, eventTime, action, x, y, 0);
- event.setSource(InputDevice.SOURCE_MOUSE);
- return event;
- }
-
- /**
- * Emulates a hover move on a point relative to the top-left corner of the passed {@link View}.
- * Offset parameters are used to compute the final screen coordinates of the tap point.
- *
- * @param instrumentation the instrumentation used to run the test
- * @param anchor the anchor view to determine the tap location on the screen
- * @param offsetX extra X offset for the move
- * @param offsetY extra Y offset for the move
- */
- public static void emulateHoverOnView(Instrumentation instrumentation, View anchor, int offsetX,
- int offsetY) {
- final long downTime = SystemClock.uptimeMillis();
- final UiAutomation uiAutomation = instrumentation.getUiAutomation();
- final int[] screenPos = new int[2];
- anchor.getLocationOnScreen(screenPos);
- final int x = screenPos[0] + offsetX;
- final int y = screenPos[1] + offsetY;
-
- injectHoverEvent(uiAutomation, downTime, x, y);
- }
-
- private static void injectHoverEvent(UiAutomation uiAutomation, long downTime, int xOnScreen,
- int yOnScreen) {
- MotionEvent event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_HOVER_MOVE,
- xOnScreen, yOnScreen, 0);
- event.setSource(InputDevice.SOURCE_MOUSE);
- uiAutomation.injectInputEvent(event, true);
- event.recycle();
- }
-
- public static class ActionMatcher implements ArgumentMatcher<MotionEvent> {
- private final int mAction;
-
- public ActionMatcher(int action) {
- mAction = action;
- }
-
- @Override
- public boolean matches(MotionEvent actual) {
- return actual.getAction() == mAction;
- }
-
- @Override
- public String toString() {
- return "action=" + MotionEvent.actionToString(mAction);
- }
- }
-
- public static class PositionMatcher extends ActionMatcher {
- private final int mX;
- private final int mY;
-
- public PositionMatcher(int action, int x, int y) {
- super(action);
- mX = x;
- mY = y;
- }
-
- @Override
- public boolean matches(MotionEvent actual) {
- return super.matches(actual)
- && ((int) actual.getX()) == mX
- && ((int) actual.getY()) == mY;
- }
-
- @Override
- public String toString() {
- return super.toString() + "@(" + mX + "," + mY + ")";
- }
- }
-
- public static void verifyEnterMove(View.OnHoverListener listener, View view, int moveCount) {
- final InOrder inOrder = inOrder(listener);
- verifyEnterMoveInternal(listener, view, moveCount, inOrder);
- inOrder.verifyNoMoreInteractions();
- }
-
- public static void verifyEnterMoveExit(
- View.OnHoverListener listener, View view, int moveCount) {
- final InOrder inOrder = inOrder(listener);
- verifyEnterMoveInternal(listener, view, moveCount, inOrder);
- inOrder.verify(listener, times(1)).onHover(eq(view),
- argThat(new ActionMatcher(MotionEvent.ACTION_HOVER_EXIT)));
- inOrder.verifyNoMoreInteractions();
- }
-
- private static void verifyEnterMoveInternal(
- View.OnHoverListener listener, View view, int moveCount, InOrder inOrder) {
- inOrder.verify(listener, times(1)).onHover(eq(view),
- argThat(new ActionMatcher(MotionEvent.ACTION_HOVER_ENTER)));
- inOrder.verify(listener, times(moveCount)).onHover(eq(view),
- argThat(new ActionMatcher(MotionEvent.ACTION_HOVER_MOVE)));
- }
-}
-
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/CtsTouchUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/CtsTouchUtils.java
deleted file mode 100644
index bd53549..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/CtsTouchUtils.java
+++ /dev/null
@@ -1,614 +0,0 @@
-/*
- * Copyright (C) 2016 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.compatibility.common.util;
-
-import android.app.Instrumentation;
-import android.app.UiAutomation;
-import android.graphics.Point;
-import android.os.SystemClock;
-import android.support.test.rule.ActivityTestRule;
-import android.util.SparseArray;
-import android.view.InputDevice;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-
-/**
- * Test utilities for touch emulation.
- */
-public final class CtsTouchUtils {
- /**
- * Interface definition for a callback to be invoked when an event has been injected.
- */
- public interface EventInjectionListener {
- /**
- * Callback method to be invoked when a {MotionEvent#ACTION_DOWN} has been injected.
- * @param xOnScreen X coordinate of the injected event.
- * @param yOnScreen Y coordinate of the injected event.
- */
- public void onDownInjected(int xOnScreen, int yOnScreen);
-
- /**
- * Callback method to be invoked when a {MotionEvent#ACTION_MOVE} has been injected.
- * @param xOnScreen X coordinates of the injected event.
- * @param yOnScreen Y coordinates of the injected event.
- */
- public void onMoveInjected(int[] xOnScreen, int[] yOnScreen);
-
- /**
- * Callback method to be invoked when a {MotionEvent#ACTION_UP} has been injected.
- * @param xOnScreen X coordinate of the injected event.
- * @param yOnScreen Y coordinate of the injected event.
- */
- public void onUpInjected(int xOnScreen, int yOnScreen);
- }
-
- private CtsTouchUtils() {}
-
- /**
- * Emulates a tap in the center of the passed {@link View}.
- *
- * @param instrumentation the instrumentation used to run the test
- * @param view the view to "tap"
- */
- public static void emulateTapOnViewCenter(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule, View view) {
- emulateTapOnView(instrumentation, activityTestRule, view, view.getWidth() / 2,
- view.getHeight() / 2);
- }
-
- /**
- * Emulates a tap on a point relative to the top-left corner of the passed {@link View}. Offset
- * parameters are used to compute the final screen coordinates of the tap point.
- *
- * @param instrumentation the instrumentation used to run the test
- * @param anchorView the anchor view to determine the tap location on the screen
- * @param offsetX extra X offset for the tap
- * @param offsetY extra Y offset for the tap
- */
- public static void emulateTapOnView(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule, View anchorView,
- int offsetX, int offsetY) {
- final int touchSlop = ViewConfiguration.get(anchorView.getContext()).getScaledTouchSlop();
- // Get anchor coordinates on the screen
- final int[] viewOnScreenXY = new int[2];
- anchorView.getLocationOnScreen(viewOnScreenXY);
- int xOnScreen = viewOnScreenXY[0] + offsetX;
- int yOnScreen = viewOnScreenXY[1] + offsetY;
- final UiAutomation uiAutomation = instrumentation.getUiAutomation();
- final long downTime = SystemClock.uptimeMillis();
-
- injectDownEvent(uiAutomation, downTime, xOnScreen, yOnScreen, null);
- injectMoveEventForTap(uiAutomation, downTime, touchSlop, xOnScreen, yOnScreen);
- injectUpEvent(uiAutomation, downTime, false, xOnScreen, yOnScreen, null);
-
- // Wait for the system to process all events in the queue
- if (activityTestRule != null) {
- WidgetTestUtils.runOnMainAndDrawSync(activityTestRule,
- activityTestRule.getActivity().getWindow().getDecorView(), null);
- } else {
- instrumentation.waitForIdleSync();
- }
- }
-
- /**
- * Emulates a double tap in the center of the passed {@link View}.
- *
- * @param instrumentation the instrumentation used to run the test
- * @param view the view to "double tap"
- */
- public static void emulateDoubleTapOnViewCenter(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule, View view) {
- emulateDoubleTapOnView(instrumentation, activityTestRule, view, view.getWidth() / 2,
- view.getHeight() / 2);
- }
-
- /**
- * Emulates a double tap on a point relative to the top-left corner of the passed {@link View}.
- * Offset parameters are used to compute the final screen coordinates of the tap points.
- *
- * @param instrumentation the instrumentation used to run the test
- * @param anchorView the anchor view to determine the tap location on the screen
- * @param offsetX extra X offset for the taps
- * @param offsetY extra Y offset for the taps
- */
- public static void emulateDoubleTapOnView(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule, View anchorView,
- int offsetX, int offsetY) {
- final int touchSlop = ViewConfiguration.get(anchorView.getContext()).getScaledTouchSlop();
- // Get anchor coordinates on the screen
- final int[] viewOnScreenXY = new int[2];
- anchorView.getLocationOnScreen(viewOnScreenXY);
- int xOnScreen = viewOnScreenXY[0] + offsetX;
- int yOnScreen = viewOnScreenXY[1] + offsetY;
- final UiAutomation uiAutomation = instrumentation.getUiAutomation();
- final long downTime = SystemClock.uptimeMillis();
-
- injectDownEvent(uiAutomation, downTime, xOnScreen, yOnScreen, null);
- injectMoveEventForTap(uiAutomation, downTime, touchSlop, xOnScreen, yOnScreen);
- injectUpEvent(uiAutomation, downTime, false, xOnScreen, yOnScreen, null);
- injectDownEvent(uiAutomation, downTime, xOnScreen, yOnScreen, null);
- injectMoveEventForTap(uiAutomation, downTime, touchSlop, xOnScreen, yOnScreen);
- injectUpEvent(uiAutomation, downTime, false, xOnScreen, yOnScreen, null);
-
- // Wait for the system to process all events in the queue
- if (activityTestRule != null) {
- WidgetTestUtils.runOnMainAndDrawSync(activityTestRule,
- activityTestRule.getActivity().getWindow().getDecorView(), null);
- } else {
- instrumentation.waitForIdleSync();
- }
- }
-
- /**
- * Emulates a linear drag gesture between 2 points across the screen.
- *
- * @param instrumentation the instrumentation used to run the test
- * @param dragStartX Start X of the emulated drag gesture
- * @param dragStartY Start Y of the emulated drag gesture
- * @param dragAmountX X amount of the emulated drag gesture
- * @param dragAmountY Y amount of the emulated drag gesture
- */
- public static void emulateDragGesture(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule,
- int dragStartX, int dragStartY, int dragAmountX, int dragAmountY) {
- emulateDragGesture(instrumentation, activityTestRule,
- dragStartX, dragStartY, dragAmountX, dragAmountY,
- 2000, 20, null);
- }
-
- private static void emulateDragGesture(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule,
- int dragStartX, int dragStartY, int dragAmountX, int dragAmountY,
- int dragDurationMs, int moveEventCount) {
- emulateDragGesture(instrumentation, activityTestRule,
- dragStartX, dragStartY, dragAmountX, dragAmountY,
- dragDurationMs, moveEventCount, null);
- }
-
- private static void emulateDragGesture(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule,
- int dragStartX, int dragStartY, int dragAmountX, int dragAmountY,
- int dragDurationMs, int moveEventCount,
- EventInjectionListener eventInjectionListener) {
- // We are using the UiAutomation object to inject events so that drag works
- // across view / window boundaries (such as for the emulated drag and drop
- // sequences)
- final UiAutomation uiAutomation = instrumentation.getUiAutomation();
- final long downTime = SystemClock.uptimeMillis();
-
- injectDownEvent(uiAutomation, downTime, dragStartX, dragStartY, eventInjectionListener);
-
- // Inject a sequence of MOVE events that emulate the "move" part of the gesture
- injectMoveEventsForDrag(uiAutomation, downTime, true, dragStartX, dragStartY,
- dragStartX + dragAmountX, dragStartY + dragAmountY, moveEventCount, dragDurationMs,
- eventInjectionListener);
-
- injectUpEvent(uiAutomation, downTime, true, dragStartX + dragAmountX,
- dragStartY + dragAmountY, eventInjectionListener);
-
- // Wait for the system to process all events in the queue
- if (activityTestRule != null) {
- WidgetTestUtils.runOnMainAndDrawSync(activityTestRule,
- activityTestRule.getActivity().getWindow().getDecorView(), null);
- } else {
- instrumentation.waitForIdleSync();
- }
- }
-
- /**
- * Emulates a series of linear drag gestures across the screen between multiple points without
- * lifting the finger. Note that this function does not support curve movements between the
- * points.
- *
- * @param instrumentation the instrumentation used to run the test
- * @param coordinates the ordered list of points for the drag gesture
- */
- public static void emulateDragGesture(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule, SparseArray<Point> coordinates) {
- emulateDragGesture(instrumentation, activityTestRule, coordinates, 2000, 20);
- }
-
- private static void emulateDragGesture(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule,
- SparseArray<Point> coordinates, int dragDurationMs, int moveEventCount) {
- final int coordinatesSize = coordinates.size();
- if (coordinatesSize < 2) {
- throw new IllegalArgumentException("Need at least 2 points for emulating drag");
- }
- // We are using the UiAutomation object to inject events so that drag works
- // across view / window boundaries (such as for the emulated drag and drop
- // sequences)
- final UiAutomation uiAutomation = instrumentation.getUiAutomation();
- final long downTime = SystemClock.uptimeMillis();
-
- injectDownEvent(uiAutomation, downTime, coordinates.get(0).x, coordinates.get(0).y, null);
-
- // Move to each coordinate.
- for (int i = 0; i < coordinatesSize - 1; i++) {
- // Inject a sequence of MOVE events that emulate the "move" part of the gesture.
- injectMoveEventsForDrag(uiAutomation,
- downTime,
- true,
- coordinates.get(i).x,
- coordinates.get(i).y,
- coordinates.get(i + 1).x,
- coordinates.get(i + 1).y,
- moveEventCount,
- dragDurationMs,
- null);
- }
-
- injectUpEvent(uiAutomation,
- downTime,
- true,
- coordinates.get(coordinatesSize - 1).x,
- coordinates.get(coordinatesSize - 1).y,
- null);
-
- // Wait for the system to process all events in the queue
- if (activityTestRule != null) {
- WidgetTestUtils.runOnMainAndDrawSync(activityTestRule,
- activityTestRule.getActivity().getWindow().getDecorView(), null);
- } else {
- instrumentation.waitForIdleSync();
- }
- }
-
- private static long injectDownEvent(UiAutomation uiAutomation, long downTime, int xOnScreen,
- int yOnScreen, EventInjectionListener eventInjectionListener) {
- MotionEvent eventDown = MotionEvent.obtain(
- downTime, downTime, MotionEvent.ACTION_DOWN, xOnScreen, yOnScreen, 1);
- eventDown.setSource(InputDevice.SOURCE_TOUCHSCREEN);
- uiAutomation.injectInputEvent(eventDown, true);
- if (eventInjectionListener != null) {
- eventInjectionListener.onDownInjected(xOnScreen, yOnScreen);
- }
- eventDown.recycle();
- return downTime;
- }
-
- private static void injectMoveEventForTap(UiAutomation uiAutomation, long downTime,
- int touchSlop, int xOnScreen, int yOnScreen) {
- MotionEvent eventMove = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_MOVE,
- xOnScreen + (touchSlop / 2.0f), yOnScreen + (touchSlop / 2.0f), 1);
- eventMove.setSource(InputDevice.SOURCE_TOUCHSCREEN);
- uiAutomation.injectInputEvent(eventMove, true);
- eventMove.recycle();
- }
-
- private static void injectMoveEventsForDrag(UiAutomation uiAutomation, long downTime,
- boolean useCurrentEventTime, int dragStartX, int dragStartY, int dragEndX, int dragEndY,
- int moveEventCount, int dragDurationMs, EventInjectionListener eventInjectionListener) {
- final int dragAmountX = dragEndX - dragStartX;
- final int dragAmountY = dragEndY - dragStartY;
- final int sleepTime = dragDurationMs / moveEventCount;
-
- // sleep for a bit to emulate the overall drag gesture.
- long prevEventTime = downTime;
- SystemClock.sleep(sleepTime);
- for (int i = 0; i < moveEventCount; i++) {
- // Note that the first MOVE event is generated "away" from the coordinates
- // of the start / DOWN event, and the last MOVE event is generated
- // at the same coordinates as the subsequent UP event.
- final int moveX = dragStartX + dragAmountX * (i + 1) / moveEventCount;
- final int moveY = dragStartY + dragAmountY * (i + 1) / moveEventCount;
- long eventTime = useCurrentEventTime ? SystemClock.uptimeMillis() : downTime;
-
- // If necessary, generate history for our next MOVE event. The history is generated
- // to be spaced at 10 millisecond intervals, interpolating the coordinates from the
- // last generated MOVE event to our current one.
- int historyEventCount = (int) ((eventTime - prevEventTime) / 10);
- int[] xCoordsForListener = (eventInjectionListener == null) ? null :
- new int[Math.max(1, historyEventCount)];
- int[] yCoordsForListener = (eventInjectionListener == null) ? null :
- new int[Math.max(1, historyEventCount)];
- MotionEvent eventMove = null;
- if (historyEventCount == 0) {
- eventMove = MotionEvent.obtain(
- downTime, eventTime, MotionEvent.ACTION_MOVE, moveX, moveY, 1);
- if (eventInjectionListener != null) {
- xCoordsForListener[0] = moveX;
- yCoordsForListener[0] = moveY;
- }
- } else {
- final int prevMoveX = dragStartX + dragAmountX * i / moveEventCount;
- final int prevMoveY = dragStartY + dragAmountY * i / moveEventCount;
- final int deltaMoveX = moveX - prevMoveX;
- final int deltaMoveY = moveY - prevMoveY;
- final long deltaTime = (eventTime - prevEventTime);
- for (int historyIndex = 0; historyIndex < historyEventCount; historyIndex++) {
- int stepMoveX = prevMoveX + deltaMoveX * (historyIndex + 1) / historyEventCount;
- int stepMoveY = prevMoveY + deltaMoveY * (historyIndex + 1) / historyEventCount;
- long stepEventTime = useCurrentEventTime
- ? prevEventTime + deltaTime * (historyIndex + 1) / historyEventCount
- : downTime;
- if (historyIndex == 0) {
- // Generate the first event in our sequence
- eventMove = MotionEvent.obtain(downTime, stepEventTime,
- MotionEvent.ACTION_MOVE, stepMoveX, stepMoveY, 1);
- } else {
- // and then add to it
- eventMove.addBatch(stepEventTime, stepMoveX, stepMoveY, 1.0f, 1.0f, 1);
- }
- if (eventInjectionListener != null) {
- xCoordsForListener[historyIndex] = stepMoveX;
- yCoordsForListener[historyIndex] = stepMoveY;
- }
- }
- }
-
- eventMove.setSource(InputDevice.SOURCE_TOUCHSCREEN);
- uiAutomation.injectInputEvent(eventMove, true);
- if (eventInjectionListener != null) {
- eventInjectionListener.onMoveInjected(xCoordsForListener, yCoordsForListener);
- }
- eventMove.recycle();
- prevEventTime = eventTime;
-
- // sleep for a bit to emulate the overall drag gesture.
- SystemClock.sleep(sleepTime);
- }
- }
-
- private static void injectUpEvent(UiAutomation uiAutomation, long downTime,
- boolean useCurrentEventTime, int xOnScreen, int yOnScreen,
- EventInjectionListener eventInjectionListener) {
- long eventTime = useCurrentEventTime ? SystemClock.uptimeMillis() : downTime;
- MotionEvent eventUp = MotionEvent.obtain(
- downTime, eventTime, MotionEvent.ACTION_UP, xOnScreen, yOnScreen, 1);
- eventUp.setSource(InputDevice.SOURCE_TOUCHSCREEN);
- uiAutomation.injectInputEvent(eventUp, true);
- if (eventInjectionListener != null) {
- eventInjectionListener.onUpInjected(xOnScreen, yOnScreen);
- }
- eventUp.recycle();
- }
-
- /**
- * Emulates a fling gesture across the horizontal center of the passed view.
- *
- * @param instrumentation the instrumentation used to run the test
- * @param view the view to fling
- * @param isDownwardsFlingGesture if <code>true</code>, the emulated fling will
- * be a downwards gesture
- * @return The vertical amount of emulated fling in pixels
- */
- public static int emulateFlingGesture(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule, View view, boolean isDownwardsFlingGesture) {
- return emulateFlingGesture(instrumentation, activityTestRule,
- view, isDownwardsFlingGesture, null);
- }
-
- /**
- * Emulates a fling gesture across the horizontal center of the passed view.
- *
- * @param instrumentation the instrumentation used to run the test
- * @param view the view to fling
- * @param isDownwardsFlingGesture if <code>true</code>, the emulated fling will
- * be a downwards gesture
- * @param eventInjectionListener optional listener to notify about the injected events
- * @return The vertical amount of emulated fling in pixels
- */
- public static int emulateFlingGesture(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule, View view, boolean isDownwardsFlingGesture,
- EventInjectionListener eventInjectionListener) {
- final ViewConfiguration configuration = ViewConfiguration.get(view.getContext());
- final int flingVelocity = (configuration.getScaledMinimumFlingVelocity() +
- configuration.getScaledMaximumFlingVelocity()) / 2;
- // Get view coordinates on the screen
- final int[] viewOnScreenXY = new int[2];
- view.getLocationOnScreen(viewOnScreenXY);
-
- // Our fling gesture will be from 25% height of the view to 75% height of the view
- // for downwards fling gesture, and the other way around for upwards fling gesture
- final int viewHeight = view.getHeight();
- final int x = viewOnScreenXY[0] + view.getWidth() / 2;
- final int startY = isDownwardsFlingGesture ? viewOnScreenXY[1] + viewHeight / 4
- : viewOnScreenXY[1] + 3 * viewHeight / 4;
- final int amountY = isDownwardsFlingGesture ? viewHeight / 2 : -viewHeight / 2;
-
- // Compute fling gesture duration based on the distance (50% height of the view) and
- // fling velocity
- final int durationMs = (1000 * viewHeight) / (2 * flingVelocity);
-
- // And do the same event injection sequence as our generic drag gesture
- emulateDragGesture(instrumentation, activityTestRule,
- x, startY, 0, amountY, durationMs, durationMs / 16,
- eventInjectionListener);
-
- return amountY;
- }
-
- private static class ViewStateSnapshot {
- final View mFirst;
- final View mLast;
- final int mFirstTop;
- final int mLastBottom;
- final int mChildCount;
- private ViewStateSnapshot(ViewGroup viewGroup) {
- mChildCount = viewGroup.getChildCount();
- if (mChildCount == 0) {
- mFirst = mLast = null;
- mFirstTop = mLastBottom = Integer.MIN_VALUE;
- } else {
- mFirst = viewGroup.getChildAt(0);
- mLast = viewGroup.getChildAt(mChildCount - 1);
- mFirstTop = mFirst.getTop();
- mLastBottom = mLast.getBottom();
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- final ViewStateSnapshot that = (ViewStateSnapshot) o;
- return mFirstTop == that.mFirstTop &&
- mLastBottom == that.mLastBottom &&
- mFirst == that.mFirst &&
- mLast == that.mLast &&
- mChildCount == that.mChildCount;
- }
-
- @Override
- public int hashCode() {
- int result = mFirst != null ? mFirst.hashCode() : 0;
- result = 31 * result + (mLast != null ? mLast.hashCode() : 0);
- result = 31 * result + mFirstTop;
- result = 31 * result + mLastBottom;
- result = 31 * result + mChildCount;
- return result;
- }
- }
-
- /**
- * Emulates a scroll to the bottom of the specified {@link ViewGroup}.
- *
- * @param instrumentation the instrumentation used to run the test
- * @param viewGroup View group
- */
- public static void emulateScrollToBottom(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule, ViewGroup viewGroup) {
- final int[] viewGroupOnScreenXY = new int[2];
- viewGroup.getLocationOnScreen(viewGroupOnScreenXY);
-
- final int emulatedX = viewGroupOnScreenXY[0] + viewGroup.getWidth() / 2;
- final int emulatedStartY = viewGroupOnScreenXY[1] + 3 * viewGroup.getHeight() / 4;
- final int swipeAmount = viewGroup.getHeight() / 2;
-
- ViewStateSnapshot prev;
- ViewStateSnapshot next = new ViewStateSnapshot(viewGroup);
- do {
- prev = next;
- emulateDragGesture(instrumentation, activityTestRule,
- emulatedX, emulatedStartY, 0, -swipeAmount, 300, 10);
- next = new ViewStateSnapshot(viewGroup);
- } while (!prev.equals(next));
- }
-
- /**
- * Emulates a long press in the center of the passed {@link View}.
- *
- * @param instrumentation the instrumentation used to run the test
- * @param view the view to "long press"
- */
- public static void emulateLongPressOnViewCenter(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule, View view) {
- emulateLongPressOnViewCenter(instrumentation, activityTestRule, view, 0);
- }
-
- /**
- * Emulates a long press in the center of the passed {@link View}.
- *
- * @param instrumentation the instrumentation used to run the test
- * @param view the view to "long press"
- * @param extraWaitMs the duration of emulated "long press" in milliseconds starting
- * after system-level long press timeout.
- */
- public static void emulateLongPressOnViewCenter(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule, View view, long extraWaitMs) {
- final int touchSlop = ViewConfiguration.get(view.getContext()).getScaledTouchSlop();
- // Use instrumentation to emulate a tap on the spinner to bring down its popup
- final int[] viewOnScreenXY = new int[2];
- view.getLocationOnScreen(viewOnScreenXY);
- int xOnScreen = viewOnScreenXY[0] + view.getWidth() / 2;
- int yOnScreen = viewOnScreenXY[1] + view.getHeight() / 2;
-
- emulateLongPressOnScreen(instrumentation, activityTestRule,
- xOnScreen, yOnScreen, touchSlop, extraWaitMs, true);
- }
-
- /**
- * Emulates a long press confirmed on a point relative to the top-left corner of the passed
- * {@link View}. Offset parameters are used to compute the final screen coordinates of the
- * press point.
- *
- * @param instrumentation the instrumentation used to run the test
- * @param view the view to "long press"
- * @param offsetX extra X offset for the tap
- * @param offsetY extra Y offset for the tap
- */
- public static void emulateLongPressOnView(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule, View view, int offsetX, int offsetY) {
- final int touchSlop = ViewConfiguration.get(view.getContext()).getScaledTouchSlop();
- final int[] viewOnScreenXY = new int[2];
- view.getLocationOnScreen(viewOnScreenXY);
- int xOnScreen = viewOnScreenXY[0] + offsetX;
- int yOnScreen = viewOnScreenXY[1] + offsetY;
-
- emulateLongPressOnScreen(instrumentation, activityTestRule,
- xOnScreen, yOnScreen, touchSlop, 0, true);
- }
-
- /**
- * Emulates a long press then a linear drag gesture between 2 points across the screen.
- * This is used for drag selection.
- *
- * @param instrumentation the instrumentation used to run the test
- * @param dragStartX Start X of the emulated drag gesture
- * @param dragStartY Start Y of the emulated drag gesture
- * @param dragAmountX X amount of the emulated drag gesture
- * @param dragAmountY Y amount of the emulated drag gesture
- */
- public static void emulateLongPressAndDragGesture(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule,
- int dragStartX, int dragStartY, int dragAmountX, int dragAmountY) {
- emulateLongPressOnScreen(instrumentation, activityTestRule, dragStartX, dragStartY,
- 0 /* touchSlop */, 0 /* extraWaitMs */, false /* upGesture */);
- emulateDragGesture(instrumentation, activityTestRule, dragStartX, dragStartY, dragAmountX,
- dragAmountY);
- }
-
- /**
- * Emulates a long press on the screen.
- *
- * @param instrumentation the instrumentation used to run the test
- * @param xOnScreen X position on screen for the "long press"
- * @param yOnScreen Y position on screen for the "long press"
- * @param extraWaitMs extra duration of emulated long press in milliseconds added
- * after the system-level "long press" timeout.
- * @param upGesture whether to include an up event.
- */
- private static void emulateLongPressOnScreen(Instrumentation instrumentation,
- ActivityTestRule<?> activityTestRule,
- int xOnScreen, int yOnScreen, int touchSlop, long extraWaitMs, boolean upGesture) {
- final UiAutomation uiAutomation = instrumentation.getUiAutomation();
- final long downTime = SystemClock.uptimeMillis();
-
- injectDownEvent(uiAutomation, downTime, xOnScreen, yOnScreen, null);
- injectMoveEventForTap(uiAutomation, downTime, touchSlop, xOnScreen, yOnScreen);
- SystemClock.sleep((long) (ViewConfiguration.getLongPressTimeout() * 1.5f) + extraWaitMs);
- if (upGesture) {
- injectUpEvent(uiAutomation, downTime, false, xOnScreen, yOnScreen, null);
- }
-
- // Wait for the system to process all events in the queue
- if (activityTestRule != null) {
- WidgetTestUtils.runOnMainAndDrawSync(activityTestRule,
- activityTestRule.getActivity().getWindow().getDecorView(), null);
- } else {
- instrumentation.waitForIdleSync();
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DeviceConfigStateChangerRule.java b/common/device-side/util/src/com/android/compatibility/common/util/DeviceConfigStateChangerRule.java
deleted file mode 100644
index a13da52..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/DeviceConfigStateChangerRule.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.util;
-
-import android.content.Context;
-import android.provider.DeviceConfig;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-/**
- * JUnit rule used to set a {@link DeviceConfig} preference before the test is run.
- *
- * <p>It stores the current value before the test, changes it (if necessary), then restores it after
- * the test (if necessary).
- */
-public class DeviceConfigStateChangerRule extends StateChangerRule<String> {
-
- /**
- * Default constructor.
- *
- * @param context context used to retrieve the {@link DeviceConfig} provider.
- * @param namespace {@code DeviceConfig} namespace.
- * @param key prefence key.
- * @param value value to be set before the test is run.
- */
- public DeviceConfigStateChangerRule(@NonNull Context context, @NonNull String namespace,
- @NonNull String key, @Nullable String value) {
- this(new DeviceConfigStateManager(context, namespace, key), value);
- }
-
- /**
- * Alternative constructor used when then test case already defines a
- * {@link DeviceConfigStateManager}.
- */
- public DeviceConfigStateChangerRule(@NonNull DeviceConfigStateManager dcsm,
- @Nullable String value) {
- super(dcsm, value);
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DeviceConfigStateKeeperRule.java b/common/device-side/util/src/com/android/compatibility/common/util/DeviceConfigStateKeeperRule.java
deleted file mode 100644
index 6f186de..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/DeviceConfigStateKeeperRule.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.util;
-
-import android.content.Context;
-import android.provider.DeviceConfig;
-
-import androidx.annotation.NonNull;
-
-/**
- * JUnit rule used to restore a {@link DeviceConfig} preference after the test is run.
- *
- * <p>It stores the current value before the test, and restores it after the test (if necessary).
- */
-public class DeviceConfigStateKeeperRule extends StateKeeperRule<String> {
-
- /**
- * Default constructor.
- *
- * @param context context used to retrieve the {@link DeviceConfig} provider.
- * @param namespace {@code DeviceConfig} namespace.
- * @param key prefence key.
- */
- public DeviceConfigStateKeeperRule(@NonNull Context context, @NonNull String namespace,
- @NonNull String key) {
- super(new DeviceConfigStateManager(context, namespace, key));
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DeviceConfigStateManager.java b/common/device-side/util/src/com/android/compatibility/common/util/DeviceConfigStateManager.java
deleted file mode 100644
index c85fc1b..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/DeviceConfigStateManager.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
-
-import android.content.Context;
-import android.provider.DeviceConfig;
-import android.provider.Settings;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.google.common.base.Preconditions;
-
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Manages the state of a preference backed by {@link DeviceConfig}.
- */
-public final class DeviceConfigStateManager implements StateManager<String> {
-
- private static final String TAG = DeviceConfigStateManager.class.getSimpleName();
-
- private final Context mContext;
- private final String mNamespace;
- private final String mKey;
-
- /**
- * Default constructor.
- *
- * @param context context used to retrieve the {@link Settings} provider.
- * @param namespace settings namespace.
- * @param key prefence key.
- */
- public DeviceConfigStateManager(@NonNull Context context, @NonNull String namespace,
- @NonNull String key) {
- debug("DeviceConfigStateManager", "namespace=%s, key=%s", namespace, key);
-
- mContext = Preconditions.checkNotNull(context);
- mNamespace = Preconditions.checkNotNull(namespace);
- mKey = Preconditions.checkNotNull(key);
- }
-
- @Override
- public void set(@Nullable String value) {
- debug("set", value);
- runWithShellPermissionIdentity(() -> setWithPermissionsGranted(value),
- "android.permission.READ_DEVICE_CONFIG", "android.permission.WRITE_DEVICE_CONFIG");
- }
-
- private void setWithPermissionsGranted(@Nullable String value) {
- final OneTimeDeviceConfigListener listener = new OneTimeDeviceConfigListener(mNamespace,
- mKey);
- DeviceConfig.addOnPropertiesChangedListener(mNamespace, mContext.getMainExecutor(),
- listener);
-
- DeviceConfig.setProperty(mNamespace, mKey, value, /* makeDefault= */ false);
- listener.assertCalled();
- }
-
- @Override
- @Nullable
- public String get() {
- final AtomicReference<String> reference = new AtomicReference<>();
- runWithShellPermissionIdentity(()
- -> reference.set(DeviceConfig.getProperty(mNamespace, mKey)),
- "android.permission.READ_DEVICE_CONFIG");
- debug("get", reference.get());
-
- return reference.get();
- }
-
- private void debug(@NonNull String methodName, @NonNull String msg, Object...args) {
- if (!Log.isLoggable(TAG, Log.DEBUG)) return;
-
- final String prefix = String.format("%s(%s:%s): ", methodName, mNamespace, mKey);
- Log.d(TAG, prefix + String.format(msg, args));
- }
-
- @Override
- public String toString() {
- return "DeviceConfigStateManager[namespace=" + mNamespace + ", key=" + mKey + "]";
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DeviceInfoStore.java b/common/device-side/util/src/com/android/compatibility/common/util/DeviceInfoStore.java
deleted file mode 100644
index 03f69fa..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/DeviceInfoStore.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2016 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.compatibility.common.util;
-
-import android.util.JsonWriter;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.List;
-
-public class DeviceInfoStore extends InfoStore {
-
- protected File mJsonFile;
- protected JsonWriter mJsonWriter = null;
-
- public DeviceInfoStore() {
- mJsonFile = null;
- }
-
- public DeviceInfoStore(File file) throws Exception {
- mJsonFile = file;
- }
-
- /**
- * Opens the file for storage and creates the writer.
- */
- @Override
- public void open() throws IOException {
- FileOutputStream out = new FileOutputStream(mJsonFile);
- mJsonWriter = new JsonWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
- // TODO(agathaman): remove to make json output less pretty
- mJsonWriter.setIndent(" ");
- mJsonWriter.beginObject();
- }
-
- /**
- * Closes the writer.
- */
- @Override
- public void close() throws Exception {
- mJsonWriter.endObject();
- mJsonWriter.flush();
- mJsonWriter.close();
- }
-
- /**
- * Start a new group of result.
- */
- @Override
- public void startGroup() throws IOException {
- mJsonWriter.beginObject();
- }
-
- /**
- * Start a new group of result with specified name.
- */
- @Override
- public void startGroup(String name) throws IOException {
- mJsonWriter.name(name);
- mJsonWriter.beginObject();
- }
-
- /**
- * Complete adding result to the last started group.
- */
- @Override
- public void endGroup() throws IOException {
- mJsonWriter.endObject();
- }
-
- /**
- * Start a new array of result.
- */
- @Override
- public void startArray() throws IOException {
- mJsonWriter.beginArray();
- }
-
- /**
- * Start a new array of result with specified name.
- */
- @Override
- public void startArray(String name) throws IOException {
- checkName(name);
- mJsonWriter.name(name);
- mJsonWriter.beginArray();
- }
-
- /**
- * Complete adding result to the last started array.
- */
- @Override
- public void endArray() throws IOException {
- mJsonWriter.endArray();
- }
-
- /**
- * Adds a int value to the InfoStore
- */
- @Override
- public void addResult(String name, int value) throws IOException {
- checkName(name);
- mJsonWriter.name(name);
- mJsonWriter.value(value);
- }
-
- /**
- * Adds a long value to the InfoStore
- */
- @Override
- public void addResult(String name, long value) throws IOException {
- checkName(name);
- mJsonWriter.name(name);
- mJsonWriter.value(value);
- }
-
- /**
- * Adds a float value to the InfoStore
- */
- @Override
- public void addResult(String name, float value) throws IOException {
- addResult(name, (double) value);
- }
-
- /**
- * Adds a double value to the InfoStore
- */
- @Override
- public void addResult(String name, double value) throws IOException {
- checkName(name);
- if (isDoubleNaNOrInfinite(value)) {
- return;
- } else {
- mJsonWriter.name(name);
- mJsonWriter.value(value);
- }
- }
-
- /**
- * Adds a boolean value to the InfoStore
- */
- @Override
- public void addResult(String name, boolean value) throws IOException {
- checkName(name);
- mJsonWriter.name(name);
- mJsonWriter.value(value);
- }
-
- /**
- * Adds a String value to the InfoStore
- */
- @Override
- public void addResult(String name, String value) throws IOException {
- checkName(name);
- mJsonWriter.name(name);
- mJsonWriter.value(checkString(value));
- }
-
- /**
- * Adds a int array to the InfoStore
- */
- @Override
- public void addArrayResult(String name, int[] array) throws IOException {
- checkName(name);
- mJsonWriter.name(name);
- mJsonWriter.beginArray();
- for (int value : checkArray(array)) {
- mJsonWriter.value(value);
- }
- mJsonWriter.endArray();
- }
-
- /**
- * Adds a long array to the InfoStore
- */
- @Override
- public void addArrayResult(String name, long[] array) throws IOException {
- checkName(name);
- mJsonWriter.name(name);
- mJsonWriter.beginArray();
- for (long value : checkArray(array)) {
- mJsonWriter.value(value);
- }
- mJsonWriter.endArray();
- }
-
- /**
- * Adds a float array to the InfoStore
- */
- @Override
- public void addArrayResult(String name, float[] array) throws IOException {
- double[] doubleArray = new double[array.length];
- for (int i = 0; i < array.length; i++) {
- doubleArray[i] = array[i];
- }
- addArrayResult(name, doubleArray);
- }
-
- /**
- * Adds a double array to the InfoStore
- */
- @Override
- public void addArrayResult(String name, double[] array) throws IOException {
- checkName(name);
- mJsonWriter.name(name);
- mJsonWriter.beginArray();
- for (double value : checkArray(array)) {
- if (isDoubleNaNOrInfinite(value)) {
- continue;
- }
- mJsonWriter.value(value);
- }
- mJsonWriter.endArray();
- }
-
- /**
- * Adds a boolean array to the InfoStore
- */
- @Override
- public void addArrayResult(String name, boolean[] array) throws IOException {
- checkName(name);
- mJsonWriter.name(name);
- mJsonWriter.beginArray();
- for (boolean value : checkArray(array)) {
- mJsonWriter.value(value);
- }
- mJsonWriter.endArray();
- }
-
- /**
- * Adds a List of String to the InfoStore
- */
- @Override
- public void addListResult(String name, List<String> list) throws IOException {
- checkName(name);
- mJsonWriter.name(name);
- mJsonWriter.beginArray();
- for (String value : checkStringList(list)) {
- mJsonWriter.value(checkString(value));
- }
- mJsonWriter.endArray();
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java b/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
deleted file mode 100644
index 12c9f1a..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (C) 2014 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.compatibility.common.util;
-
-import android.app.Instrumentation;
-import android.os.Bundle;
-import android.os.Environment;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Handles adding results to the report for device side tests.
- *
- * NOTE: tests MUST call {@link #submit(Instrumentation)} if and only if the test passes in order to
- * send the results to the runner.
- */
-public class DeviceReportLog extends ReportLog {
- private static final String TAG = DeviceReportLog.class.getSimpleName();
- private static final String RESULT = "COMPATIBILITY_TEST_RESULT";
- private static final int INST_STATUS_ERROR = -1;
- private static final int INST_STATUS_IN_PROGRESS = 2;
-
- private ReportLogDeviceInfoStore store;
-
- public DeviceReportLog(String reportLogName, String streamName) {
- this(reportLogName, streamName, new File(InstrumentationRegistry
- .getInstrumentation().getTargetContext()
- .getExternalFilesDir(null).getPath(),
- "report-log-files"));
- }
-
- public DeviceReportLog(String reportLogName, String streamName, File logDirectory) {
- super(reportLogName, streamName);
- try {
- // dir value must match the src-dir value configured in ReportLogCollector target
- // preparer in cts/harness/tools/cts-tradefed/res/config/cts-preconditions.xml
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- throw new IOException("External storage is not mounted");
- } else if ((!logDirectory.exists() && !logDirectory.mkdirs())
- || (logDirectory.exists() && !logDirectory.isDirectory())) {
- throw new IOException("Cannot create directory for device info files");
- } else {
- File jsonFile = new File(logDirectory, mReportLogName + ".reportlog.json");
- store = new ReportLogDeviceInfoStore(jsonFile, mStreamName);
- store.open();
- }
- } catch (Exception e) {
- Log.e(TAG, "Could not create report log file.", e);
- }
- }
-
- /**
- * Adds a double metric to the report.
- */
- @Override
- public void addValue(String source, String message, double value, ResultType type,
- ResultUnit unit) {
- super.addValue(source, message, value, type, unit);
- try {
- store.addResult(message, value);
- } catch (Exception e) {
- Log.e(TAG, "Could not log metric.", e);
- }
- }
-
- /**
- * Adds a double metric to the report.
- */
- @Override
- public void addValue(String message, double value, ResultType type, ResultUnit unit) {
- super.addValue(message, value, type, unit);
- try {
- store.addResult(message, value);
- } catch (Exception e) {
- Log.e(TAG, "Could not log metric.", e);
- }
- }
-
- /**
- * Adds a double array of metrics to the report.
- */
- @Override
- public void addValues(String source, String message, double[] values, ResultType type,
- ResultUnit unit) {
- super.addValues(source, message, values, type, unit);
- try {
- store.addArrayResult(message, values);
- } catch (Exception e) {
- Log.e(TAG, "Could not log metric.", e);
- }
- }
-
- /**
- * Adds a double array of metrics to the report.
- */
- @Override
- public void addValues(String message, double[] values, ResultType type, ResultUnit unit) {
- super.addValues(message, values, type, unit);
- try {
- store.addArrayResult(message, values);
- } catch (Exception e) {
- Log.e(TAG, "Could not log metric.", e);
- }
- }
-
- /**
- * Adds an int metric to the report.
- */
- @Override
- public void addValue(String message, int value, ResultType type, ResultUnit unit) {
- try {
- store.addResult(message, value);
- } catch (Exception e) {
- Log.e(TAG, "Could not log metric.", e);
- }
- }
-
- /**
- * Adds a long metric to the report.
- */
- @Override
- public void addValue(String message, long value, ResultType type, ResultUnit unit) {
- try {
- store.addResult(message, value);
- } catch (Exception e) {
- Log.e(TAG, "Could not log metric.", e);
- }
- }
-
- /**
- * Adds a float metric to the report.
- */
- @Override
- public void addValue(String message, float value, ResultType type, ResultUnit unit) {
- try {
- store.addResult(message, value);
- } catch (Exception e) {
- Log.e(TAG, "Could not log metric.", e);
- }
- }
-
- /**
- * Adds a boolean metric to the report.
- */
- @Override
- public void addValue(String message, boolean value, ResultType type, ResultUnit unit) {
- try {
- store.addResult(message, value);
- } catch (Exception e) {
- Log.e(TAG, "Could not log metric.", e);
- }
- }
-
- /**
- * Adds a String metric to the report.
- */
- @Override
- public void addValue(String message, String value, ResultType type, ResultUnit unit) {
- try {
- store.addResult(message, value);
- } catch (Exception e) {
- Log.e(TAG, "Could not log metric.", e);
- }
- }
-
- /**
- * Adds an int array of metrics to the report.
- */
- @Override
- public void addValues(String message, int[] values, ResultType type, ResultUnit unit) {
- try {
- store.addArrayResult(message, values);
- } catch (Exception e) {
- Log.e(TAG, "Could not log metric.", e);
- }
- }
-
- /**
- * Adds a long array of metrics to the report.
- */
- @Override
- public void addValues(String message, long[] values, ResultType type, ResultUnit unit) {
- try {
- store.addArrayResult(message, values);
- } catch (Exception e) {
- Log.e(TAG, "Could not log metric.", e);
- }
- }
-
- /**
- * Adds a float array of metrics to the report.
- */
- @Override
- public void addValues(String message, float[] values, ResultType type, ResultUnit unit) {
- try {
- store.addArrayResult(message, values);
- } catch (Exception e) {
- Log.e(TAG, "Could not log metric.", e);
- }
- }
-
- /**
- * Adds a boolean array of metrics to the report.
- */
- @Override
- public void addValues(String message, boolean[] values, ResultType type, ResultUnit unit) {
- try {
- store.addArrayResult(message, values);
- } catch (Exception e) {
- Log.e(TAG, "Could not log metric.", e);
- }
- }
-
- /**
- * Adds a String List of metrics to the report.
- */
- @Override
- public void addValues(String message, List<String> values, ResultType type, ResultUnit unit) {
- try {
- store.addListResult(message, values);
- } catch (Exception e) {
- Log.e(TAG, "Could not log metric.", e);
- }
- }
-
- /**
- * Sets the summary double metric of the report.
- *
- * NOTE: messages over {@value Metric#MAX_MESSAGE_LENGTH} chars will be trimmed.
- */
- @Override
- public void setSummary(String message, double value, ResultType type, ResultUnit unit) {
- super.setSummary(message, value, type, unit);
- try {
- store.addResult(message, value);
- } catch (Exception e) {
- Log.e(TAG, "Could not log metric.", e);
- }
- }
-
- /**
- * Closes report file and submits report to instrumentation.
- */
- public void submit(Instrumentation instrumentation) {
- try {
- store.close();
- Bundle output = new Bundle();
- output.putString(RESULT, serialize(this));
- instrumentation.sendStatus(INST_STATUS_IN_PROGRESS, output);
- } catch (Exception e) {
- Log.e(TAG, "ReportLog Submit Failed", e);
- instrumentation.sendStatus(INST_STATUS_ERROR, null);
- }
- }
-
- /**
- * Closes report file. Static functions that do not have access to instrumentation can
- * use this to close report logs. Summary, if present, is not reported to instrumentation, hence
- * does not appear in the result XML.
- */
- public void submit() {
- try {
- store.close();
- } catch (Exception e) {
- Log.e(TAG, "ReportLog Submit Failed", e);
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DoubleVisitor.java b/common/device-side/util/src/com/android/compatibility/common/util/DoubleVisitor.java
deleted file mode 100644
index 96fb3bb..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/DoubleVisitor.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import androidx.annotation.NonNull;
-
-/**
- * Implements the Visitor design pattern to visit 2 related objects (like a view and the activity
- * hosting it).
- *
- * @param <V1> 1st visited object
- * @param <V2> 2nd visited object
- */
-public interface DoubleVisitor<V1, V2> {
-
- /**
- * Visit those objects.
- */
- void visit(@NonNull V1 visited1, @NonNull V2 visited2);
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DummyActivity.java b/common/device-side/util/src/com/android/compatibility/common/util/DummyActivity.java
deleted file mode 100644
index 672106c..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/DummyActivity.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2013 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.compatibility.common.util;
-
-import android.app.Activity;
-
-public class DummyActivity extends Activity {
-
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DynamicConfigDeviceSide.java b/common/device-side/util/src/com/android/compatibility/common/util/DynamicConfigDeviceSide.java
deleted file mode 100644
index 0e443fb..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/DynamicConfigDeviceSide.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2015 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.compatibility.common.util;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.net.Uri;
-import android.os.Environment;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import android.support.test.InstrumentationRegistry;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.FileNotFoundException;
-
-/**
- * Load dynamic config for device side test cases
- */
-public class DynamicConfigDeviceSide extends DynamicConfig {
-
- public static final String CONTENT_PROVIDER =
- String.format("%s://android.tradefed.contentprovider", ContentResolver.SCHEME_CONTENT);
-
- public DynamicConfigDeviceSide(String moduleName) throws XmlPullParserException, IOException {
- this(moduleName, new File(CONFIG_FOLDER_ON_DEVICE));
- }
-
- public DynamicConfigDeviceSide(String moduleName, File configFolder)
- throws XmlPullParserException, IOException {
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- throw new IOException("External storage is not mounted");
- }
- // Use the content provider to get the config:
- String uriPath = String.format("%s/%s/%s.dynamic", CONTENT_PROVIDER, configFolder.getAbsolutePath(), moduleName);
- Uri sdcardUri = Uri.parse(uriPath);
- Context appContext = InstrumentationRegistry.getTargetContext();
- try {
- ContentResolver resolver = appContext.getContentResolver();
- ParcelFileDescriptor descriptor = resolver.openFileDescriptor(sdcardUri,"r");
-
- initializeConfig(new ParcelFileDescriptor.AutoCloseInputStream(descriptor));
- return;
- } catch (FileNotFoundException e) {
- // Log the error and use the fallback too
- Log.e("DynamicConfigDeviceSide", "Error while using content provider for config", e);
- }
- // Fallback to the direct search
- File configFile = getConfigFile(configFolder, moduleName);
- initializeConfig(configFile);
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/FakeKeys.java b/common/device-side/util/src/com/android/compatibility/common/util/FakeKeys.java
deleted file mode 100644
index 85e06ea..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/FakeKeys.java
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * Copyright (C) 2014 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.compatibility.common.util;
-
-// Copied from cts/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
-
-public class FakeKeys {
- /*
- * The keys and certificates below are generated with:
- *
- * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem
- * openssl req -newkey rsa:1024 -keyout userkey.pem -nodes -days 3650 -out userkey.req
- * mkdir -p demoCA/newcerts
- * touch demoCA/index.txt
- * echo "01" > demoCA/serial
- * openssl ca -out usercert.pem -in userkey.req -cert cacert.pem -keyfile cakey.pem -days 3650
- */
- public static class FAKE_RSA_1 {
- /**
- * Generated from above and converted with:
- *
- * openssl pkcs8 -topk8 -outform d -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g'
- */
- public static final byte[] privateKey = {
- (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x02, (byte) 0x01,
- (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a,
- (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01,
- (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82,
- (byte) 0x02, (byte) 0x62, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5e,
- (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81,
- (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, (byte) 0x5b,
- (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, (byte) 0x66,
- (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, (byte) 0x8a,
- (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, (byte) 0x02,
- (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, (byte) 0xf3,
- (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, (byte) 0x6d,
- (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, (byte) 0x67,
- (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, (byte) 0xcb,
- (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, (byte) 0xe2,
- (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, (byte) 0x79,
- (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, (byte) 0xce,
- (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, (byte) 0x08,
- (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, (byte) 0x3b,
- (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, (byte) 0xc4,
- (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, (byte) 0x0d,
- (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, (byte) 0x23,
- (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, (byte) 0x08,
- (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, (byte) 0xf1,
- (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, (byte) 0xb4,
- (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, (byte) 0x16,
- (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, (byte) 0x9e,
- (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, (byte) 0x01,
- (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x16,
- (byte) 0x59, (byte) 0xc3, (byte) 0x24, (byte) 0x1d, (byte) 0x33, (byte) 0x98,
- (byte) 0x9c, (byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x88, (byte) 0xbf,
- (byte) 0x0a, (byte) 0x01, (byte) 0xce, (byte) 0xfb, (byte) 0x34, (byte) 0x7a,
- (byte) 0x58, (byte) 0x7a, (byte) 0xb0, (byte) 0xbf, (byte) 0xa6, (byte) 0xb2,
- (byte) 0x60, (byte) 0xbe, (byte) 0x70, (byte) 0x21, (byte) 0xf5, (byte) 0xfc,
- (byte) 0x85, (byte) 0x0d, (byte) 0x33, (byte) 0x58, (byte) 0xa1, (byte) 0xe5,
- (byte) 0x09, (byte) 0x36, (byte) 0x84, (byte) 0xb2, (byte) 0x04, (byte) 0x0a,
- (byte) 0x02, (byte) 0xd3, (byte) 0x88, (byte) 0x1f, (byte) 0x0c, (byte) 0x2b,
- (byte) 0x1d, (byte) 0xe9, (byte) 0x3d, (byte) 0xe7, (byte) 0x79, (byte) 0xf9,
- (byte) 0x32, (byte) 0x5c, (byte) 0x8a, (byte) 0x75, (byte) 0x49, (byte) 0x12,
- (byte) 0xe4, (byte) 0x05, (byte) 0x26, (byte) 0xd4, (byte) 0x2e, (byte) 0x9e,
- (byte) 0x1f, (byte) 0xcc, (byte) 0x54, (byte) 0xad, (byte) 0x33, (byte) 0x8d,
- (byte) 0x99, (byte) 0x00, (byte) 0xdc, (byte) 0xf5, (byte) 0xb4, (byte) 0xa2,
- (byte) 0x2f, (byte) 0xba, (byte) 0xe5, (byte) 0x62, (byte) 0x30, (byte) 0x6d,
- (byte) 0xe6, (byte) 0x3d, (byte) 0xeb, (byte) 0x24, (byte) 0xc2, (byte) 0xdc,
- (byte) 0x5f, (byte) 0xb7, (byte) 0x16, (byte) 0x35, (byte) 0xa3, (byte) 0x98,
- (byte) 0x98, (byte) 0xa8, (byte) 0xef, (byte) 0xe8, (byte) 0xc4, (byte) 0x96,
- (byte) 0x6d, (byte) 0x38, (byte) 0xab, (byte) 0x26, (byte) 0x6d, (byte) 0x30,
- (byte) 0xc2, (byte) 0xa0, (byte) 0x44, (byte) 0xe4, (byte) 0xff, (byte) 0x7e,
- (byte) 0xbe, (byte) 0x7c, (byte) 0x33, (byte) 0xa5, (byte) 0x10, (byte) 0xad,
- (byte) 0xd7, (byte) 0x1e, (byte) 0x13, (byte) 0x20, (byte) 0xb3, (byte) 0x1f,
- (byte) 0x41, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xf1, (byte) 0x89,
- (byte) 0x07, (byte) 0x0f, (byte) 0xe8, (byte) 0xcf, (byte) 0xab, (byte) 0x13,
- (byte) 0x2a, (byte) 0x8f, (byte) 0x88, (byte) 0x80, (byte) 0x11, (byte) 0x9a,
- (byte) 0x79, (byte) 0xb6, (byte) 0x59, (byte) 0x3a, (byte) 0x50, (byte) 0x6e,
- (byte) 0x57, (byte) 0x37, (byte) 0xab, (byte) 0x2a, (byte) 0xd2, (byte) 0xaa,
- (byte) 0xd9, (byte) 0x72, (byte) 0x73, (byte) 0xff, (byte) 0x8b, (byte) 0x47,
- (byte) 0x76, (byte) 0xdd, (byte) 0xdc, (byte) 0xf5, (byte) 0x97, (byte) 0x44,
- (byte) 0x3a, (byte) 0x78, (byte) 0xbe, (byte) 0x17, (byte) 0xb4, (byte) 0x22,
- (byte) 0x6f, (byte) 0xe5, (byte) 0x23, (byte) 0x70, (byte) 0x1d, (byte) 0x10,
- (byte) 0x5d, (byte) 0xba, (byte) 0x16, (byte) 0x81, (byte) 0xf1, (byte) 0x45,
- (byte) 0xce, (byte) 0x30, (byte) 0xb4, (byte) 0xab, (byte) 0x80, (byte) 0xe4,
- (byte) 0x98, (byte) 0x31, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xda,
- (byte) 0x82, (byte) 0x9d, (byte) 0x3f, (byte) 0xca, (byte) 0x2f, (byte) 0xe1,
- (byte) 0xd4, (byte) 0x86, (byte) 0x77, (byte) 0x48, (byte) 0xa6, (byte) 0xab,
- (byte) 0xab, (byte) 0x1c, (byte) 0x42, (byte) 0x5c, (byte) 0xd5, (byte) 0xc7,
- (byte) 0x46, (byte) 0x59, (byte) 0x91, (byte) 0x3f, (byte) 0xfc, (byte) 0xcc,
- (byte) 0xec, (byte) 0xc2, (byte) 0x40, (byte) 0x12, (byte) 0x2c, (byte) 0x8d,
- (byte) 0x1f, (byte) 0xa2, (byte) 0x18, (byte) 0x88, (byte) 0xee, (byte) 0x82,
- (byte) 0x4a, (byte) 0x5a, (byte) 0x5e, (byte) 0x88, (byte) 0x20, (byte) 0xe3,
- (byte) 0x7b, (byte) 0xe0, (byte) 0xd8, (byte) 0x3a, (byte) 0x52, (byte) 0x9a,
- (byte) 0x26, (byte) 0x6a, (byte) 0x04, (byte) 0xec, (byte) 0xe8, (byte) 0xb9,
- (byte) 0x48, (byte) 0x40, (byte) 0xe1, (byte) 0xe1, (byte) 0x83, (byte) 0xa6,
- (byte) 0x67, (byte) 0xa6, (byte) 0xfd, (byte) 0x02, (byte) 0x41, (byte) 0x00,
- (byte) 0x89, (byte) 0x72, (byte) 0x3e, (byte) 0xb0, (byte) 0x90, (byte) 0xfd,
- (byte) 0x4c, (byte) 0x0e, (byte) 0xd6, (byte) 0x13, (byte) 0x63, (byte) 0xcb,
- (byte) 0xed, (byte) 0x38, (byte) 0x88, (byte) 0xb6, (byte) 0x79, (byte) 0xc4,
- (byte) 0x33, (byte) 0x6c, (byte) 0xf6, (byte) 0xf8, (byte) 0xd8, (byte) 0xd0,
- (byte) 0xbf, (byte) 0x9d, (byte) 0x35, (byte) 0xac, (byte) 0x69, (byte) 0xd2,
- (byte) 0x2b, (byte) 0xc1, (byte) 0xf9, (byte) 0x24, (byte) 0x7b, (byte) 0xce,
- (byte) 0xcd, (byte) 0xcb, (byte) 0xa7, (byte) 0xb2, (byte) 0x7a, (byte) 0x0a,
- (byte) 0x27, (byte) 0x19, (byte) 0xc9, (byte) 0xaf, (byte) 0x0d, (byte) 0x21,
- (byte) 0x89, (byte) 0x88, (byte) 0x7c, (byte) 0xad, (byte) 0x9e, (byte) 0x8d,
- (byte) 0x47, (byte) 0x6d, (byte) 0x3f, (byte) 0xce, (byte) 0x7b, (byte) 0xa1,
- (byte) 0x74, (byte) 0xf1, (byte) 0xa0, (byte) 0xa1, (byte) 0x02, (byte) 0x41,
- (byte) 0x00, (byte) 0xd9, (byte) 0xa8, (byte) 0xf5, (byte) 0xfe, (byte) 0xce,
- (byte) 0xe6, (byte) 0x77, (byte) 0x6b, (byte) 0xfe, (byte) 0x2d, (byte) 0xe0,
- (byte) 0x1e, (byte) 0xb6, (byte) 0x2e, (byte) 0x12, (byte) 0x4e, (byte) 0x40,
- (byte) 0xaf, (byte) 0x6a, (byte) 0x7b, (byte) 0x37, (byte) 0x49, (byte) 0x2a,
- (byte) 0x96, (byte) 0x25, (byte) 0x83, (byte) 0x49, (byte) 0xd4, (byte) 0x0c,
- (byte) 0xc6, (byte) 0x78, (byte) 0x25, (byte) 0x24, (byte) 0x90, (byte) 0x90,
- (byte) 0x06, (byte) 0x15, (byte) 0x9e, (byte) 0xfe, (byte) 0xf9, (byte) 0xdf,
- (byte) 0x5b, (byte) 0xf3, (byte) 0x7e, (byte) 0x38, (byte) 0x70, (byte) 0xeb,
- (byte) 0x57, (byte) 0xd0, (byte) 0xd9, (byte) 0xa7, (byte) 0x0e, (byte) 0x14,
- (byte) 0xf7, (byte) 0x95, (byte) 0x68, (byte) 0xd5, (byte) 0xc8, (byte) 0xab,
- (byte) 0x9d, (byte) 0x3a, (byte) 0x2b, (byte) 0x51, (byte) 0xf9, (byte) 0x02,
- (byte) 0x41, (byte) 0x00, (byte) 0x96, (byte) 0xdf, (byte) 0xe9, (byte) 0x67,
- (byte) 0x6c, (byte) 0xdc, (byte) 0x90, (byte) 0x14, (byte) 0xb4, (byte) 0x1d,
- (byte) 0x22, (byte) 0x33, (byte) 0x4a, (byte) 0x31, (byte) 0xc1, (byte) 0x9d,
- (byte) 0x2e, (byte) 0xff, (byte) 0x9a, (byte) 0x2a, (byte) 0x95, (byte) 0x4b,
- (byte) 0x27, (byte) 0x74, (byte) 0xcb, (byte) 0x21, (byte) 0xc3, (byte) 0xd2,
- (byte) 0x0b, (byte) 0xb2, (byte) 0x46, (byte) 0x87, (byte) 0xf8, (byte) 0x28,
- (byte) 0x01, (byte) 0x8b, (byte) 0xd8, (byte) 0xb9, (byte) 0x4b, (byte) 0xcd,
- (byte) 0x9a, (byte) 0x96, (byte) 0x41, (byte) 0x0e, (byte) 0x36, (byte) 0x6d,
- (byte) 0x40, (byte) 0x42, (byte) 0xbc, (byte) 0xd9, (byte) 0xd3, (byte) 0x7b,
- (byte) 0xbc, (byte) 0xa7, (byte) 0x92, (byte) 0x90, (byte) 0xdd, (byte) 0xa1,
- (byte) 0x9c, (byte) 0xce, (byte) 0xa1, (byte) 0x87, (byte) 0x11, (byte) 0x51
- };
-
- /**
- * Generated from above and converted with:
- *
- * openssl x509 -outform d -in cacert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
- */
- public static final byte[] caCertificate = {
- (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0xce, (byte) 0x30, (byte) 0x82,
- (byte) 0x02, (byte) 0x37, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
- (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0xe1, (byte) 0x6a,
- (byte) 0xa2, (byte) 0xf4, (byte) 0x2e, (byte) 0x55, (byte) 0x48, (byte) 0x0a,
- (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
- (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
- (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x4f, (byte) 0x31,
- (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
- (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53,
- (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03,
- (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43,
- (byte) 0x41, (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06,
- (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d,
- (byte) 0x4d, (byte) 0x6f, (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61,
- (byte) 0x69, (byte) 0x6e, (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65,
- (byte) 0x77, (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06,
- (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12,
- (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69,
- (byte) 0x64, (byte) 0x20, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74,
- (byte) 0x20, (byte) 0x43, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73,
- (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x31, (byte) 0x32,
- (byte) 0x30, (byte) 0x38, (byte) 0x31, (byte) 0x34, (byte) 0x31, (byte) 0x36,
- (byte) 0x35, (byte) 0x35, (byte) 0x34, (byte) 0x34, (byte) 0x5a, (byte) 0x17,
- (byte) 0x0d, (byte) 0x32, (byte) 0x32, (byte) 0x30, (byte) 0x38, (byte) 0x31,
- (byte) 0x32, (byte) 0x31, (byte) 0x36, (byte) 0x35, (byte) 0x35, (byte) 0x34,
- (byte) 0x34, (byte) 0x5a, (byte) 0x30, (byte) 0x4f, (byte) 0x31, (byte) 0x0b,
- (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
- (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31,
- (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
- (byte) 0x04, (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41,
- (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03,
- (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, (byte) 0x4d,
- (byte) 0x6f, (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69,
- (byte) 0x6e, (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77,
- (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03,
- (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41,
- (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64,
- (byte) 0x20, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20,
- (byte) 0x43, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x30,
- (byte) 0x81, (byte) 0x9f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
- (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d,
- (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03,
- (byte) 0x81, (byte) 0x8d, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89,
- (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xa3, (byte) 0x72,
- (byte) 0xab, (byte) 0xd0, (byte) 0xe4, (byte) 0xad, (byte) 0x2f, (byte) 0xe7,
- (byte) 0xe2, (byte) 0x79, (byte) 0x07, (byte) 0x36, (byte) 0x3d, (byte) 0x0c,
- (byte) 0x8d, (byte) 0x42, (byte) 0x9a, (byte) 0x0a, (byte) 0x33, (byte) 0x64,
- (byte) 0xb3, (byte) 0xcd, (byte) 0xb2, (byte) 0xd7, (byte) 0x3a, (byte) 0x42,
- (byte) 0x06, (byte) 0x77, (byte) 0x45, (byte) 0x29, (byte) 0xe9, (byte) 0xcb,
- (byte) 0xb7, (byte) 0x4a, (byte) 0xd6, (byte) 0xee, (byte) 0xad, (byte) 0x01,
- (byte) 0x91, (byte) 0x9b, (byte) 0x0c, (byte) 0x59, (byte) 0xa1, (byte) 0x03,
- (byte) 0xfa, (byte) 0xf0, (byte) 0x5a, (byte) 0x7c, (byte) 0x4f, (byte) 0xf7,
- (byte) 0x8d, (byte) 0x36, (byte) 0x0f, (byte) 0x1f, (byte) 0x45, (byte) 0x7d,
- (byte) 0x1b, (byte) 0x31, (byte) 0xa1, (byte) 0x35, (byte) 0x0b, (byte) 0x00,
- (byte) 0xed, (byte) 0x7a, (byte) 0xb6, (byte) 0xc8, (byte) 0x4e, (byte) 0xa9,
- (byte) 0x86, (byte) 0x4c, (byte) 0x7b, (byte) 0x99, (byte) 0x57, (byte) 0x41,
- (byte) 0x12, (byte) 0xef, (byte) 0x6b, (byte) 0xbc, (byte) 0x3d, (byte) 0x60,
- (byte) 0xf2, (byte) 0x99, (byte) 0x1a, (byte) 0xcd, (byte) 0xed, (byte) 0x56,
- (byte) 0xa4, (byte) 0xe5, (byte) 0x36, (byte) 0x9f, (byte) 0x24, (byte) 0x1f,
- (byte) 0xdc, (byte) 0x89, (byte) 0x40, (byte) 0xc8, (byte) 0x99, (byte) 0x92,
- (byte) 0xab, (byte) 0x4a, (byte) 0xb5, (byte) 0x61, (byte) 0x45, (byte) 0x62,
- (byte) 0xff, (byte) 0xa3, (byte) 0x45, (byte) 0x65, (byte) 0xaf, (byte) 0xf6,
- (byte) 0x27, (byte) 0x30, (byte) 0x51, (byte) 0x0e, (byte) 0x0e, (byte) 0xeb,
- (byte) 0x79, (byte) 0x0c, (byte) 0xbe, (byte) 0xb3, (byte) 0x0a, (byte) 0x6f,
- (byte) 0x29, (byte) 0x06, (byte) 0xdc, (byte) 0x2f, (byte) 0x6b, (byte) 0x51,
- (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3,
- (byte) 0x81, (byte) 0xb1, (byte) 0x30, (byte) 0x81, (byte) 0xae, (byte) 0x30,
- (byte) 0x1d, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e,
- (byte) 0x04, (byte) 0x16, (byte) 0x04, (byte) 0x14, (byte) 0x33, (byte) 0x05,
- (byte) 0xee, (byte) 0xfe, (byte) 0x6f, (byte) 0x60, (byte) 0xc7, (byte) 0xf9,
- (byte) 0xa9, (byte) 0xd2, (byte) 0x73, (byte) 0x5c, (byte) 0x8f, (byte) 0x6d,
- (byte) 0xa2, (byte) 0x2f, (byte) 0x97, (byte) 0x8e, (byte) 0x5d, (byte) 0x51,
- (byte) 0x30, (byte) 0x7f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d,
- (byte) 0x23, (byte) 0x04, (byte) 0x78, (byte) 0x30, (byte) 0x76, (byte) 0x80,
- (byte) 0x14, (byte) 0x33, (byte) 0x05, (byte) 0xee, (byte) 0xfe, (byte) 0x6f,
- (byte) 0x60, (byte) 0xc7, (byte) 0xf9, (byte) 0xa9, (byte) 0xd2, (byte) 0x73,
- (byte) 0x5c, (byte) 0x8f, (byte) 0x6d, (byte) 0xa2, (byte) 0x2f, (byte) 0x97,
- (byte) 0x8e, (byte) 0x5d, (byte) 0x51, (byte) 0xa1, (byte) 0x53, (byte) 0xa4,
- (byte) 0x51, (byte) 0x30, (byte) 0x4f, (byte) 0x31, (byte) 0x0b, (byte) 0x30,
- (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
- (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x0b,
- (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
- (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41, (byte) 0x31,
- (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, (byte) 0x55,
- (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, (byte) 0x4d, (byte) 0x6f,
- (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e,
- (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31,
- (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03, (byte) 0x55,
- (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41, (byte) 0x6e,
- (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20,
- (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x43,
- (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x82, (byte) 0x09,
- (byte) 0x00, (byte) 0xe1, (byte) 0x6a, (byte) 0xa2, (byte) 0xf4, (byte) 0x2e,
- (byte) 0x55, (byte) 0x48, (byte) 0x0a, (byte) 0x30, (byte) 0x0c, (byte) 0x06,
- (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x05,
- (byte) 0x30, (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x30,
- (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48,
- (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05,
- (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x81, (byte) 0x00,
- (byte) 0x8c, (byte) 0x30, (byte) 0x42, (byte) 0xfa, (byte) 0xeb, (byte) 0x1a,
- (byte) 0x26, (byte) 0xeb, (byte) 0xda, (byte) 0x56, (byte) 0x32, (byte) 0xf2,
- (byte) 0x9d, (byte) 0xa5, (byte) 0x24, (byte) 0xd8, (byte) 0x3a, (byte) 0xda,
- (byte) 0x30, (byte) 0xa6, (byte) 0x8b, (byte) 0x46, (byte) 0xfe, (byte) 0xfe,
- (byte) 0xdb, (byte) 0xf1, (byte) 0xe6, (byte) 0xe1, (byte) 0x7c, (byte) 0x1b,
- (byte) 0xe7, (byte) 0x77, (byte) 0x00, (byte) 0xa1, (byte) 0x1c, (byte) 0x19,
- (byte) 0x17, (byte) 0x73, (byte) 0xb0, (byte) 0xf0, (byte) 0x9d, (byte) 0xf3,
- (byte) 0x4f, (byte) 0xb6, (byte) 0xbc, (byte) 0xc7, (byte) 0x47, (byte) 0x85,
- (byte) 0x2a, (byte) 0x4a, (byte) 0xa1, (byte) 0xa5, (byte) 0x58, (byte) 0xf5,
- (byte) 0xc5, (byte) 0x1a, (byte) 0x51, (byte) 0xb1, (byte) 0x04, (byte) 0x80,
- (byte) 0xee, (byte) 0x3a, (byte) 0xec, (byte) 0x2f, (byte) 0xe1, (byte) 0xfd,
- (byte) 0x58, (byte) 0xeb, (byte) 0xed, (byte) 0x82, (byte) 0x9e, (byte) 0x38,
- (byte) 0xa3, (byte) 0x24, (byte) 0x75, (byte) 0xf7, (byte) 0x3e, (byte) 0xc2,
- (byte) 0xc5, (byte) 0x27, (byte) 0xeb, (byte) 0x6f, (byte) 0x7b, (byte) 0x50,
- (byte) 0xda, (byte) 0x43, (byte) 0xdc, (byte) 0x3b, (byte) 0x0b, (byte) 0x6f,
- (byte) 0x78, (byte) 0x8f, (byte) 0xb0, (byte) 0x66, (byte) 0xe1, (byte) 0x12,
- (byte) 0x87, (byte) 0x5f, (byte) 0x97, (byte) 0x7b, (byte) 0xca, (byte) 0x14,
- (byte) 0x79, (byte) 0xf7, (byte) 0xe8, (byte) 0x6c, (byte) 0x72, (byte) 0xdb,
- (byte) 0x91, (byte) 0x65, (byte) 0x17, (byte) 0x54, (byte) 0xe0, (byte) 0x74,
- (byte) 0x1d, (byte) 0xac, (byte) 0x47, (byte) 0x04, (byte) 0x12, (byte) 0xe0,
- (byte) 0xc3, (byte) 0x66, (byte) 0x19, (byte) 0x05, (byte) 0x2e, (byte) 0x7e,
- (byte) 0xf1, (byte) 0x61
- };
- }
-
- /*
- * The keys and certificates below are generated with:
- *
- * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem
- * openssl dsaparam -out dsaparam.pem 1024
- * openssl req -newkey dsa:dsaparam.pem -keyout userkey.pem -nodes -days 3650 -out userkey.req
- * mkdir -p demoCA/newcerts
- * touch demoCA/index.txt
- * echo "01" > demoCA/serial
- * openssl ca -out usercert.pem -in userkey.req -cert cacert.pem -keyfile cakey.pem -days 3650
- */
- public static class FAKE_DSA_1 {
- /**
- * Generated from above and converted with: openssl pkcs8 -topk8 -outform d
- * -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g'
- */
- public static final byte[] privateKey = {
- (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x4c, (byte) 0x02, (byte) 0x01,
- (byte) 0x00, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x2c, (byte) 0x06,
- (byte) 0x07, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x38,
- (byte) 0x04, (byte) 0x01, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x1f,
- (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xb3, (byte) 0x23,
- (byte) 0xf7, (byte) 0x86, (byte) 0xbd, (byte) 0x3b, (byte) 0x86, (byte) 0xcc,
- (byte) 0xc3, (byte) 0x91, (byte) 0xc0, (byte) 0x30, (byte) 0x32, (byte) 0x02,
- (byte) 0x47, (byte) 0x35, (byte) 0x01, (byte) 0xef, (byte) 0xee, (byte) 0x98,
- (byte) 0x13, (byte) 0x56, (byte) 0x49, (byte) 0x47, (byte) 0xb5, (byte) 0x20,
- (byte) 0xa8, (byte) 0x60, (byte) 0xcb, (byte) 0xc0, (byte) 0xd5, (byte) 0x77,
- (byte) 0xc1, (byte) 0x69, (byte) 0xcd, (byte) 0x18, (byte) 0x34, (byte) 0x92,
- (byte) 0xf2, (byte) 0x6a, (byte) 0x2a, (byte) 0x10, (byte) 0x59, (byte) 0x1c,
- (byte) 0x91, (byte) 0x20, (byte) 0x51, (byte) 0xca, (byte) 0x37, (byte) 0xb2,
- (byte) 0x87, (byte) 0xa6, (byte) 0x8a, (byte) 0x02, (byte) 0xfd, (byte) 0x45,
- (byte) 0x46, (byte) 0xf9, (byte) 0x76, (byte) 0xb1, (byte) 0x35, (byte) 0x38,
- (byte) 0x8d, (byte) 0xff, (byte) 0x4c, (byte) 0x5d, (byte) 0x75, (byte) 0x8f,
- (byte) 0x66, (byte) 0x15, (byte) 0x7d, (byte) 0x7b, (byte) 0xda, (byte) 0xdb,
- (byte) 0x57, (byte) 0x39, (byte) 0xff, (byte) 0x91, (byte) 0x3f, (byte) 0xdd,
- (byte) 0xe2, (byte) 0xb4, (byte) 0x22, (byte) 0x60, (byte) 0x4c, (byte) 0x32,
- (byte) 0x3b, (byte) 0x9d, (byte) 0x34, (byte) 0x9f, (byte) 0xb9, (byte) 0x5d,
- (byte) 0x75, (byte) 0xb9, (byte) 0xd3, (byte) 0x7f, (byte) 0x11, (byte) 0xba,
- (byte) 0xb7, (byte) 0xc8, (byte) 0x32, (byte) 0xc6, (byte) 0xce, (byte) 0x71,
- (byte) 0x91, (byte) 0xd3, (byte) 0x32, (byte) 0xaf, (byte) 0x4d, (byte) 0x7e,
- (byte) 0x7c, (byte) 0x15, (byte) 0xf7, (byte) 0x71, (byte) 0x2c, (byte) 0x52,
- (byte) 0x65, (byte) 0x4d, (byte) 0xa9, (byte) 0x81, (byte) 0x25, (byte) 0x35,
- (byte) 0xce, (byte) 0x0b, (byte) 0x5b, (byte) 0x56, (byte) 0xfe, (byte) 0xf1,
- (byte) 0x02, (byte) 0x15, (byte) 0x00, (byte) 0xeb, (byte) 0x4e, (byte) 0x7f,
- (byte) 0x7a, (byte) 0x31, (byte) 0xb3, (byte) 0x7d, (byte) 0x8d, (byte) 0xb2,
- (byte) 0xf7, (byte) 0xaf, (byte) 0xad, (byte) 0xb1, (byte) 0x42, (byte) 0x92,
- (byte) 0xf3, (byte) 0x6c, (byte) 0xe4, (byte) 0xed, (byte) 0x8b, (byte) 0x02,
- (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x81, (byte) 0xc8, (byte) 0x36,
- (byte) 0x48, (byte) 0xdb, (byte) 0x71, (byte) 0x2b, (byte) 0x91, (byte) 0xce,
- (byte) 0x6d, (byte) 0xbc, (byte) 0xb8, (byte) 0xf9, (byte) 0xcb, (byte) 0x50,
- (byte) 0x91, (byte) 0x10, (byte) 0x8a, (byte) 0xf8, (byte) 0x37, (byte) 0x50,
- (byte) 0xda, (byte) 0x4f, (byte) 0xc8, (byte) 0x4d, (byte) 0x73, (byte) 0xcb,
- (byte) 0x4d, (byte) 0xb0, (byte) 0x19, (byte) 0x54, (byte) 0x5a, (byte) 0xf3,
- (byte) 0x6c, (byte) 0xc9, (byte) 0xd8, (byte) 0x96, (byte) 0xd9, (byte) 0xb0,
- (byte) 0x54, (byte) 0x7e, (byte) 0x7d, (byte) 0xe2, (byte) 0x58, (byte) 0x0e,
- (byte) 0x5f, (byte) 0xc0, (byte) 0xce, (byte) 0xb9, (byte) 0x5c, (byte) 0xe3,
- (byte) 0xd3, (byte) 0xdf, (byte) 0xcf, (byte) 0x45, (byte) 0x74, (byte) 0xfb,
- (byte) 0xe6, (byte) 0x20, (byte) 0xe7, (byte) 0xfc, (byte) 0x0f, (byte) 0xca,
- (byte) 0xdb, (byte) 0xc0, (byte) 0x0b, (byte) 0xe1, (byte) 0x5a, (byte) 0x16,
- (byte) 0x1d, (byte) 0xb3, (byte) 0x2e, (byte) 0xe5, (byte) 0x5f, (byte) 0x89,
- (byte) 0x17, (byte) 0x73, (byte) 0x50, (byte) 0xd1, (byte) 0x4a, (byte) 0x60,
- (byte) 0xb7, (byte) 0xaa, (byte) 0xf0, (byte) 0xc7, (byte) 0xc5, (byte) 0x03,
- (byte) 0x4e, (byte) 0x36, (byte) 0x51, (byte) 0x9e, (byte) 0x2f, (byte) 0xfa,
- (byte) 0xf3, (byte) 0xd6, (byte) 0x58, (byte) 0x14, (byte) 0x02, (byte) 0xb4,
- (byte) 0x41, (byte) 0xd6, (byte) 0x72, (byte) 0x6f, (byte) 0x58, (byte) 0x5b,
- (byte) 0x2d, (byte) 0x23, (byte) 0xc0, (byte) 0x75, (byte) 0x4f, (byte) 0x39,
- (byte) 0xa8, (byte) 0x6a, (byte) 0xdf, (byte) 0x79, (byte) 0x21, (byte) 0xf2,
- (byte) 0x77, (byte) 0x91, (byte) 0x3f, (byte) 0x1c, (byte) 0x4d, (byte) 0x48,
- (byte) 0x78, (byte) 0xcd, (byte) 0xed, (byte) 0x79, (byte) 0x23, (byte) 0x04,
- (byte) 0x17, (byte) 0x02, (byte) 0x15, (byte) 0x00, (byte) 0xc7, (byte) 0xe7,
- (byte) 0xe2, (byte) 0x6b, (byte) 0x14, (byte) 0xe6, (byte) 0x31, (byte) 0x12,
- (byte) 0xb2, (byte) 0x1e, (byte) 0xd4, (byte) 0xf2, (byte) 0x9b, (byte) 0x2c,
- (byte) 0xf6, (byte) 0x54, (byte) 0x4c, (byte) 0x12, (byte) 0xe8, (byte) 0x22
-
- };
-
- /**
- * Generated from above and converted with:
- *
- * openssl x509 -outform d -in cacert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
- */
- public static final byte[] caCertificate = new byte[] {
- (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x8a, (byte) 0x30, (byte) 0x82,
- (byte) 0x01, (byte) 0xf3, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
- (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0x87, (byte) 0xc0,
- (byte) 0x68, (byte) 0x7f, (byte) 0x42, (byte) 0x92, (byte) 0x0b, (byte) 0x7a,
- (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
- (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
- (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x5e, (byte) 0x31,
- (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
- (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55,
- (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03,
- (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53,
- (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74,
- (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x21, (byte) 0x30,
- (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a,
- (byte) 0x0c, (byte) 0x18, (byte) 0x49, (byte) 0x6e, (byte) 0x74, (byte) 0x65,
- (byte) 0x72, (byte) 0x6e, (byte) 0x65, (byte) 0x74, (byte) 0x20, (byte) 0x57,
- (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69, (byte) 0x74, (byte) 0x73,
- (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79, (byte) 0x20, (byte) 0x4c,
- (byte) 0x74, (byte) 0x64, (byte) 0x31, (byte) 0x17, (byte) 0x30, (byte) 0x15,
- (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c,
- (byte) 0x0e, (byte) 0x63, (byte) 0x61, (byte) 0x2e, (byte) 0x65, (byte) 0x78,
- (byte) 0x61, (byte) 0x6d, (byte) 0x70, (byte) 0x6c, (byte) 0x65, (byte) 0x2e,
- (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30, (byte) 0x1e, (byte) 0x17,
- (byte) 0x0d, (byte) 0x31, (byte) 0x33, (byte) 0x30, (byte) 0x38, (byte) 0x32,
- (byte) 0x37, (byte) 0x32, (byte) 0x33, (byte) 0x33, (byte) 0x31, (byte) 0x32,
- (byte) 0x39, (byte) 0x5a, (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x33,
- (byte) 0x30, (byte) 0x38, (byte) 0x32, (byte) 0x35, (byte) 0x32, (byte) 0x33,
- (byte) 0x33, (byte) 0x31, (byte) 0x32, (byte) 0x39, (byte) 0x5a, (byte) 0x30,
- (byte) 0x5e, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06,
- (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02,
- (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11,
- (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c,
- (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d,
- (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31,
- (byte) 0x21, (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55,
- (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x18, (byte) 0x49, (byte) 0x6e,
- (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x6e, (byte) 0x65, (byte) 0x74,
- (byte) 0x20, (byte) 0x57, (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69,
- (byte) 0x74, (byte) 0x73, (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79,
- (byte) 0x20, (byte) 0x4c, (byte) 0x74, (byte) 0x64, (byte) 0x31, (byte) 0x17,
- (byte) 0x30, (byte) 0x15, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
- (byte) 0x03, (byte) 0x0c, (byte) 0x0e, (byte) 0x63, (byte) 0x61, (byte) 0x2e,
- (byte) 0x65, (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70, (byte) 0x6c,
- (byte) 0x65, (byte) 0x2e, (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30,
- (byte) 0x81, (byte) 0x9f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
- (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d,
- (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03,
- (byte) 0x81, (byte) 0x8d, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89,
- (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xa4, (byte) 0xc7,
- (byte) 0x06, (byte) 0xba, (byte) 0xdf, (byte) 0x2b, (byte) 0xee, (byte) 0xd2,
- (byte) 0xb9, (byte) 0xe4, (byte) 0x52, (byte) 0x21, (byte) 0x68, (byte) 0x2b,
- (byte) 0x83, (byte) 0xdf, (byte) 0xe3, (byte) 0x9c, (byte) 0x08, (byte) 0x73,
- (byte) 0xdd, (byte) 0x90, (byte) 0xea, (byte) 0x97, (byte) 0x0c, (byte) 0x96,
- (byte) 0x20, (byte) 0xb1, (byte) 0xee, (byte) 0x11, (byte) 0xd5, (byte) 0xd4,
- (byte) 0x7c, (byte) 0x44, (byte) 0x96, (byte) 0x2e, (byte) 0x6e, (byte) 0xa2,
- (byte) 0xb2, (byte) 0xa3, (byte) 0x4b, (byte) 0x0f, (byte) 0x32, (byte) 0x90,
- (byte) 0xaf, (byte) 0x5c, (byte) 0x6f, (byte) 0x00, (byte) 0x88, (byte) 0x45,
- (byte) 0x4e, (byte) 0x9b, (byte) 0x26, (byte) 0xc1, (byte) 0x94, (byte) 0x3c,
- (byte) 0xfe, (byte) 0x10, (byte) 0xbd, (byte) 0xda, (byte) 0xf2, (byte) 0x8d,
- (byte) 0x03, (byte) 0x52, (byte) 0x32, (byte) 0x11, (byte) 0xff, (byte) 0xf6,
- (byte) 0xf9, (byte) 0x6e, (byte) 0x8f, (byte) 0x0f, (byte) 0xc8, (byte) 0x0a,
- (byte) 0x48, (byte) 0x39, (byte) 0x33, (byte) 0xb9, (byte) 0x0c, (byte) 0xb3,
- (byte) 0x2b, (byte) 0xab, (byte) 0x7d, (byte) 0x79, (byte) 0x6f, (byte) 0x57,
- (byte) 0x5b, (byte) 0xb8, (byte) 0x84, (byte) 0xb6, (byte) 0xcc, (byte) 0xe8,
- (byte) 0x30, (byte) 0x78, (byte) 0xff, (byte) 0x92, (byte) 0xe5, (byte) 0x43,
- (byte) 0x2e, (byte) 0xef, (byte) 0x66, (byte) 0x98, (byte) 0xb4, (byte) 0xfe,
- (byte) 0xa2, (byte) 0x40, (byte) 0xf2, (byte) 0x1f, (byte) 0xd0, (byte) 0x86,
- (byte) 0x16, (byte) 0xc8, (byte) 0x45, (byte) 0xc4, (byte) 0x52, (byte) 0xcb,
- (byte) 0x31, (byte) 0x5c, (byte) 0x9f, (byte) 0x32, (byte) 0x3b, (byte) 0xf7,
- (byte) 0x19, (byte) 0x08, (byte) 0xc7, (byte) 0x00, (byte) 0x21, (byte) 0x7d,
- (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3,
- (byte) 0x50, (byte) 0x30, (byte) 0x4e, (byte) 0x30, (byte) 0x1d, (byte) 0x06,
- (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16,
- (byte) 0x04, (byte) 0x14, (byte) 0x47, (byte) 0x82, (byte) 0xa3, (byte) 0xf1,
- (byte) 0xc2, (byte) 0x7e, (byte) 0x3a, (byte) 0xde, (byte) 0x4f, (byte) 0x30,
- (byte) 0x4c, (byte) 0x7f, (byte) 0x72, (byte) 0x81, (byte) 0x15, (byte) 0x32,
- (byte) 0xda, (byte) 0x7f, (byte) 0x58, (byte) 0x18, (byte) 0x30, (byte) 0x1f,
- (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04,
- (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x47,
- (byte) 0x82, (byte) 0xa3, (byte) 0xf1, (byte) 0xc2, (byte) 0x7e, (byte) 0x3a,
- (byte) 0xde, (byte) 0x4f, (byte) 0x30, (byte) 0x4c, (byte) 0x7f, (byte) 0x72,
- (byte) 0x81, (byte) 0x15, (byte) 0x32, (byte) 0xda, (byte) 0x7f, (byte) 0x58,
- (byte) 0x18, (byte) 0x30, (byte) 0x0c, (byte) 0x06, (byte) 0x03, (byte) 0x55,
- (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x05, (byte) 0x30, (byte) 0x03,
- (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x30, (byte) 0x0d, (byte) 0x06,
- (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7,
- (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00,
- (byte) 0x03, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x08, (byte) 0x7f,
- (byte) 0x6a, (byte) 0x48, (byte) 0x90, (byte) 0x7b, (byte) 0x9b, (byte) 0x72,
- (byte) 0x13, (byte) 0xa7, (byte) 0xef, (byte) 0x6b, (byte) 0x0b, (byte) 0x59,
- (byte) 0xe5, (byte) 0x49, (byte) 0x72, (byte) 0x3a, (byte) 0xc8, (byte) 0x84,
- (byte) 0xcc, (byte) 0x23, (byte) 0x18, (byte) 0x4c, (byte) 0xec, (byte) 0xc7,
- (byte) 0xef, (byte) 0xcb, (byte) 0xa7, (byte) 0xbe, (byte) 0xe4, (byte) 0xef,
- (byte) 0x8f, (byte) 0xc6, (byte) 0x06, (byte) 0x8c, (byte) 0xc0, (byte) 0xe4,
- (byte) 0x2f, (byte) 0x2a, (byte) 0xc0, (byte) 0x35, (byte) 0x7d, (byte) 0x5e,
- (byte) 0x19, (byte) 0x29, (byte) 0x8c, (byte) 0xb9, (byte) 0xf1, (byte) 0x1e,
- (byte) 0xaf, (byte) 0x82, (byte) 0xd8, (byte) 0xe3, (byte) 0x88, (byte) 0xe1,
- (byte) 0x31, (byte) 0xc8, (byte) 0x82, (byte) 0x1f, (byte) 0x83, (byte) 0xa9,
- (byte) 0xde, (byte) 0xfe, (byte) 0x4b, (byte) 0xe2, (byte) 0x78, (byte) 0x64,
- (byte) 0xed, (byte) 0xa4, (byte) 0x7b, (byte) 0xee, (byte) 0x8d, (byte) 0x71,
- (byte) 0x1b, (byte) 0x44, (byte) 0xe6, (byte) 0xb7, (byte) 0xe8, (byte) 0xc5,
- (byte) 0x9a, (byte) 0x93, (byte) 0x92, (byte) 0x6f, (byte) 0x6f, (byte) 0xdb,
- (byte) 0xbd, (byte) 0xd7, (byte) 0x03, (byte) 0x85, (byte) 0xa9, (byte) 0x5f,
- (byte) 0x53, (byte) 0x5f, (byte) 0x5d, (byte) 0x30, (byte) 0xc6, (byte) 0xd9,
- (byte) 0xce, (byte) 0x34, (byte) 0xa8, (byte) 0xbe, (byte) 0x31, (byte) 0x47,
- (byte) 0x1c, (byte) 0xa4, (byte) 0x7f, (byte) 0xc0, (byte) 0x2c, (byte) 0xbc,
- (byte) 0xfe, (byte) 0x1a, (byte) 0x31, (byte) 0xd8, (byte) 0x77, (byte) 0x4d,
- (byte) 0xfc, (byte) 0x45, (byte) 0x84, (byte) 0xfc, (byte) 0x45, (byte) 0x12,
- (byte) 0xab, (byte) 0x50, (byte) 0xe4, (byte) 0x45, (byte) 0xe5, (byte) 0x11
- };
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/FeatureUtil.java b/common/device-side/util/src/com/android/compatibility/common/util/FeatureUtil.java
deleted file mode 100644
index c9681d2..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/FeatureUtil.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import android.content.Context;
-import android.content.pm.FeatureInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.os.Build;
-import android.support.test.InstrumentationRegistry;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Device-side utility class for detecting system features
- */
-public class FeatureUtil {
-
- public static final String AUTOMOTIVE_FEATURE = "android.hardware.type.automotive";
- public static final String LEANBACK_FEATURE = "android.software.leanback";
- public static final String LOW_RAM_FEATURE = "android.hardware.ram.low";
- public static final String TELEPHONY_FEATURE = "android.hardware.telephony";
- public static final String TV_FEATURE = "android.hardware.type.television";
- public static final String WATCH_FEATURE = "android.hardware.type.watch";
-
-
- /** Returns true if the device has a given system feature */
- public static boolean hasSystemFeature(String feature) {
- return getPackageManager().hasSystemFeature(feature);
- }
-
- /** Returns true if the device has any feature in a given collection of system features */
- public static boolean hasAnySystemFeature(String... features) {
- PackageManager pm = getPackageManager();
- for (String feature : features) {
- if (pm.hasSystemFeature(feature)) {
- return true;
- }
- }
- return false;
- }
-
- /** Returns true if the device has all features in a given collection of system features */
- public static boolean hasAllSystemFeatures(String... features) {
- PackageManager pm = getPackageManager();
- for (String feature : features) {
- if (!pm.hasSystemFeature(feature)) {
- return false;
- }
- }
- return true;
- }
-
- /** Returns all system features of the device */
- public static Set<String> getAllFeatures() {
- Set<String> allFeatures = new HashSet<String>();
- for (FeatureInfo fi : getPackageManager().getSystemAvailableFeatures()) {
- allFeatures.add(fi.name);
- }
- return allFeatures;
- }
-
- /** Returns true if the device has feature TV_FEATURE or feature LEANBACK_FEATURE */
- public static boolean isTV() {
- return hasAnySystemFeature(TV_FEATURE, LEANBACK_FEATURE);
- }
-
- /** Returns true if the device has feature WATCH_FEATURE */
- public static boolean isWatch() {
- return hasSystemFeature(WATCH_FEATURE);
- }
-
- /** Returns true if the device has feature AUTOMOTIVE_FEATURE */
- public static boolean isAutomotive() {
- return hasSystemFeature(AUTOMOTIVE_FEATURE);
- }
-
- public static boolean isVrHeadset() {
- int maskedUiMode = (getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK);
- return (maskedUiMode == Configuration.UI_MODE_TYPE_VR_HEADSET);
- }
-
- /** Returns true if the device is a low ram device:
- * 1. API level >= O_MR1
- * 2. device has feature LOW_RAM_FEATURE
- */
- public static boolean isLowRam() {
- return ApiLevelUtil.isAtLeast(Build.VERSION_CODES.O_MR1) &&
- hasSystemFeature(LOW_RAM_FEATURE);
- }
-
- private static Context getContext() {
- return InstrumentationRegistry.getInstrumentation().getTargetContext();
- }
-
- private static PackageManager getPackageManager() {
- return getContext().getPackageManager();
- }
-
- private static Configuration getConfiguration() {
- return getContext().getResources().getConfiguration();
- }
-
- /** Returns true if the device has feature TELEPHONY_FEATURE */
- public static boolean hasTelephony() {
- return hasSystemFeature(TELEPHONY_FEATURE);
- }
-
- /** Returns true if the device has feature FEATURE_MICROPHONE */
- public static boolean hasMicrophone() {
- return hasSystemFeature(getPackageManager().FEATURE_MICROPHONE);
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/FileCopyHelper.java b/common/device-side/util/src/com/android/compatibility/common/util/FileCopyHelper.java
deleted file mode 100644
index f58dbd0..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/FileCopyHelper.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2009 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.compatibility.common.util;
-
-import android.content.Context;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-
-/**
- * FileCopyHelper is used to copy files from resources to the
- * application directory and responsible for deleting the files.
- *
- * @see MediaStore_VideoTest
- * @see MediaStore_Images_MediaTest
- * @see MediaStore_Images_ThumbnailsTest
- */
-public class FileCopyHelper {
- /** The context. */
- private Context mContext;
-
- /** The files added. */
- private ArrayList<String> mFilesList;
-
- /**
- * Instantiates a new file copy helper.
- *
- * @param context the context
- */
- public FileCopyHelper(Context context) {
- mContext = context;
- mFilesList = new ArrayList<String>();
- }
-
- /**
- * Copy the file from the resources with a filename.
- *
- * @param resId the res id
- * @param fileName the file name
- *
- * @return the absolute path of the destination file
- * @throws IOException
- */
- public String copy(int resId, String fileName) throws IOException {
- InputStream source = mContext.getResources().openRawResource(resId);
- OutputStream target = mContext.openFileOutput(fileName, Context.MODE_WORLD_READABLE);
- copyFile(source, target);
- mFilesList.add(fileName);
- return mContext.getFileStreamPath(fileName).getAbsolutePath();
- }
-
- public void copyToExternalStorage(int resId, File path) throws IOException {
- InputStream source = mContext.getResources().openRawResource(resId);
- OutputStream target = new FileOutputStream(path);
- copyFile(source, target);
- }
-
- private void copyFile(InputStream source, OutputStream target) throws IOException {
- try {
- byte[] buffer = new byte[1024];
- for (int len = source.read(buffer); len > 0; len = source.read(buffer)) {
- target.write(buffer, 0, len);
- }
- } finally {
- if (source != null) {
- source.close();
- }
- if (target != null) {
- target.close();
- }
- }
- }
-
- /**
- * Delete all the files copied by the helper.
- */
- public void clear(){
- for (String path : mFilesList) {
- mContext.deleteFile(path);
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/FileUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/FileUtils.java
deleted file mode 100644
index ceada01..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/FileUtils.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2011 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.compatibility.common.util;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/** Bits and pieces copied from hidden API of android.os.FileUtils. */
-public class FileUtils {
-
- public static final int S_IFMT = 0170000;
- public static final int S_IFSOCK = 0140000;
- public static final int S_IFLNK = 0120000;
- public static final int S_IFREG = 0100000;
- public static final int S_IFBLK = 0060000;
- public static final int S_IFDIR = 0040000;
- public static final int S_IFCHR = 0020000;
- public static final int S_IFIFO = 0010000;
-
- public static final int S_ISUID = 0004000;
- public static final int S_ISGID = 0002000;
- public static final int S_ISVTX = 0001000;
-
- public static final int S_IRWXU = 00700;
- public static final int S_IRUSR = 00400;
- public static final int S_IWUSR = 00200;
- public static final int S_IXUSR = 00100;
-
- public static final int S_IRWXG = 00070;
- public static final int S_IRGRP = 00040;
- public static final int S_IWGRP = 00020;
- public static final int S_IXGRP = 00010;
-
- public static final int S_IRWXO = 00007;
- public static final int S_IROTH = 00004;
- public static final int S_IWOTH = 00002;
- public static final int S_IXOTH = 00001;
-
- static {
- System.loadLibrary("cts_jni");
- }
-
- public static class FileStatus {
-
- public int dev;
- public int ino;
- public int mode;
- public int nlink;
- public int uid;
- public int gid;
- public int rdev;
- public long size;
- public int blksize;
- public long blocks;
- public long atime;
- public long mtime;
- public long ctime;
-
- public boolean hasModeFlag(int flag) {
- if (((S_IRWXU | S_IRWXG | S_IRWXO) & flag) != flag) {
- throw new IllegalArgumentException("Inappropriate flag " + flag);
- }
- return (mode & flag) == flag;
- }
-
- public boolean isOfType(int type) {
- if ((type & S_IFMT) != type) {
- throw new IllegalArgumentException("Unknown type " + type);
- }
- return (mode & S_IFMT) == type;
- }
- }
-
- /**
- * @param path of the file to stat
- * @param status object to set the fields on
- * @param statLinks or don't stat links (lstat vs stat)
- * @return whether or not we were able to stat the file
- */
- public native static boolean getFileStatus(String path, FileStatus status, boolean statLinks);
-
- public native static String getUserName(int uid);
-
- public native static String getGroupName(int gid);
-
- public native static int setPermissions(String file, int mode);
-
- /**
- * Copy data from a source stream to destFile.
- * Return true if succeed, return false if failed.
- */
- public static boolean copyToFile(InputStream inputStream, File destFile) {
- try {
- if (destFile.exists()) {
- destFile.delete();
- }
- FileOutputStream out = new FileOutputStream(destFile);
- try {
- byte[] buffer = new byte[4096];
- int bytesRead;
- while ((bytesRead = inputStream.read(buffer)) >= 0) {
- out.write(buffer, 0, bytesRead);
- }
- } finally {
- out.flush();
- try {
- out.getFD().sync();
- } catch (IOException e) {
- }
- out.close();
- }
- return true;
- } catch (IOException e) {
- return false;
- }
- }
-
- public static void createFile(File file, int numBytes) throws IOException {
- File parentFile = file.getParentFile();
- if (parentFile != null) {
- parentFile.mkdirs();
- }
- byte[] buffer = new byte[numBytes];
- FileOutputStream output = new FileOutputStream(file);
- try {
- output.write(buffer);
- } finally {
- output.close();
- }
- }
-
- public static byte[] readInputStreamFully(InputStream is) {
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- byte[] buffer = new byte[32768];
- int count;
- try {
- while ((count = is.read(buffer)) != -1) {
- os.write(buffer, 0, count);
- }
- is.close();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- return os.toByteArray();
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/IBinderParcelable.java b/common/device-side/util/src/com/android/compatibility/common/util/IBinderParcelable.java
deleted file mode 100644
index f3c53fe..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/IBinderParcelable.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2009 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.compatibility.common.util;
-
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class IBinderParcelable implements Parcelable {
- public IBinder binder;
-
- public IBinderParcelable(IBinder source) {
- binder = source;
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeStrongBinder(binder);
- }
-
- public static final Parcelable.Creator<IBinderParcelable>
- CREATOR = new Parcelable.Creator<IBinderParcelable>() {
-
- public IBinderParcelable createFromParcel(Parcel source) {
- return new IBinderParcelable(source);
- }
-
- public IBinderParcelable[] newArray(int size) {
- return new IBinderParcelable[size];
- }
- };
-
- private IBinderParcelable(Parcel source) {
- binder = source.readStrongBinder();
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ImeAwareEditText.java b/common/device-side/util/src/com/android/compatibility/common/util/ImeAwareEditText.java
deleted file mode 100644
index db148bf..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/ImeAwareEditText.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-
-public class ImeAwareEditText extends EditText {
- private boolean mHasPendingShowSoftInputRequest;
- final Runnable mRunShowSoftInputIfNecessary = () -> showSoftInputIfNecessary();
-
- public ImeAwareEditText(Context context) {
- super(context, null);
- }
-
- public ImeAwareEditText(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public ImeAwareEditText(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- public ImeAwareEditText(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
- /**
- * This method is called back by the system when the system is about to establish a connection
- * to the current input method.
- *
- * <p>This is a good and reliable signal to schedule a pending task to call
- * {@link InputMethodManager#showSoftInput(View, int)}.</p>
- *
- * @param editorInfo context about the text input field.
- * @return {@link InputConnection} to be passed to the input method.
- */
- @Override
- public InputConnection onCreateInputConnection(EditorInfo editorInfo) {
- final InputConnection ic = super.onCreateInputConnection(editorInfo);
- if (mHasPendingShowSoftInputRequest) {
- removeCallbacks(mRunShowSoftInputIfNecessary);
- post(mRunShowSoftInputIfNecessary);
- }
- return ic;
- }
-
- private void showSoftInputIfNecessary() {
- if (mHasPendingShowSoftInputRequest) {
- final InputMethodManager imm =
- getContext().getSystemService(InputMethodManager.class);
- imm.showSoftInput(this, 0);
- mHasPendingShowSoftInputRequest = false;
- }
- }
-
- public void scheduleShowSoftInput() {
- final InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
- if (imm.isActive(this)) {
- // This means that ImeAwareEditText is already connected to the IME.
- // InputMethodManager#showSoftInput() is guaranteed to pass client-side focus check.
- mHasPendingShowSoftInputRequest = false;
- removeCallbacks(mRunShowSoftInputIfNecessary);
- imm.showSoftInput(this, 0);
- return;
- }
-
- // Otherwise, InputMethodManager#showSoftInput() should be deferred after
- // onCreateInputConnection().
- mHasPendingShowSoftInputRequest = true;
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/LocationUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/LocationUtils.java
deleted file mode 100644
index f233851..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/LocationUtils.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2015 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.compatibility.common.util;
-
-import android.app.Instrumentation;
-import android.util.Log;
-
-import java.io.IOException;
-
-public class LocationUtils {
- private static String TAG = "LocationUtils";
-
- public static void registerMockLocationProvider(Instrumentation instrumentation,
- boolean enable) {
- StringBuilder command = new StringBuilder();
- command.append("appops set ");
- command.append(instrumentation.getContext().getPackageName());
- command.append(" android:mock_location ");
- command.append(enable ? "allow" : "deny");
- try {
- SystemUtil.runShellCommand(instrumentation, command.toString());
- } catch (IOException e) {
- Log.e(TAG, "Error managing mock location app. Command: " + command, e);
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/MediaPerfUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/MediaPerfUtils.java
deleted file mode 100644
index 469e99a..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/MediaPerfUtils.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright 2016 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.compatibility.common.util;
-
-import android.media.MediaFormat;
-import android.util.Range;
-
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-
-import java.util.Arrays;
-import android.util.Log;
-
-public class MediaPerfUtils {
- private static final String TAG = "MediaPerfUtils";
-
- private static final int MOVING_AVERAGE_NUM_FRAMES = 10;
- private static final int MOVING_AVERAGE_WINDOW_MS = 1000;
-
- // allow a variance of 2x for measured frame rates (e.g. half of lower-limit to double of
- // upper-limit of the published values). Also allow an extra 10% margin. This also acts as
- // a limit for the size of the published rates (e.g. upper-limit / lower-limit <= tolerance).
- private static final double FRAMERATE_TOLERANCE = 2.0 * 1.1;
-
- /*
- * ------------------ HELPER METHODS FOR ACHIEVABLE FRAME RATES ------------------
- */
-
- /** removes brackets from format to be included in JSON. */
- private static String formatForReport(MediaFormat format) {
- String asString = "" + format;
- return asString.substring(1, asString.length() - 1);
- }
-
- /**
- * Adds performance header info to |log| for |codecName|, |round|, |configFormat|, |inputFormat|
- * and |outputFormat|. Also appends same to |message| and returns the resulting base message
- * for logging purposes.
- */
- public static String addPerformanceHeadersToLog(
- DeviceReportLog log, String message, int round, String codecName,
- MediaFormat configFormat, MediaFormat inputFormat, MediaFormat outputFormat) {
- String mime = configFormat.getString(MediaFormat.KEY_MIME);
- int width = configFormat.getInteger(MediaFormat.KEY_WIDTH);
- int height = configFormat.getInteger(MediaFormat.KEY_HEIGHT);
-
- log.addValue("round", round, ResultType.NEUTRAL, ResultUnit.NONE);
- log.addValue("codec_name", codecName, ResultType.NEUTRAL, ResultUnit.NONE);
- log.addValue("mime_type", mime, ResultType.NEUTRAL, ResultUnit.NONE);
- log.addValue("width", width, ResultType.NEUTRAL, ResultUnit.NONE);
- log.addValue("height", height, ResultType.NEUTRAL, ResultUnit.NONE);
- log.addValue("config_format", formatForReport(configFormat),
- ResultType.NEUTRAL, ResultUnit.NONE);
- log.addValue("input_format", formatForReport(inputFormat),
- ResultType.NEUTRAL, ResultUnit.NONE);
- log.addValue("output_format", formatForReport(outputFormat),
- ResultType.NEUTRAL, ResultUnit.NONE);
-
- message += " codec=" + codecName + " round=" + round + " configFormat=" + configFormat
- + " inputFormat=" + inputFormat + " outputFormat=" + outputFormat;
-
- Range<Double> reported =
- MediaUtils.getVideoCapabilities(codecName, mime)
- .getAchievableFrameRatesFor(width, height);
- if (reported != null) {
- log.addValue("reported_low", reported.getLower(), ResultType.NEUTRAL, ResultUnit.FPS);
- log.addValue("reported_high", reported.getUpper(), ResultType.NEUTRAL, ResultUnit.FPS);
- message += " reported=" + reported.getLower() + "-" + reported.getUpper();
- }
-
- return message;
- }
-
- /**
- * Adds performance statistics based on the raw |stats| to |log|. Also prints the same into
- * logcat. Returns the "final fps" value.
- */
- public static double addPerformanceStatsToLog(
- DeviceReportLog log, MediaUtils.Stats durationsUsStats, String message) {
-
- MediaUtils.Stats frameAvgUsStats =
- durationsUsStats.movingAverage(MOVING_AVERAGE_NUM_FRAMES);
- log.addValue(
- "window_frames", MOVING_AVERAGE_NUM_FRAMES, ResultType.NEUTRAL, ResultUnit.COUNT);
- logPerformanceStats(log, frameAvgUsStats, "frame_avg_stats",
- message + " window=" + MOVING_AVERAGE_NUM_FRAMES);
-
- MediaUtils.Stats timeAvgUsStats =
- durationsUsStats.movingAverageOverSum(MOVING_AVERAGE_WINDOW_MS * 1000);
- log.addValue("window_time", MOVING_AVERAGE_WINDOW_MS, ResultType.NEUTRAL, ResultUnit.MS);
- double fps = logPerformanceStats(log, timeAvgUsStats, "time_avg_stats",
- message + " windowMs=" + MOVING_AVERAGE_WINDOW_MS);
-
- log.setSummary("fps", fps, ResultType.HIGHER_BETTER, ResultUnit.FPS);
- return fps;
- }
-
- /**
- * Adds performance statistics based on the processed |stats| to |log| using |prefix|.
- * Also prints the same into logcat using |message| as the base message. Returns the fps value
- * for |stats|. |prefix| must be lowercase alphanumeric underscored format.
- */
- private static double logPerformanceStats(
- DeviceReportLog log, MediaUtils.Stats statsUs, String prefix, String message) {
- final String[] labels = {
- "min", "p5", "p10", "p20", "p30", "p40", "p50", "p60", "p70", "p80", "p90", "p95", "max"
- };
- final double[] points = {
- 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 100
- };
-
- int num = statsUs.getNum();
- long avg = Math.round(statsUs.getAverage());
- long stdev = Math.round(statsUs.getStdev());
- log.addValue(prefix + "_num", num, ResultType.NEUTRAL, ResultUnit.COUNT);
- log.addValue(prefix + "_avg", avg / 1000., ResultType.LOWER_BETTER, ResultUnit.MS);
- log.addValue(prefix + "_stdev", stdev / 1000., ResultType.LOWER_BETTER, ResultUnit.MS);
- message += " num=" + num + " avg=" + avg + " stdev=" + stdev;
- final double[] percentiles = statsUs.getPercentiles(points);
- for (int i = 0; i < labels.length; ++i) {
- long p = Math.round(percentiles[i]);
- message += " " + labels[i] + "=" + p;
- log.addValue(prefix + "_" + labels[i], p / 1000., ResultType.NEUTRAL, ResultUnit.MS);
- }
-
- // print result to logcat in case test aborts before logs are written
- Log.i(TAG, message);
-
- return 1e6 / percentiles[points.length - 2];
- }
-
- /** Verifies |measuredFps| against reported achievable rates. Returns null if at least
- * one measurement falls within the margins of the reported range. Otherwise, returns
- * an error message to display.*/
- public static String verifyAchievableFrameRates(
- String name, String mime, int w, int h, double... measuredFps) {
- Range<Double> reported =
- MediaUtils.getVideoCapabilities(name, mime).getAchievableFrameRatesFor(w, h);
- String kind = "achievable frame rates for " + name + " " + mime + " " + w + "x" + h;
- if (reported == null) {
- return "Failed to get " + kind;
- }
- double lowerBoundary1 = reported.getLower() / FRAMERATE_TOLERANCE;
- double upperBoundary1 = reported.getUpper() * FRAMERATE_TOLERANCE;
- double lowerBoundary2 = reported.getUpper() / Math.pow(FRAMERATE_TOLERANCE, 2);
- double upperBoundary2 = reported.getLower() * Math.pow(FRAMERATE_TOLERANCE, 2);
- Log.d(TAG, name + " " + mime + " " + w + "x" + h +
- " lowerBoundary1 " + lowerBoundary1 + " upperBoundary1 " + upperBoundary1 +
- " lowerBoundary2 " + lowerBoundary2 + " upperBoundary2 " + upperBoundary2 +
- " measured " + Arrays.toString(measuredFps));
-
- for (double measured : measuredFps) {
- if (measured >= lowerBoundary1 && measured <= upperBoundary1
- && measured >= lowerBoundary2 && measured <= upperBoundary2) {
- return null;
- }
- }
-
- return "Expected " + kind + ": " + reported + ".\n"
- + "Measured frame rate: " + Arrays.toString(measuredFps) + ".\n";
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/MediaUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/MediaUtils.java
deleted file mode 100644
index 3ea6b63..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/MediaUtils.java
+++ /dev/null
@@ -1,1232 +0,0 @@
-/*
- * Copyright 2014 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.compatibility.common.util;
-
-import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.drm.DrmConvertedStatus;
-import android.drm.DrmManagerClient;
-import android.graphics.ImageFormat;
-import android.media.Image;
-import android.media.Image.Plane;
-import android.media.MediaCodec;
-import android.media.MediaCodec.BufferInfo;
-import android.media.MediaCodecInfo;
-import android.media.MediaCodecInfo.CodecCapabilities;
-import android.media.MediaCodecInfo.VideoCapabilities;
-import android.media.MediaCodecList;
-import android.media.MediaExtractor;
-import android.media.MediaFormat;
-import android.net.Uri;
-import android.util.Log;
-import android.util.Range;
-
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-
-import java.lang.reflect.Method;
-import java.nio.ByteBuffer;
-import java.security.MessageDigest;
-
-import static java.lang.reflect.Modifier.isPublic;
-import static java.lang.reflect.Modifier.isStatic;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-import static junit.framework.Assert.assertTrue;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.RandomAccessFile;
-
-public class MediaUtils {
- private static final String TAG = "MediaUtils";
-
- /*
- * ----------------------- HELPER METHODS FOR SKIPPING TESTS -----------------------
- */
- private static final int ALL_AV_TRACKS = -1;
-
- private static final MediaCodecList sMCL = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-
- /**
- * Returns the test name (heuristically).
- *
- * Since it uses heuristics, this method has only been verified for media
- * tests. This centralizes the way to signal errors during a test.
- */
- public static String getTestName() {
- return getTestName(false /* withClass */);
- }
-
- /**
- * Returns the test name with the full class (heuristically).
- *
- * Since it uses heuristics, this method has only been verified for media
- * tests. This centralizes the way to signal errors during a test.
- */
- public static String getTestNameWithClass() {
- return getTestName(true /* withClass */);
- }
-
- private static String getTestName(boolean withClass) {
- int bestScore = -1;
- String testName = "test???";
- Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
- for (Map.Entry<Thread, StackTraceElement[]> entry : traces.entrySet()) {
- StackTraceElement[] stack = entry.getValue();
- for (int index = 0; index < stack.length; ++index) {
- // method name must start with "test"
- String methodName = stack[index].getMethodName();
- if (!methodName.startsWith("test")) {
- continue;
- }
-
- int score = 0;
- // see if there is a public non-static void method that takes no argument
- Class<?> clazz;
- try {
- clazz = Class.forName(stack[index].getClassName());
- ++score;
- for (final Method method : clazz.getDeclaredMethods()) {
- if (method.getName().equals(methodName)
- && isPublic(method.getModifiers())
- && !isStatic(method.getModifiers())
- && method.getParameterTypes().length == 0
- && method.getReturnType().equals(Void.TYPE)) {
- ++score;
- break;
- }
- }
- if (score == 1) {
- // if we could read the class, but method is not public void, it is
- // not a candidate
- continue;
- }
- } catch (ClassNotFoundException e) {
- }
-
- // even if we cannot verify the method signature, there are signals in the stack
-
- // usually test method is invoked by reflection
- int depth = 1;
- while (index + depth < stack.length
- && stack[index + depth].getMethodName().equals("invoke")
- && stack[index + depth].getClassName().equals(
- "java.lang.reflect.Method")) {
- ++depth;
- }
- if (depth > 1) {
- ++score;
- // and usually test method is run by runMethod method in android.test package
- if (index + depth < stack.length) {
- if (stack[index + depth].getClassName().startsWith("android.test.")) {
- ++score;
- }
- if (stack[index + depth].getMethodName().equals("runMethod")) {
- ++score;
- }
- }
- }
-
- if (score > bestScore) {
- bestScore = score;
- testName = methodName;
- if (withClass) {
- testName = stack[index].getClassName() + "." + testName;
- }
- }
- }
- }
- return testName;
- }
-
- /**
- * Finds test name (heuristically) and prints out standard skip message.
- *
- * Since it uses heuristics, this method has only been verified for media
- * tests. This centralizes the way to signal a skipped test.
- */
- public static void skipTest(String tag, String reason) {
- Log.i(tag, "SKIPPING " + getTestName() + "(): " + reason);
- DeviceReportLog log = new DeviceReportLog("CtsMediaSkippedTests", "test_skipped");
- try {
- log.addValue("reason", reason, ResultType.NEUTRAL, ResultUnit.NONE);
- log.addValue(
- "test", getTestNameWithClass(), ResultType.NEUTRAL, ResultUnit.NONE);
- log.submit();
- } catch (NullPointerException e) { }
- }
-
- /**
- * Finds test name (heuristically) and prints out standard skip message.
- *
- * Since it uses heuristics, this method has only been verified for media
- * tests. This centralizes the way to signal a skipped test.
- */
- public static void skipTest(String reason) {
- skipTest(TAG, reason);
- }
-
- public static boolean check(boolean result, String message) {
- if (!result) {
- skipTest(message);
- }
- return result;
- }
-
- /*
- * ------------------- HELPER METHODS FOR CHECKING CODEC SUPPORT -------------------
- */
-
- public static boolean isGoogle(String codecName) {
- codecName = codecName.toLowerCase();
- return codecName.startsWith("omx.google.")
- || codecName.startsWith("c2.android.")
- || codecName.startsWith("c2.google.");
- }
-
- // returns the list of codecs that support any one of the formats
- private static String[] getCodecNames(
- boolean isEncoder, Boolean isGoog, MediaFormat... formats) {
- MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
- ArrayList<String> result = new ArrayList<>();
- for (MediaCodecInfo info : mcl.getCodecInfos()) {
- if (info.isEncoder() != isEncoder) {
- continue;
- }
- if (isGoog != null && isGoogle(info.getName()) != isGoog) {
- continue;
- }
-
- for (MediaFormat format : formats) {
- String mime = format.getString(MediaFormat.KEY_MIME);
-
- CodecCapabilities caps = null;
- try {
- caps = info.getCapabilitiesForType(mime);
- } catch (IllegalArgumentException e) { // mime is not supported
- continue;
- }
- if (caps.isFormatSupported(format)) {
- result.add(info.getName());
- break;
- }
- }
- }
- return result.toArray(new String[result.size()]);
- }
-
- /* Use isGoog = null to query all decoders */
- public static String[] getDecoderNames(/* Nullable */ Boolean isGoog, MediaFormat... formats) {
- return getCodecNames(false /* isEncoder */, isGoog, formats);
- }
-
- public static String[] getDecoderNames(MediaFormat... formats) {
- return getCodecNames(false /* isEncoder */, null /* isGoog */, formats);
- }
-
- /* Use isGoog = null to query all decoders */
- public static String[] getEncoderNames(/* Nullable */ Boolean isGoog, MediaFormat... formats) {
- return getCodecNames(true /* isEncoder */, isGoog, formats);
- }
-
- public static String[] getEncoderNames(MediaFormat... formats) {
- return getCodecNames(true /* isEncoder */, null /* isGoog */, formats);
- }
-
- public static String[] getDecoderNamesForMime(String mime) {
- MediaFormat format = new MediaFormat();
- format.setString(MediaFormat.KEY_MIME, mime);
- return getCodecNames(false /* isEncoder */, null /* isGoog */, format);
- }
-
- public static String[] getEncoderNamesForMime(String mime) {
- MediaFormat format = new MediaFormat();
- format.setString(MediaFormat.KEY_MIME, mime);
- return getCodecNames(true /* isEncoder */, null /* isGoog */, format);
- }
-
- public static void verifyNumCodecs(
- int count, boolean isEncoder, Boolean isGoog, MediaFormat... formats) {
- String desc = (isEncoder ? "encoders" : "decoders") + " for "
- + (formats.length == 1 ? formats[0].toString() : Arrays.toString(formats));
- if (isGoog != null) {
- desc = (isGoog ? "Google " : "non-Google ") + desc;
- }
-
- String[] codecs = getCodecNames(isEncoder, isGoog, formats);
- assertTrue("test can only verify " + count + " " + desc + "; found " + codecs.length + ": "
- + Arrays.toString(codecs), codecs.length <= count);
- }
-
- public static MediaCodec getDecoder(MediaFormat format) {
- String decoder = sMCL.findDecoderForFormat(format);
- if (decoder != null) {
- try {
- return MediaCodec.createByCodecName(decoder);
- } catch (IOException e) {
- }
- }
- return null;
- }
-
- public static boolean canEncode(MediaFormat format) {
- if (sMCL.findEncoderForFormat(format) == null) {
- Log.i(TAG, "no encoder for " + format);
- return false;
- }
- return true;
- }
-
- public static boolean canDecode(MediaFormat format) {
- if (sMCL.findDecoderForFormat(format) == null) {
- Log.i(TAG, "no decoder for " + format);
- return false;
- }
- return true;
- }
-
- public static boolean supports(String codecName, String mime, int w, int h) {
- // While this could be simply written as such, give more graceful feedback.
- // MediaFormat format = MediaFormat.createVideoFormat(mime, w, h);
- // return supports(codecName, format);
-
- VideoCapabilities vidCap = getVideoCapabilities(codecName, mime);
- if (vidCap == null) {
- return false;
- } else if (vidCap.isSizeSupported(w, h)) {
- return true;
- }
-
- Log.w(TAG, "unsupported size " + w + "x" + h);
- return false;
- }
-
- public static boolean supports(String codecName, MediaFormat format) {
- MediaCodec codec;
- try {
- codec = MediaCodec.createByCodecName(codecName);
- } catch (IOException e) {
- Log.w(TAG, "codec not found: " + codecName);
- return false;
- }
-
- String mime = format.getString(MediaFormat.KEY_MIME);
- CodecCapabilities cap = null;
- try {
- cap = codec.getCodecInfo().getCapabilitiesForType(mime);
- return cap.isFormatSupported(format);
- } catch (IllegalArgumentException e) {
- Log.w(TAG, "not supported mime: " + mime);
- return false;
- } finally {
- codec.release();
- }
- }
-
- public static boolean hasCodecForTrack(MediaExtractor ex, int track) {
- int count = ex.getTrackCount();
- if (track < 0 || track >= count) {
- throw new IndexOutOfBoundsException(track + " not in [0.." + (count - 1) + "]");
- }
- return canDecode(ex.getTrackFormat(track));
- }
-
- /**
- * return true iff all audio and video tracks are supported
- */
- public static boolean hasCodecsForMedia(MediaExtractor ex) {
- for (int i = 0; i < ex.getTrackCount(); ++i) {
- MediaFormat format = ex.getTrackFormat(i);
- // only check for audio and video codecs
- String mime = format.getString(MediaFormat.KEY_MIME).toLowerCase();
- if (!mime.startsWith("audio/") && !mime.startsWith("video/")) {
- continue;
- }
- if (!canDecode(format)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * return true iff any track starting with mimePrefix is supported
- */
- public static boolean hasCodecForMediaAndDomain(MediaExtractor ex, String mimePrefix) {
- mimePrefix = mimePrefix.toLowerCase();
- for (int i = 0; i < ex.getTrackCount(); ++i) {
- MediaFormat format = ex.getTrackFormat(i);
- String mime = format.getString(MediaFormat.KEY_MIME);
- if (mime.toLowerCase().startsWith(mimePrefix)) {
- if (canDecode(format)) {
- return true;
- }
- Log.i(TAG, "no decoder for " + format);
- }
- }
- return false;
- }
-
- private static boolean hasCodecsForResourceCombo(
- Context context, int resourceId, int track, String mimePrefix) {
- try {
- AssetFileDescriptor afd = null;
- MediaExtractor ex = null;
- try {
- afd = context.getResources().openRawResourceFd(resourceId);
- ex = new MediaExtractor();
- ex.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
- if (mimePrefix != null) {
- return hasCodecForMediaAndDomain(ex, mimePrefix);
- } else if (track == ALL_AV_TRACKS) {
- return hasCodecsForMedia(ex);
- } else {
- return hasCodecForTrack(ex, track);
- }
- } finally {
- if (ex != null) {
- ex.release();
- }
- if (afd != null) {
- afd.close();
- }
- }
- } catch (IOException e) {
- Log.i(TAG, "could not open resource");
- }
- return false;
- }
-
- /**
- * return true iff all audio and video tracks are supported
- */
- public static boolean hasCodecsForResource(Context context, int resourceId) {
- return hasCodecsForResourceCombo(context, resourceId, ALL_AV_TRACKS, null /* mimePrefix */);
- }
-
- public static boolean checkCodecsForResource(Context context, int resourceId) {
- return check(hasCodecsForResource(context, resourceId), "no decoder found");
- }
-
- /**
- * return true iff track is supported.
- */
- public static boolean hasCodecForResource(Context context, int resourceId, int track) {
- return hasCodecsForResourceCombo(context, resourceId, track, null /* mimePrefix */);
- }
-
- public static boolean checkCodecForResource(Context context, int resourceId, int track) {
- return check(hasCodecForResource(context, resourceId, track), "no decoder found");
- }
-
- /**
- * return true iff any track starting with mimePrefix is supported
- */
- public static boolean hasCodecForResourceAndDomain(
- Context context, int resourceId, String mimePrefix) {
- return hasCodecsForResourceCombo(context, resourceId, ALL_AV_TRACKS, mimePrefix);
- }
-
- /**
- * return true iff all audio and video tracks are supported
- */
- public static boolean hasCodecsForPath(Context context, String path) {
- MediaExtractor ex = null;
- try {
- ex = getExtractorForPath(context, path);
- return hasCodecsForMedia(ex);
- } catch (IOException e) {
- Log.i(TAG, "could not open path " + path);
- } finally {
- if (ex != null) {
- ex.release();
- }
- }
- return true;
- }
-
- private static MediaExtractor getExtractorForPath(Context context, String path)
- throws IOException {
- Uri uri = Uri.parse(path);
- String scheme = uri.getScheme();
- MediaExtractor ex = new MediaExtractor();
- try {
- if (scheme == null) { // file
- ex.setDataSource(path);
- } else if (scheme.equalsIgnoreCase("file")) {
- ex.setDataSource(uri.getPath());
- } else {
- ex.setDataSource(context, uri, null);
- }
- } catch (IOException e) {
- ex.release();
- throw e;
- }
- return ex;
- }
-
- public static boolean checkCodecsForPath(Context context, String path) {
- return check(hasCodecsForPath(context, path), "no decoder found");
- }
-
- public static boolean hasCodecForDomain(boolean encoder, String domain) {
- for (MediaCodecInfo info : sMCL.getCodecInfos()) {
- if (encoder != info.isEncoder()) {
- continue;
- }
-
- for (String type : info.getSupportedTypes()) {
- if (type.toLowerCase().startsWith(domain.toLowerCase() + "/")) {
- Log.i(TAG, "found codec " + info.getName() + " for mime " + type);
- return true;
- }
- }
- }
- return false;
- }
-
- public static boolean checkCodecForDomain(boolean encoder, String domain) {
- return check(hasCodecForDomain(encoder, domain),
- "no " + domain + (encoder ? " encoder" : " decoder") + " found");
- }
-
- private static boolean hasCodecForMime(boolean encoder, String mime) {
- for (MediaCodecInfo info : sMCL.getCodecInfos()) {
- if (encoder != info.isEncoder()) {
- continue;
- }
-
- for (String type : info.getSupportedTypes()) {
- if (type.equalsIgnoreCase(mime)) {
- Log.i(TAG, "found codec " + info.getName() + " for mime " + mime);
- return true;
- }
- }
- }
- return false;
- }
-
- private static boolean hasCodecForMimes(boolean encoder, String[] mimes) {
- for (String mime : mimes) {
- if (!hasCodecForMime(encoder, mime)) {
- Log.i(TAG, "no " + (encoder ? "encoder" : "decoder") + " for mime " + mime);
- return false;
- }
- }
- return true;
- }
-
-
- public static boolean hasEncoder(String... mimes) {
- return hasCodecForMimes(true /* encoder */, mimes);
- }
-
- public static boolean hasDecoder(String... mimes) {
- return hasCodecForMimes(false /* encoder */, mimes);
- }
-
- public static boolean checkDecoder(String... mimes) {
- return check(hasCodecForMimes(false /* encoder */, mimes), "no decoder found");
- }
-
- public static boolean checkEncoder(String... mimes) {
- return check(hasCodecForMimes(true /* encoder */, mimes), "no encoder found");
- }
-
- public static boolean canDecodeVideo(String mime, int width, int height, float rate) {
- MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
- format.setFloat(MediaFormat.KEY_FRAME_RATE, rate);
- return canDecode(format);
- }
-
- public static boolean canDecodeVideo(
- String mime, int width, int height, float rate,
- Integer profile, Integer level, Integer bitrate) {
- MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
- format.setFloat(MediaFormat.KEY_FRAME_RATE, rate);
- if (profile != null) {
- format.setInteger(MediaFormat.KEY_PROFILE, profile);
- if (level != null) {
- format.setInteger(MediaFormat.KEY_LEVEL, level);
- }
- }
- if (bitrate != null) {
- format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
- }
- return canDecode(format);
- }
-
- public static boolean checkEncoderForFormat(MediaFormat format) {
- return check(canEncode(format), "no encoder for " + format);
- }
-
- public static boolean checkDecoderForFormat(MediaFormat format) {
- return check(canDecode(format), "no decoder for " + format);
- }
-
- /*
- * ----------------------- HELPER METHODS FOR MEDIA HANDLING -----------------------
- */
-
- public static VideoCapabilities getVideoCapabilities(String codecName, String mime) {
- for (MediaCodecInfo info : sMCL.getCodecInfos()) {
- if (!info.getName().equalsIgnoreCase(codecName)) {
- continue;
- }
- CodecCapabilities caps;
- try {
- caps = info.getCapabilitiesForType(mime);
- } catch (IllegalArgumentException e) {
- // mime is not supported
- Log.w(TAG, "not supported mime: " + mime);
- return null;
- }
- VideoCapabilities vidCaps = caps.getVideoCapabilities();
- if (vidCaps == null) {
- Log.w(TAG, "not a video codec: " + codecName);
- }
- return vidCaps;
- }
- Log.w(TAG, "codec not found: " + codecName);
- return null;
- }
-
- public static MediaFormat getTrackFormatForResource(
- Context context,
- int resourceId,
- String mimeTypePrefix) throws IOException {
- MediaExtractor extractor = new MediaExtractor();
- AssetFileDescriptor afd = context.getResources().openRawResourceFd(resourceId);
- try {
- extractor.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
- } finally {
- afd.close();
- }
- return getTrackFormatForExtractor(extractor, mimeTypePrefix);
- }
-
- public static MediaFormat getTrackFormatForPath(
- Context context, String path, String mimeTypePrefix)
- throws IOException {
- MediaExtractor extractor = getExtractorForPath(context, path);
- return getTrackFormatForExtractor(extractor, mimeTypePrefix);
- }
-
- private static MediaFormat getTrackFormatForExtractor(
- MediaExtractor extractor,
- String mimeTypePrefix) {
- int trackIndex;
- MediaFormat format = null;
- for (trackIndex = 0; trackIndex < extractor.getTrackCount(); trackIndex++) {
- MediaFormat trackMediaFormat = extractor.getTrackFormat(trackIndex);
- if (trackMediaFormat.getString(MediaFormat.KEY_MIME).startsWith(mimeTypePrefix)) {
- format = trackMediaFormat;
- break;
- }
- }
- extractor.release();
- if (format == null) {
- throw new RuntimeException("couldn't get a track for " + mimeTypePrefix);
- }
-
- return format;
- }
-
- public static MediaExtractor createMediaExtractorForMimeType(
- Context context, int resourceId, String mimeTypePrefix)
- throws IOException {
- MediaExtractor extractor = new MediaExtractor();
- AssetFileDescriptor afd = context.getResources().openRawResourceFd(resourceId);
- try {
- extractor.setDataSource(
- afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
- } finally {
- afd.close();
- }
- int trackIndex;
- for (trackIndex = 0; trackIndex < extractor.getTrackCount(); trackIndex++) {
- MediaFormat trackMediaFormat = extractor.getTrackFormat(trackIndex);
- if (trackMediaFormat.getString(MediaFormat.KEY_MIME).startsWith(mimeTypePrefix)) {
- extractor.selectTrack(trackIndex);
- break;
- }
- }
- if (trackIndex == extractor.getTrackCount()) {
- extractor.release();
- throw new IllegalStateException("couldn't get a track for " + mimeTypePrefix);
- }
-
- return extractor;
- }
-
- /*
- * ---------------------- HELPER METHODS FOR CODEC CONFIGURATION
- */
-
- /** Format must contain mime, width and height.
- * Throws Exception if encoder does not support this width and height */
- public static void setMaxEncoderFrameAndBitrates(
- MediaCodec encoder, MediaFormat format, int maxFps) {
- String mime = format.getString(MediaFormat.KEY_MIME);
-
- VideoCapabilities vidCaps =
- encoder.getCodecInfo().getCapabilitiesForType(mime).getVideoCapabilities();
- setMaxEncoderFrameAndBitrates(vidCaps, format, maxFps);
- }
-
- public static void setMaxEncoderFrameAndBitrates(
- VideoCapabilities vidCaps, MediaFormat format, int maxFps) {
- int width = format.getInteger(MediaFormat.KEY_WIDTH);
- int height = format.getInteger(MediaFormat.KEY_HEIGHT);
-
- int maxWidth = vidCaps.getSupportedWidths().getUpper();
- int maxHeight = vidCaps.getSupportedHeightsFor(maxWidth).getUpper();
- int frameRate = Math.min(
- maxFps, vidCaps.getSupportedFrameRatesFor(width, height).getUpper().intValue());
- format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
-
- int bitrate = vidCaps.getBitrateRange().clamp(
- (int)(vidCaps.getBitrateRange().getUpper() /
- Math.sqrt((double)maxWidth * maxHeight / width / height)));
- format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
- }
-
- /*
- * ------------------ HELPER METHODS FOR STATISTICS AND REPORTING ------------------
- */
-
- // TODO: migrate this into com.android.compatibility.common.util.Stat
- public static class Stats {
- /** does not support NaN or Inf in |data| */
- public Stats(double[] data) {
- mData = data;
- if (mData != null) {
- mNum = mData.length;
- }
- }
-
- public int getNum() {
- return mNum;
- }
-
- /** calculate mSumX and mSumXX */
- private void analyze() {
- if (mAnalyzed) {
- return;
- }
-
- if (mData != null) {
- for (double x : mData) {
- if (!(x >= mMinX)) { // mMinX may be NaN
- mMinX = x;
- }
- if (!(x <= mMaxX)) { // mMaxX may be NaN
- mMaxX = x;
- }
- mSumX += x;
- mSumXX += x * x;
- }
- }
- mAnalyzed = true;
- }
-
- /** returns the maximum or NaN if it does not exist */
- public double getMin() {
- analyze();
- return mMinX;
- }
-
- /** returns the minimum or NaN if it does not exist */
- public double getMax() {
- analyze();
- return mMaxX;
- }
-
- /** returns the average or NaN if it does not exist. */
- public double getAverage() {
- analyze();
- if (mNum == 0) {
- return Double.NaN;
- } else {
- return mSumX / mNum;
- }
- }
-
- /** returns the standard deviation or NaN if it does not exist. */
- public double getStdev() {
- analyze();
- if (mNum == 0) {
- return Double.NaN;
- } else {
- double average = mSumX / mNum;
- return Math.sqrt(mSumXX / mNum - average * average);
- }
- }
-
- /** returns the statistics for the moving average over n values */
- public Stats movingAverage(int n) {
- if (n < 1 || mNum < n) {
- return new Stats(null);
- } else if (n == 1) {
- return this;
- }
-
- double[] avgs = new double[mNum - n + 1];
- double sum = 0;
- for (int i = 0; i < mNum; ++i) {
- sum += mData[i];
- if (i >= n - 1) {
- avgs[i - n + 1] = sum / n;
- sum -= mData[i - n + 1];
- }
- }
- return new Stats(avgs);
- }
-
- /** returns the statistics for the moving average over a window over the
- * cumulative sum. Basically, moves a window from: [0, window] to
- * [sum - window, sum] over the cumulative sum, over ((sum - window) / average)
- * steps, and returns the average value over each window.
- * This method is used to average time-diff data over a window of a constant time.
- */
- public Stats movingAverageOverSum(double window) {
- if (window <= 0 || mNum < 1) {
- return new Stats(null);
- }
-
- analyze();
- double average = mSumX / mNum;
- if (window >= mSumX) {
- return new Stats(new double[] { average });
- }
- int samples = (int)Math.ceil((mSumX - window) / average);
- double[] avgs = new double[samples];
-
- // A somewhat brute force approach to calculating the moving average.
- // TODO: add support for weights in Stats, so we can do a more refined approach.
- double sum = 0; // sum of elements in the window
- int num = 0; // number of elements in the moving window
- int bi = 0; // index of the first element in the moving window
- int ei = 0; // index of the last element in the moving window
- double space = window; // space at the end of the window
- double foot = 0; // space at the beginning of the window
-
- // invariants: foot + sum + space == window
- // bi + num == ei
- //
- // window: |-------------------------------|
- // | <-----sum------> |
- // <foot> <---space-->
- // | |
- // intervals: |-----------|-------|-------|--------------------|--------|
- // ^bi ^ei
-
- int ix = 0; // index in the result
- while (ix < samples) {
- // add intervals while there is space in the window
- while (ei < mData.length && mData[ei] <= space) {
- space -= mData[ei];
- sum += mData[ei];
- num++;
- ei++;
- }
-
- // calculate average over window and deal with odds and ends (e.g. if there are no
- // intervals in the current window: pick whichever element overlaps the window
- // most.
- if (num > 0) {
- avgs[ix++] = sum / num;
- } else if (bi > 0 && foot > space) {
- // consider previous
- avgs[ix++] = mData[bi - 1];
- } else if (ei == mData.length) {
- break;
- } else {
- avgs[ix++] = mData[ei];
- }
-
- // move the window to the next position
- foot -= average;
- space += average;
-
- // remove intervals that are now partially or wholly outside of the window
- while (bi < ei && foot < 0) {
- foot += mData[bi];
- sum -= mData[bi];
- num--;
- bi++;
- }
- }
- return new Stats(Arrays.copyOf(avgs, ix));
- }
-
- /** calculate mSortedData */
- private void sort() {
- if (mSorted || mNum == 0) {
- return;
- }
- mSortedData = Arrays.copyOf(mData, mNum);
- Arrays.sort(mSortedData);
- mSorted = true;
- }
-
- /** returns an array of percentiles for the points using nearest rank */
- public double[] getPercentiles(double... points) {
- sort();
- double[] res = new double[points.length];
- for (int i = 0; i < points.length; ++i) {
- if (mNum < 1 || points[i] < 0 || points[i] > 100) {
- res[i] = Double.NaN;
- } else {
- res[i] = mSortedData[(int)Math.round(points[i] / 100 * (mNum - 1))];
- }
- }
- return res;
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof Stats) {
- Stats other = (Stats)o;
- if (other.mNum != mNum) {
- return false;
- } else if (mNum == 0) {
- return true;
- }
- return Arrays.equals(mData, other.mData);
- }
- return false;
- }
-
- private double[] mData;
- private double mSumX = 0;
- private double mSumXX = 0;
- private double mMinX = Double.NaN;
- private double mMaxX = Double.NaN;
- private int mNum = 0;
- private boolean mAnalyzed = false;
- private double[] mSortedData;
- private boolean mSorted = false;
- }
-
- /**
- * Convert a forward lock .dm message stream to a .fl file
- * @param context Context to use
- * @param dmStream The .dm message
- * @param flFile The output file to be written
- * @return success
- */
- public static boolean convertDmToFl(
- Context context,
- InputStream dmStream,
- RandomAccessFile flFile) {
- final String MIMETYPE_DRM_MESSAGE = "application/vnd.oma.drm.message";
- byte[] dmData = new byte[10000];
- int totalRead = 0;
- int numRead;
- while (true) {
- try {
- numRead = dmStream.read(dmData, totalRead, dmData.length - totalRead);
- } catch (IOException e) {
- Log.w(TAG, "Failed to read from input file");
- return false;
- }
- if (numRead == -1) {
- break;
- }
- totalRead += numRead;
- if (totalRead == dmData.length) {
- // grow array
- dmData = Arrays.copyOf(dmData, dmData.length + 10000);
- }
- }
- byte[] fileData = Arrays.copyOf(dmData, totalRead);
-
- DrmManagerClient drmClient = null;
- try {
- drmClient = new DrmManagerClient(context);
- } catch (IllegalArgumentException e) {
- Log.w(TAG, "DrmManagerClient instance could not be created, context is Illegal.");
- return false;
- } catch (IllegalStateException e) {
- Log.w(TAG, "DrmManagerClient didn't initialize properly.");
- return false;
- }
-
- try {
- int convertSessionId = -1;
- try {
- convertSessionId = drmClient.openConvertSession(MIMETYPE_DRM_MESSAGE);
- } catch (IllegalArgumentException e) {
- Log.w(TAG, "Conversion of Mimetype: " + MIMETYPE_DRM_MESSAGE
- + " is not supported.", e);
- return false;
- } catch (IllegalStateException e) {
- Log.w(TAG, "Could not access Open DrmFramework.", e);
- return false;
- }
-
- if (convertSessionId < 0) {
- Log.w(TAG, "Failed to open session.");
- return false;
- }
-
- DrmConvertedStatus convertedStatus = null;
- try {
- convertedStatus = drmClient.convertData(convertSessionId, fileData);
- } catch (IllegalArgumentException e) {
- Log.w(TAG, "Buffer with data to convert is illegal. Convertsession: "
- + convertSessionId, e);
- return false;
- } catch (IllegalStateException e) {
- Log.w(TAG, "Could not convert data. Convertsession: " + convertSessionId, e);
- return false;
- }
-
- if (convertedStatus == null ||
- convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK ||
- convertedStatus.convertedData == null) {
- Log.w(TAG, "Error in converting data. Convertsession: " + convertSessionId);
- try {
- DrmConvertedStatus result = drmClient.closeConvertSession(convertSessionId);
- if (result.statusCode != DrmConvertedStatus.STATUS_OK) {
- Log.w(TAG, "Conversion failed with status: " + result.statusCode);
- return false;
- }
- } catch (IllegalStateException e) {
- Log.w(TAG, "Could not close session. Convertsession: " +
- convertSessionId, e);
- }
- return false;
- }
-
- try {
- flFile.write(convertedStatus.convertedData, 0, convertedStatus.convertedData.length);
- } catch (IOException e) {
- Log.w(TAG, "Failed to write to output file: " + e);
- return false;
- }
-
- try {
- convertedStatus = drmClient.closeConvertSession(convertSessionId);
- } catch (IllegalStateException e) {
- Log.w(TAG, "Could not close convertsession. Convertsession: " +
- convertSessionId, e);
- return false;
- }
-
- if (convertedStatus == null ||
- convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK ||
- convertedStatus.convertedData == null) {
- Log.w(TAG, "Error in closing session. Convertsession: " + convertSessionId);
- return false;
- }
-
- try {
- flFile.seek(convertedStatus.offset);
- flFile.write(convertedStatus.convertedData);
- } catch (IOException e) {
- Log.w(TAG, "Could not update file.", e);
- return false;
- }
-
- return true;
- } finally {
- drmClient.close();
- }
- }
-
- /**
- * @param decoder new MediaCodec object
- * @param ex MediaExtractor after setDataSource and selectTrack
- * @param frameMD5Sums reference MD5 checksum for decoded frames
- * @return true if decoded frames checksums matches reference checksums
- * @throws IOException
- */
- public static boolean verifyDecoder(
- MediaCodec decoder, MediaExtractor ex, List<String> frameMD5Sums)
- throws IOException {
-
- int trackIndex = ex.getSampleTrackIndex();
- MediaFormat format = ex.getTrackFormat(trackIndex);
- decoder.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
- decoder.start();
-
- boolean sawInputEOS = false;
- boolean sawOutputEOS = false;
- final long kTimeOutUs = 5000; // 5ms timeout
- int decodedFrameCount = 0;
- int expectedFrameCount = frameMD5Sums.size();
- MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
-
- while (!sawOutputEOS) {
- // handle input
- if (!sawInputEOS) {
- int inIdx = decoder.dequeueInputBuffer(kTimeOutUs);
- if (inIdx >= 0) {
- ByteBuffer buffer = decoder.getInputBuffer(inIdx);
- int sampleSize = ex.readSampleData(buffer, 0);
- if (sampleSize < 0) {
- final int flagEOS = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
- decoder.queueInputBuffer(inIdx, 0, 0, 0, flagEOS);
- sawInputEOS = true;
- } else {
- decoder.queueInputBuffer(inIdx, 0, sampleSize, ex.getSampleTime(), 0);
- ex.advance();
- }
- }
- }
-
- // handle output
- int outputBufIndex = decoder.dequeueOutputBuffer(info, kTimeOutUs);
- if (outputBufIndex >= 0) {
- try {
- if (info.size > 0) {
- // Disregard 0-sized buffers at the end.
- String md5CheckSum = "";
- Image image = decoder.getOutputImage(outputBufIndex);
- md5CheckSum = getImageMD5Checksum(image);
-
- if (!md5CheckSum.equals(frameMD5Sums.get(decodedFrameCount))) {
- Log.d(TAG,
- String.format(
- "Frame %d md5sum mismatch: %s(actual) vs %s(expected)",
- decodedFrameCount, md5CheckSum,
- frameMD5Sums.get(decodedFrameCount)));
- return false;
- }
-
- decodedFrameCount++;
- }
- } catch (Exception e) {
- Log.e(TAG, "getOutputImage md5CheckSum failed", e);
- return false;
- } finally {
- decoder.releaseOutputBuffer(outputBufIndex, false /* render */);
- }
- if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
- sawOutputEOS = true;
- }
- } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
- MediaFormat decOutputFormat = decoder.getOutputFormat();
- Log.d(TAG, "output format " + decOutputFormat);
- } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
- Log.i(TAG, "Skip handling MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED");
- } else if (outputBufIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
- continue;
- } else {
- Log.w(TAG, "decoder.dequeueOutputBuffer() unrecognized index: " + outputBufIndex);
- return false;
- }
- }
-
- if (decodedFrameCount != expectedFrameCount) {
- return false;
- }
-
- return true;
- }
-
- public static String getImageMD5Checksum(Image image) throws Exception {
- int format = image.getFormat();
- if (ImageFormat.YUV_420_888 != format) {
- Log.w(TAG, "unsupported image format");
- return "";
- }
-
- MessageDigest md = MessageDigest.getInstance("MD5");
-
- int imageWidth = image.getWidth();
- int imageHeight = image.getHeight();
-
- Image.Plane[] planes = image.getPlanes();
- for (int i = 0; i < planes.length; ++i) {
- ByteBuffer buf = planes[i].getBuffer();
-
- int width, height, rowStride, pixelStride, x, y;
- rowStride = planes[i].getRowStride();
- pixelStride = planes[i].getPixelStride();
- if (i == 0) {
- width = imageWidth;
- height = imageHeight;
- } else {
- width = imageWidth / 2;
- height = imageHeight /2;
- }
- // local contiguous pixel buffer
- byte[] bb = new byte[width * height];
- if (buf.hasArray()) {
- byte b[] = buf.array();
- int offs = buf.arrayOffset();
- if (pixelStride == 1) {
- for (y = 0; y < height; ++y) {
- System.arraycopy(bb, y * width, b, y * rowStride + offs, width);
- }
- } else {
- // do it pixel-by-pixel
- for (y = 0; y < height; ++y) {
- int lineOffset = offs + y * rowStride;
- for (x = 0; x < width; ++x) {
- bb[y * width + x] = b[lineOffset + x * pixelStride];
- }
- }
- }
- } else { // almost always ends up here due to direct buffers
- int pos = buf.position();
- if (pixelStride == 1) {
- for (y = 0; y < height; ++y) {
- buf.position(pos + y * rowStride);
- buf.get(bb, y * width, width);
- }
- } else {
- // local line buffer
- byte[] lb = new byte[rowStride];
- // do it pixel-by-pixel
- for (y = 0; y < height; ++y) {
- buf.position(pos + y * rowStride);
- // we're only guaranteed to have pixelStride * (width - 1) + 1 bytes
- buf.get(lb, 0, pixelStride * (width - 1) + 1);
- for (x = 0; x < width; ++x) {
- bb[y * width + x] = lb[x * pixelStride];
- }
- }
- }
- buf.position(pos);
- }
- md.update(bb, 0, width * height);
- }
-
- return convertByteArrayToHEXString(md.digest());
- }
-
- private static String convertByteArrayToHEXString(byte[] ba) throws Exception {
- StringBuilder result = new StringBuilder();
- for (int i = 0; i < ba.length; i++) {
- result.append(Integer.toString((ba[i] & 0xff) + 0x100, 16).substring(1));
- }
- return result.toString();
- }
-
-
- /*
- * -------------------------------------- END --------------------------------------
- */
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/MoreMatchers.java b/common/device-side/util/src/com/android/compatibility/common/util/MoreMatchers.java
deleted file mode 100644
index cee610e..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/MoreMatchers.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import org.mockito.ArgumentMatchers;
-
-public class MoreMatchers {
- private MoreMatchers() {
- }
-
- public static <T> T anyOrNull(Class<T> clazz) {
- return ArgumentMatchers.argThat(value -> true);
- }
-
- public static String anyStringOrNull() {
- return ArgumentMatchers.argThat(value -> true);
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/NullWebViewUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/NullWebViewUtils.java
deleted file mode 100644
index 3153adb..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/NullWebViewUtils.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2010 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.compatibility.common.util;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-
-/**
- * Utilities to enable the android.webkit.* CTS tests (and others that rely on a functioning
- * android.webkit.WebView implementation) to determine whether a functioning WebView is present
- * on the device or not.
- *
- * Test cases that require android.webkit.* classes should wrap their first usage of WebView in a
- * try catch block, and pass any exception that is thrown to
- * NullWebViewUtils.determineIfWebViewAvailable. The return value of
- * NullWebViewUtils.isWebViewAvailable will then determine if the test should expect to be able to
- * use a WebView.
- */
-public class NullWebViewUtils {
-
- private static boolean sWebViewUnavailable;
-
- /**
- * @param context Current Activity context, used to query the PackageManager.
- * @param t An exception thrown by trying to invoke android.webkit.* APIs.
- */
- public static void determineIfWebViewAvailable(Context context, Throwable t) {
- sWebViewUnavailable = !hasWebViewFeature(context) && checkCauseWasUnsupportedOperation(t);
- }
-
- /**
- * After calling determineIfWebViewAvailable, this returns whether a WebView is available on the
- * device and wheter the test can rely on it.
- * @return True iff. PackageManager determined that there is no WebView on the device and the
- * exception thrown from android.webkit.* was UnsupportedOperationException.
- */
- public static boolean isWebViewAvailable() {
- return !sWebViewUnavailable;
- }
-
- private static boolean hasWebViewFeature(Context context) {
- // Query the system property that determins if there is a functional WebView on the device.
- PackageManager pm = context.getPackageManager();
- return pm.hasSystemFeature(PackageManager.FEATURE_WEBVIEW);
- }
-
- private static boolean checkCauseWasUnsupportedOperation(Throwable t) {
- if (t == null) return false;
- while (t.getCause() != null) {
- t = t.getCause();
- }
- return t instanceof UnsupportedOperationException;
- }
-
- /**
- * Some CTS tests (by design) first use android.webkit.* from a background thread. This helper
- * allows the test to catch the UnsupportedOperationException from that background thread, and
- * then query the result from the test main thread.
- */
- public static class NullWebViewFromThreadExceptionHandler
- implements Thread.UncaughtExceptionHandler {
- private Throwable mPendingException;
-
- @Override
- public void uncaughtException(Thread t, Throwable e) {
- mPendingException = e;
- }
-
- public boolean isWebViewAvailable(Context context) {
- return hasWebViewFeature(context) ||
- !checkCauseWasUnsupportedOperation(mPendingException);
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/OnFailureRule.java b/common/device-side/util/src/com/android/compatibility/common/util/OnFailureRule.java
deleted file mode 100644
index 585c145..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/OnFailureRule.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import android.util.Log;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * Custom JUnit4 rule that provides a callback upon test failures.
- */
-public abstract class OnFailureRule implements TestRule {
- private String mLogTag = "OnFailureRule";
-
- public OnFailureRule() {
- }
-
- public OnFailureRule(String logTag) {
- mLogTag = logTag;
- }
-
- @Override
- public Statement apply(Statement base, Description description) {
- return new Statement() {
-
- @Override
- public void evaluate() throws Throwable {
- try {
- base.evaluate();
- } catch (Throwable t) {
- Log.e(mLogTag, "Test failed: description=" + description + "\nThrowable=" + t);
- onTestFailure(base, description, t);
- throw t;
- }
- }
- };
- }
-
- protected abstract void onTestFailure(Statement base, Description description, Throwable t);
-}
\ No newline at end of file
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/OneTimeDeviceConfigListener.java b/common/device-side/util/src/com/android/compatibility/common/util/OneTimeDeviceConfigListener.java
deleted file mode 100644
index e5be3f41..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/OneTimeDeviceConfigListener.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.util;
-
-import android.os.SystemClock;
-import android.provider.DeviceConfig;
-import android.provider.DeviceConfig.OnPropertiesChangedListener;
-import android.provider.DeviceConfig.Properties;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import com.google.common.base.Preconditions;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Helper used to block tests until a device config value has been updated.
- */
-public final class OneTimeDeviceConfigListener implements OnPropertiesChangedListener {
-
- public static final long DEFAULT_TIMEOUT_MS = 5_000;
-
- private static final String TAG = OneTimeDeviceConfigListener.class.getSimpleName();
-
- private final String mNamespace;
- private final String mKey;
- private final long mTimeoutMs;
- private final long mStarted = SystemClock.elapsedRealtime();
-
- private final CountDownLatch mLatch = new CountDownLatch(1);
-
- public OneTimeDeviceConfigListener(@NonNull String namespace, @NonNull String key) {
- this(namespace, key, DEFAULT_TIMEOUT_MS);
- }
-
- public OneTimeDeviceConfigListener(@NonNull String namespace, @NonNull String key,
- long timeoutMs) {
- mNamespace = Preconditions.checkNotNull(namespace);
- mKey = Preconditions.checkNotNull(key);
- mTimeoutMs = timeoutMs;
- }
-
- @Override
- public void onPropertiesChanged(@NonNull Properties properties) {
- if (!properties.getNamespace().equals(mNamespace)
- || !properties.getKeyset().contains(mKey)) {
- Log.d(TAG, "ignoring callback for namespace: " + properties.getNamespace());
- return;
- }
- mLatch.countDown();
- DeviceConfig.removeOnPropertiesChangedListener(this);
- }
-
- /**
- * Blocks for a few seconds until it's called.
- *
- * @throws IllegalStateException if it's not called.
- */
- public void assertCalled() {
- try {
- final boolean updated = mLatch.await(mTimeoutMs, TimeUnit.MILLISECONDS);
- if (!updated) {
- throw new RetryableException(
- "Settings " + mKey + " not called in " + mTimeoutMs + "ms");
- }
- final long delta = SystemClock.elapsedRealtime() - mStarted;
- Log.v(TAG, TestNameUtils.getCurrentTestName() + "/" + mKey + ": " + delta + "ms");
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new IllegalStateException("Interrupted", e);
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/OneTimeSettingsListener.java b/common/device-side/util/src/com/android/compatibility/common/util/OneTimeSettingsListener.java
deleted file mode 100644
index 79c80c9..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/OneTimeSettingsListener.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import static com.android.compatibility.common.util.SettingsUtils.NAMESPACE_GLOBAL;
-import static com.android.compatibility.common.util.SettingsUtils.NAMESPACE_SECURE;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.util.Log;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Helper used to block tests until a secure settings value has been updated.
- */
-public final class OneTimeSettingsListener extends ContentObserver {
-
- private static final String TAG = "OneTimeSettingsListener";
- public static final long DEFAULT_TIMEOUT_MS = 30_000;
-
- private final CountDownLatch mLatch = new CountDownLatch(1);
- private final ContentResolver mResolver;
- private final String mKey;
- private final long mStarted;
-
- public OneTimeSettingsListener(Context context, String namespace, String key) {
- super(new Handler(Looper.getMainLooper()));
- mStarted = SystemClock.elapsedRealtime();
- mKey = key;
- mResolver = context.getContentResolver();
- final Uri uri;
- switch (namespace) {
- case NAMESPACE_SECURE:
- uri = Settings.Secure.getUriFor(key);
- break;
- case NAMESPACE_GLOBAL:
- uri = Settings.Global.getUriFor(key);
- break;
- default:
- throw new IllegalArgumentException("invalid namespace: " + namespace);
- }
- mResolver.registerContentObserver(uri, false, this);
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- mResolver.unregisterContentObserver(this);
- mLatch.countDown();
- }
-
- /**
- * Blocks for a few seconds until it's called.
- *
- * @throws IllegalStateException if it's not called.
- */
- public void assertCalled() {
- try {
- final boolean updated = mLatch.await(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- if (!updated) {
- throw new RetryableException(
- "Settings " + mKey + " not called in " + DEFAULT_TIMEOUT_MS + "ms");
- }
- final long delta = SystemClock.elapsedRealtime() - mStarted;
- // TODO: usually it's notified in ~50-150ms, but for some reason it takes ~10s
- // on some ViewAttributesTest methods, hence the 30s limit
- Log.v(TAG, TestNameUtils.getCurrentTestName() + "/" + mKey + ": " + delta + "ms");
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new IllegalStateException("Interrupted", e);
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/PackageUtil.java b/common/device-side/util/src/com/android/compatibility/common/util/PackageUtil.java
deleted file mode 100644
index e7b6976..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/PackageUtil.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.support.test.InstrumentationRegistry;
-import android.util.Log;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-/**
- * Device-side utility class for PackageManager-related operations
- */
-public class PackageUtil {
-
- private static final String TAG = PackageUtil.class.getSimpleName();
-
- private static final int SYSTEM_APP_MASK =
- ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
- private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
-
- /** Returns true if a package with the given name exists on the device */
- public static boolean exists(String packageName) {
- try {
- return (getPackageManager().getApplicationInfo(packageName,
- PackageManager.GET_META_DATA) != null);
- } catch(PackageManager.NameNotFoundException e) {
- return false;
- }
- }
-
- /** Returns true if a package with the given name AND SHA digest exists on the device */
- public static boolean exists(String packageName, String sha) {
- try {
- if (getPackageManager().getApplicationInfo(
- packageName, PackageManager.GET_META_DATA) == null) {
- return false;
- }
- return sha.equals(computePackageSignatureDigest(packageName));
- } catch (NoSuchAlgorithmException | PackageManager.NameNotFoundException e) {
- return false;
- }
- }
-
- /** Returns true if the app for the given package name is a system app for this device */
- public static boolean isSystemApp(String packageName) {
- try {
- ApplicationInfo ai = getPackageManager().getApplicationInfo(packageName,
- PackageManager.GET_META_DATA);
- return ai != null && ((ai.flags & SYSTEM_APP_MASK) != 0);
- } catch(PackageManager.NameNotFoundException e) {
- return false;
- }
- }
-
- /** Returns the version string of the package name, or null if the package can't be found */
- public static String getVersionString(String packageName) {
- try {
- PackageInfo info = getPackageManager().getPackageInfo(packageName,
- PackageManager.GET_META_DATA);
- return info.versionName;
- } catch (PackageManager.NameNotFoundException | NullPointerException e) {
- Log.w(TAG, "Could not find version string for package " + packageName);
- return null;
- }
- }
-
- /**
- * Compute the signature SHA digest for a package.
- * @param package the name of the package for which the signature SHA digest is requested
- * @return the signature SHA digest
- */
- public static String computePackageSignatureDigest(String packageName)
- throws NoSuchAlgorithmException, PackageManager.NameNotFoundException {
- PackageInfo packageInfo = getPackageManager()
- .getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
- MessageDigest messageDigest = MessageDigest.getInstance("SHA256");
- messageDigest.update(packageInfo.signatures[0].toByteArray());
-
- final byte[] digest = messageDigest.digest();
- final int digestLength = digest.length;
- final int charCount = 3 * digestLength - 1;
-
- final char[] chars = new char[charCount];
- for (int i = 0; i < digestLength; i++) {
- final int byteHex = digest[i] & 0xFF;
- chars[i * 3] = HEX_ARRAY[byteHex >>> 4];
- chars[i * 3 + 1] = HEX_ARRAY[byteHex & 0x0F];
- if (i < digestLength - 1) {
- chars[i * 3 + 2] = ':';
- }
- }
- return new String(chars);
- }
-
- private static PackageManager getPackageManager() {
- return InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager();
- }
-
- private static boolean hasDeviceFeature(final String requiredFeature) {
- return InstrumentationRegistry.getContext()
- .getPackageManager()
- .hasSystemFeature(requiredFeature);
- }
-
- /**
- * Rotation support is indicated by explicitly having both landscape and portrait
- * features or not listing either at all.
- */
- public static boolean supportsRotation() {
- final boolean supportsLandscape = hasDeviceFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE);
- final boolean supportsPortrait = hasDeviceFeature(PackageManager.FEATURE_SCREEN_PORTRAIT);
- return (supportsLandscape && supportsPortrait)
- || (!supportsLandscape && !supportsPortrait);
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ParcelUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/ParcelUtils.java
deleted file mode 100644
index ecaa722..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/ParcelUtils.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import static org.junit.Assert.assertNotNull;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class ParcelUtils {
- private ParcelUtils() {
- }
-
- /** Convert a Parcelable into a byte[]. */
- public static byte[] toBytes(Parcelable p) {
- assertNotNull(p);
-
- final Parcel parcel = Parcel.obtain();
- parcel.writeParcelable(p, 0);
- byte[] data = parcel.marshall();
- parcel.recycle();
-
- return data;
- }
-
- /** Decode a byte[] into a Parcelable. */
- public static <T extends Parcelable> T fromBytes(byte[] data) {
- assertNotNull(data);
-
- final Parcel parcel = Parcel.obtain();
- parcel.unmarshall(data, 0, data.length);
- parcel.setDataPosition(0);
- T ret = parcel.readParcelable(ParcelUtils.class.getClassLoader());
- parcel.recycle();
-
- return ret;
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/PollingCheck.java b/common/device-side/util/src/com/android/compatibility/common/util/PollingCheck.java
deleted file mode 100644
index bcc3530..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/PollingCheck.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2012 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.compatibility.common.util;
-
-import java.util.concurrent.Callable;
-
-import junit.framework.Assert;
-
-public abstract class PollingCheck {
- private static final long TIME_SLICE = 50;
- private long mTimeout = 3000;
-
- public static interface PollingCheckCondition {
- boolean canProceed();
- }
-
- public PollingCheck() {
- }
-
- public PollingCheck(long timeout) {
- mTimeout = timeout;
- }
-
- protected abstract boolean check();
-
- public void run() {
- if (check()) {
- return;
- }
-
- long timeout = mTimeout;
- while (timeout > 0) {
- try {
- Thread.sleep(TIME_SLICE);
- } catch (InterruptedException e) {
- Assert.fail("unexpected InterruptedException");
- }
-
- if (check()) {
- return;
- }
-
- timeout -= TIME_SLICE;
- }
-
- Assert.fail("unexpected timeout");
- }
-
- public static void check(CharSequence message, long timeout, Callable<Boolean> condition)
- throws Exception {
- while (timeout > 0) {
- if (condition.call()) {
- return;
- }
-
- Thread.sleep(TIME_SLICE);
- timeout -= TIME_SLICE;
- }
-
- Assert.fail(message.toString());
- }
-
- public static void waitFor(final PollingCheckCondition condition) {
- new PollingCheck() {
- @Override
- protected boolean check() {
- return condition.canProceed();
- }
- }.run();
- }
-
- public static void waitFor(long timeout, final PollingCheckCondition condition) {
- new PollingCheck(timeout) {
- @Override
- protected boolean check() {
- return condition.canProceed();
- }
- }.run();
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/PropertyUtil.java b/common/device-side/util/src/com/android/compatibility/common/util/PropertyUtil.java
deleted file mode 100644
index c95b8df..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/PropertyUtil.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import android.os.Build;
-import android.support.test.InstrumentationRegistry;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Scanner;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Device-side utility class for reading properties and gathering information for testing
- * Android device compatibility.
- */
-public class PropertyUtil {
-
- /**
- * Name of read-only property detailing the first API level for which the product was
- * shipped. Property should be undefined for factory ROM products.
- */
- public static final String FIRST_API_LEVEL = "ro.product.first_api_level";
- private static final String BUILD_TYPE_PROPERTY = "ro.build.type";
- private static final String MANUFACTURER_PROPERTY = "ro.product.manufacturer";
- private static final String TAG_DEV_KEYS = "dev-keys";
- private static final String VNDK_VERSION = "ro.vndk.version";
-
- public static final String GOOGLE_SETTINGS_QUERY =
- "content query --uri content://com.google.settings/partner";
-
- /** Value to be returned by getPropertyInt() if property is not found */
- public static int INT_VALUE_IF_UNSET = -1;
-
- /** Returns whether the device build is a user build */
- public static boolean isUserBuild() {
- return propertyEquals(BUILD_TYPE_PROPERTY, "user");
- }
-
- /** Returns whether this build is built with dev-keys */
- public static boolean isDevKeysBuild() {
- for (String tag : Build.TAGS.split(",")) {
- if (TAG_DEV_KEYS.equals(tag.trim())) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Return the first API level for this product. If the read-only property is unset,
- * this means the first API level is the current API level, and the current API level
- * is returned.
- */
- public static int getFirstApiLevel() {
- int firstApiLevel = getPropertyInt(FIRST_API_LEVEL);
- return (firstApiLevel == INT_VALUE_IF_UNSET) ? Build.VERSION.SDK_INT : firstApiLevel;
- }
-
- /**
- * Return whether the SDK version of the vendor partiton is newer than the given API level.
- * If the property is set to non-integer value, this means the vendor partition is using
- * current API level and true is returned.
- */
- public static boolean isVendorApiLevelNewerThan(int apiLevel) {
- int vendorApiLevel = getPropertyInt(VNDK_VERSION);
- if (vendorApiLevel == INT_VALUE_IF_UNSET) {
- return true;
- }
- return vendorApiLevel > apiLevel;
- }
-
- /**
- * Return the manufacturer of this product. If unset, return null.
- */
- public static String getManufacturer() {
- return getProperty(MANUFACTURER_PROPERTY);
- }
-
- /** Returns a mapping from client ID names to client ID values */
- public static Map<String, String> getClientIds() throws IOException {
- Map<String,String> clientIds = new HashMap<>();
- String queryOutput = SystemUtil.runShellCommand(
- InstrumentationRegistry.getInstrumentation(), GOOGLE_SETTINGS_QUERY);
- for (String line : queryOutput.split("[\\r?\\n]+")) {
- // Expected line format: "Row: 1 _id=123, name=<property_name>, value=<property_value>"
- Pattern pattern = Pattern.compile("name=([a-z_]*), value=(.*)$");
- Matcher matcher = pattern.matcher(line);
- if (matcher.find()) {
- String name = matcher.group(1);
- String value = matcher.group(2);
- if (name.contains("client_id")) {
- clientIds.put(name, value); // only add name-value pair for client ids
- }
- }
- }
- return clientIds;
- }
-
- /** Returns whether the property exists on this device */
- public static boolean propertyExists(String property) {
- return getProperty(property) != null;
- }
-
- /** Returns whether the property value is equal to a given string */
- public static boolean propertyEquals(String property, String value) {
- if (value == null) {
- return !propertyExists(property); // null value implies property does not exist
- }
- return value.equals(getProperty(property));
- }
-
- /**
- * Returns whether the property value matches a given regular expression. The method uses
- * String.matches(), requiring a complete match (i.e. expression matches entire value string)
- */
- public static boolean propertyMatches(String property, String regex) {
- if (regex == null || regex.isEmpty()) {
- // null or empty pattern implies property does not exist
- return !propertyExists(property);
- }
- String value = getProperty(property);
- return (value == null) ? false : value.matches(regex);
- }
-
- /**
- * Retrieves the desired integer property, returning INT_VALUE_IF_UNSET if not found.
- */
- public static int getPropertyInt(String property) {
- String value = getProperty(property);
- if (value == null) {
- return INT_VALUE_IF_UNSET;
- }
- try {
- return Integer.parseInt(value);
- } catch (NumberFormatException e) {
- return INT_VALUE_IF_UNSET;
- }
- }
-
- /** Retrieves the desired property value in string form */
- public static String getProperty(String property) {
- Scanner scanner = null;
- try {
- Process process = new ProcessBuilder("getprop", property).start();
- scanner = new Scanner(process.getInputStream());
- String value = scanner.nextLine().trim();
- return (value.isEmpty()) ? null : value;
- } catch (IOException e) {
- return null;
- } finally {
- if (scanner != null) {
- scanner.close();
- }
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ReadElf.java b/common/device-side/util/src/com/android/compatibility/common/util/ReadElf.java
deleted file mode 100644
index feaa9cd..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/ReadElf.java
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
- * Copyright (C) 2011 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.compatibility.common.util;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A poor man's implementation of the readelf command. This program is designed
- * to parse ELF (Executable and Linkable Format) files.
- */
-public class ReadElf implements AutoCloseable {
- /** The magic values for the ELF identification. */
- private static final byte[] ELFMAG = {
- (byte) 0x7F, (byte) 'E', (byte) 'L', (byte) 'F', };
-
- private static final int EI_NIDENT = 16;
-
- private static final int EI_CLASS = 4;
- private static final int EI_DATA = 5;
-
- private static final int EM_386 = 3;
- private static final int EM_MIPS = 8;
- private static final int EM_ARM = 40;
- private static final int EM_X86_64 = 62;
- // http://en.wikipedia.org/wiki/Qualcomm_Hexagon
- private static final int EM_QDSP6 = 164;
- private static final int EM_AARCH64 = 183;
-
- private static final int ELFCLASS32 = 1;
- private static final int ELFCLASS64 = 2;
-
- private static final int ELFDATA2LSB = 1;
- private static final int ELFDATA2MSB = 2;
-
- private static final int EV_CURRENT = 1;
-
- private static final long PT_LOAD = 1;
-
- private static final int SHT_SYMTAB = 2;
- private static final int SHT_STRTAB = 3;
- private static final int SHT_DYNAMIC = 6;
- private static final int SHT_DYNSYM = 11;
-
- public static class Symbol {
- public static final int STB_LOCAL = 0;
- public static final int STB_GLOBAL = 1;
- public static final int STB_WEAK = 2;
- public static final int STB_LOPROC = 13;
- public static final int STB_HIPROC = 15;
-
- public static final int STT_NOTYPE = 0;
- public static final int STT_OBJECT = 1;
- public static final int STT_FUNC = 2;
- public static final int STT_SECTION = 3;
- public static final int STT_FILE = 4;
- public static final int STT_COMMON = 5;
- public static final int STT_TLS = 6;
-
- public final String name;
- public final int bind;
- public final int type;
-
- Symbol(String name, int st_info) {
- this.name = name;
- this.bind = (st_info >> 4) & 0x0F;
- this.type = st_info & 0x0F;
- }
-
- @Override
- public String toString() {
- return "Symbol[" + name + "," + toBind() + "," + toType() + "]";
- }
-
- private String toBind() {
- switch (bind) {
- case STB_LOCAL:
- return "LOCAL";
- case STB_GLOBAL:
- return "GLOBAL";
- case STB_WEAK:
- return "WEAK";
- }
- return "STB_??? (" + bind + ")";
- }
-
- private String toType() {
- switch (type) {
- case STT_NOTYPE:
- return "NOTYPE";
- case STT_OBJECT:
- return "OBJECT";
- case STT_FUNC:
- return "FUNC";
- case STT_SECTION:
- return "SECTION";
- case STT_FILE:
- return "FILE";
- case STT_COMMON:
- return "COMMON";
- case STT_TLS:
- return "TLS";
- }
- return "STT_??? (" + type + ")";
- }
- }
-
- private final String mPath;
- private final RandomAccessFile mFile;
- private final byte[] mBuffer = new byte[512];
- private int mEndian;
- private boolean mIsDynamic;
- private boolean mIsPIE;
- private int mType;
- private int mAddrSize;
-
- /** Symbol Table offset */
- private long mSymTabOffset;
-
- /** Symbol Table size */
- private long mSymTabSize;
-
- /** Dynamic Symbol Table offset */
- private long mDynSymOffset;
-
- /** Dynamic Symbol Table size */
- private long mDynSymSize;
-
- /** Section Header String Table offset */
- private long mShStrTabOffset;
-
- /** Section Header String Table size */
- private long mShStrTabSize;
-
- /** String Table offset */
- private long mStrTabOffset;
-
- /** String Table size */
- private long mStrTabSize;
-
- /** Dynamic String Table offset */
- private long mDynStrOffset;
-
- /** Dynamic String Table size */
- private long mDynStrSize;
-
- /** Symbol Table symbol names */
- private Map<String, Symbol> mSymbols;
-
- /** Dynamic Symbol Table symbol names */
- private Map<String, Symbol> mDynamicSymbols;
-
- public static ReadElf read(File file) throws IOException {
- return new ReadElf(file);
- }
-
- public static void main(String[] args) throws IOException {
- for (String arg : args) {
- ReadElf re = new ReadElf(new File(arg));
- re.getSymbol("x");
- re.getDynamicSymbol("x");
- re.close();
- }
- }
-
- public boolean isDynamic() {
- return mIsDynamic;
- }
-
- public int getType() {
- return mType;
- }
-
- public boolean isPIE() {
- return mIsPIE;
- }
-
- private ReadElf(File file) throws IOException {
- mPath = file.getPath();
- mFile = new RandomAccessFile(file, "r");
-
- if (mFile.length() < EI_NIDENT) {
- throw new IllegalArgumentException("Too small to be an ELF file: " + file);
- }
-
- readHeader();
- }
-
- @Override
- public void close() {
- try {
- mFile.close();
- } catch (IOException ignored) {
- }
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- close();
- } finally {
- super.finalize();
- }
- }
-
- private void readHeader() throws IOException {
- mFile.seek(0);
- mFile.readFully(mBuffer, 0, EI_NIDENT);
-
- if (mBuffer[0] != ELFMAG[0] || mBuffer[1] != ELFMAG[1] ||
- mBuffer[2] != ELFMAG[2] || mBuffer[3] != ELFMAG[3]) {
- throw new IllegalArgumentException("Invalid ELF file: " + mPath);
- }
-
- int elfClass = mBuffer[EI_CLASS];
- if (elfClass == ELFCLASS32) {
- mAddrSize = 4;
- } else if (elfClass == ELFCLASS64) {
- mAddrSize = 8;
- } else {
- throw new IOException("Invalid ELF EI_CLASS: " + elfClass + ": " + mPath);
- }
-
- mEndian = mBuffer[EI_DATA];
- if (mEndian == ELFDATA2LSB) {
- } else if (mEndian == ELFDATA2MSB) {
- throw new IOException("Unsupported ELFDATA2MSB file: " + mPath);
- } else {
- throw new IOException("Invalid ELF EI_DATA: " + mEndian + ": " + mPath);
- }
-
- mType = readHalf();
-
- int e_machine = readHalf();
- if (e_machine != EM_386 && e_machine != EM_X86_64 &&
- e_machine != EM_AARCH64 && e_machine != EM_ARM &&
- e_machine != EM_MIPS &&
- e_machine != EM_QDSP6) {
- throw new IOException("Invalid ELF e_machine: " + e_machine + ": " + mPath);
- }
-
- // AbiTest relies on us rejecting any unsupported combinations.
- if ((e_machine == EM_386 && elfClass != ELFCLASS32) ||
- (e_machine == EM_X86_64 && elfClass != ELFCLASS64) ||
- (e_machine == EM_AARCH64 && elfClass != ELFCLASS64) ||
- (e_machine == EM_ARM && elfClass != ELFCLASS32) ||
- (e_machine == EM_QDSP6 && elfClass != ELFCLASS32)) {
- throw new IOException("Invalid e_machine/EI_CLASS ELF combination: " +
- e_machine + "/" + elfClass + ": " + mPath);
- }
-
- long e_version = readWord();
- if (e_version != EV_CURRENT) {
- throw new IOException("Invalid e_version: " + e_version + ": " + mPath);
- }
-
- long e_entry = readAddr();
-
- long ph_off = readOff();
- long sh_off = readOff();
-
- long e_flags = readWord();
- int e_ehsize = readHalf();
- int e_phentsize = readHalf();
- int e_phnum = readHalf();
- int e_shentsize = readHalf();
- int e_shnum = readHalf();
- int e_shstrndx = readHalf();
-
- readSectionHeaders(sh_off, e_shnum, e_shentsize, e_shstrndx);
- readProgramHeaders(ph_off, e_phnum, e_phentsize);
- }
-
- private void readSectionHeaders(long sh_off, int e_shnum, int e_shentsize, int e_shstrndx)
- throws IOException {
- // Read the Section Header String Table offset first.
- {
- mFile.seek(sh_off + e_shstrndx * e_shentsize);
-
- long sh_name = readWord();
- long sh_type = readWord();
- long sh_flags = readX(mAddrSize);
- long sh_addr = readAddr();
- long sh_offset = readOff();
- long sh_size = readX(mAddrSize);
- // ...
-
- if (sh_type == SHT_STRTAB) {
- mShStrTabOffset = sh_offset;
- mShStrTabSize = sh_size;
- }
- }
-
- for (int i = 0; i < e_shnum; ++i) {
- // Don't bother to re-read the Section Header StrTab.
- if (i == e_shstrndx) {
- continue;
- }
-
- mFile.seek(sh_off + i * e_shentsize);
-
- long sh_name = readWord();
- long sh_type = readWord();
- long sh_flags = readX(mAddrSize);
- long sh_addr = readAddr();
- long sh_offset = readOff();
- long sh_size = readX(mAddrSize);
-
- if (sh_type == SHT_SYMTAB || sh_type == SHT_DYNSYM) {
- final String symTabName = readShStrTabEntry(sh_name);
- if (".symtab".equals(symTabName)) {
- mSymTabOffset = sh_offset;
- mSymTabSize = sh_size;
- } else if (".dynsym".equals(symTabName)) {
- mDynSymOffset = sh_offset;
- mDynSymSize = sh_size;
- }
- } else if (sh_type == SHT_STRTAB) {
- final String strTabName = readShStrTabEntry(sh_name);
- if (".strtab".equals(strTabName)) {
- mStrTabOffset = sh_offset;
- mStrTabSize = sh_size;
- } else if (".dynstr".equals(strTabName)) {
- mDynStrOffset = sh_offset;
- mDynStrSize = sh_size;
- }
- } else if (sh_type == SHT_DYNAMIC) {
- mIsDynamic = true;
- }
- }
- }
-
- private void readProgramHeaders(long ph_off, int e_phnum, int e_phentsize) throws IOException {
- for (int i = 0; i < e_phnum; ++i) {
- mFile.seek(ph_off + i * e_phentsize);
-
- long p_type = readWord();
- if (p_type == PT_LOAD) {
- if (mAddrSize == 8) {
- // Only in Elf64_phdr; in Elf32_phdr p_flags is at the end.
- long p_flags = readWord();
- }
- long p_offset = readOff();
- long p_vaddr = readAddr();
- // ...
-
- if (p_vaddr == 0) {
- mIsPIE = true;
- }
- }
- }
- }
-
- private HashMap<String, Symbol> readSymbolTable(long symStrOffset, long symStrSize,
- long tableOffset, long tableSize) throws IOException {
- HashMap<String, Symbol> result = new HashMap<String, Symbol>();
- mFile.seek(tableOffset);
- while (mFile.getFilePointer() < tableOffset + tableSize) {
- long st_name = readWord();
- int st_info;
- if (mAddrSize == 8) {
- st_info = readByte();
- int st_other = readByte();
- int st_shndx = readHalf();
- long st_value = readAddr();
- long st_size = readX(mAddrSize);
- } else {
- long st_value = readAddr();
- long st_size = readWord();
- st_info = readByte();
- int st_other = readByte();
- int st_shndx = readHalf();
- }
- if (st_name == 0) {
- continue;
- }
-
- final String symName = readStrTabEntry(symStrOffset, symStrSize, st_name);
- if (symName != null) {
- Symbol s = new Symbol(symName, st_info);
- result.put(symName, s);
- }
- }
- return result;
- }
-
- private String readShStrTabEntry(long strOffset) throws IOException {
- if (mShStrTabOffset == 0 || strOffset < 0 || strOffset >= mShStrTabSize) {
- return null;
- }
- return readString(mShStrTabOffset + strOffset);
- }
-
- private String readStrTabEntry(long tableOffset, long tableSize, long strOffset)
- throws IOException {
- if (tableOffset == 0 || strOffset < 0 || strOffset >= tableSize) {
- return null;
- }
- return readString(tableOffset + strOffset);
- }
-
- private int readHalf() throws IOException {
- return (int) readX(2);
- }
-
- private long readWord() throws IOException {
- return readX(4);
- }
-
- private long readOff() throws IOException {
- return readX(mAddrSize);
- }
-
- private long readAddr() throws IOException {
- return readX(mAddrSize);
- }
-
- private long readX(int byteCount) throws IOException {
- mFile.readFully(mBuffer, 0, byteCount);
-
- int answer = 0;
- if (mEndian == ELFDATA2LSB) {
- for (int i = byteCount - 1; i >= 0; i--) {
- answer = (answer << 8) | (mBuffer[i] & 0xff);
- }
- } else {
- final int N = byteCount - 1;
- for (int i = 0; i <= N; ++i) {
- answer = (answer << 8) | (mBuffer[i] & 0xff);
- }
- }
-
- return answer;
- }
-
- private String readString(long offset) throws IOException {
- long originalOffset = mFile.getFilePointer();
- mFile.seek(offset);
- mFile.readFully(mBuffer, 0, (int) Math.min(mBuffer.length, mFile.length() - offset));
- mFile.seek(originalOffset);
-
- for (int i = 0; i < mBuffer.length; ++i) {
- if (mBuffer[i] == 0) {
- return new String(mBuffer, 0, i);
- }
- }
-
- return null;
- }
-
- private int readByte() throws IOException {
- return mFile.read() & 0xff;
- }
-
- public Symbol getSymbol(String name) {
- if (mSymbols == null) {
- try {
- mSymbols = readSymbolTable(mStrTabOffset, mStrTabSize, mSymTabOffset, mSymTabSize);
- } catch (IOException e) {
- return null;
- }
- }
- return mSymbols.get(name);
- }
-
- public Symbol getDynamicSymbol(String name) {
- if (mDynamicSymbols == null) {
- try {
- mDynamicSymbols = readSymbolTable(
- mDynStrOffset, mDynStrSize, mDynSymOffset, mDynSymSize);
- } catch (IOException e) {
- return null;
- }
- }
- return mDynamicSymbols.get(name);
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.java b/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.java
deleted file mode 100644
index 538881d..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2016 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.compatibility.common.util;
-
-import android.util.JsonWriter;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-
-public class ReportLogDeviceInfoStore extends DeviceInfoStore {
-
- private final String mStreamName;
- private File tempJsonFile;
-
- public ReportLogDeviceInfoStore(File jsonFile, String streamName) throws Exception {
- mJsonFile = jsonFile;
- mStreamName = streamName;
- }
-
- /**
- * Creates the writer and starts the JSON Object for the metric stream.
- */
- @Override
- public void open() throws IOException {
- // Write new metrics to a temp file to avoid invalid JSON files due to failed tests.
- BufferedWriter formatWriter;
- tempJsonFile = File.createTempFile(mStreamName, "-temp-report-log");
- formatWriter = new BufferedWriter(new FileWriter(tempJsonFile));
- if (mJsonFile.exists()) {
- BufferedReader jsonReader = new BufferedReader(new FileReader(mJsonFile));
- String currentLine;
- String nextLine = jsonReader.readLine();
- while ((currentLine = nextLine) != null) {
- nextLine = jsonReader.readLine();
- if (nextLine == null && currentLine.charAt(currentLine.length() - 1) == '}') {
- // Reopen overall JSON object to write new metrics.
- currentLine = currentLine.substring(0, currentLine.length() - 1) + ",";
- }
- // Copy to temp file directly to avoid large metrics string in memory.
- formatWriter.write(currentLine, 0, currentLine.length());
- }
- jsonReader.close();
- } else {
- formatWriter.write("{", 0 , 1);
- }
- // Start new JSON object for new metrics.
- formatWriter.write("\"" + mStreamName + "\":", 0, mStreamName.length() + 3);
- formatWriter.flush();
- formatWriter.close();
- mJsonWriter = new JsonWriter(new FileWriter(tempJsonFile, true));
- mJsonWriter.beginObject();
- }
-
- /**
- * Closes the writer.
- */
- @Override
- public void close() throws IOException {
- // Close JSON Writer.
- mJsonWriter.endObject();
- mJsonWriter.close();
- // Close overall JSON Object.
- try (BufferedWriter formatWriter = new BufferedWriter(new FileWriter(tempJsonFile, true))) {
- formatWriter.write("}", 0, 1);
- }
- // Copy metrics from temp file and delete temp file.
- mJsonFile.createNewFile();
- try (
- BufferedReader jsonReader = new BufferedReader(new FileReader(tempJsonFile));
- BufferedWriter metricsWriter = new BufferedWriter(new FileWriter(mJsonFile))
- ) {
- String line;
- while ((line = jsonReader.readLine()) != null) {
- // Copy from temp file directly to avoid large metrics string in memory.
- metricsWriter.write(line, 0, line.length());
- }
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/RequiredFeatureRule.java b/common/device-side/util/src/com/android/compatibility/common/util/RequiredFeatureRule.java
deleted file mode 100644
index 0968ddc..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/RequiredFeatureRule.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import android.support.test.InstrumentationRegistry;
-import android.util.Log;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * Custom JUnit4 rule that does not run a test case if the device does not have a given feature.
- */
-public class RequiredFeatureRule implements TestRule {
- private static final String TAG = "RequiredFeatureRule";
-
- private final String mFeature;
- private final boolean mHasFeature;
-
- public RequiredFeatureRule(String feature) {
- mFeature = feature;
- mHasFeature = hasFeature(feature);
- }
-
- @Override
- public Statement apply(Statement base, Description description) {
- return new Statement() {
-
- @Override
- public void evaluate() throws Throwable {
- if (!mHasFeature) {
- Log.d(TAG, "skipping "
- + description.getClassName() + "#" + description.getMethodName()
- + " because device does not have feature '" + mFeature + "'");
- return;
- }
- base.evaluate();
- }
- };
- }
-
- public static boolean hasFeature(String feature) {
- return InstrumentationRegistry.getContext().getPackageManager().hasSystemFeature(feature);
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/RequiredServiceRule.java b/common/device-side/util/src/com/android/compatibility/common/util/RequiredServiceRule.java
deleted file mode 100644
index a4359fd..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/RequiredServiceRule.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import android.support.test.InstrumentationRegistry;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * Custom JUnit4 rule that does not run a test case if the device does not have a given service.
- */
-public class RequiredServiceRule implements TestRule {
- private static final String TAG = "RequiredServiceRule";
-
- private final String mService;
- private final boolean mHasService;
-
- /**
- * Creates a rule for the given service.
- */
- public RequiredServiceRule(@NonNull String service) {
- mService = service;
- mHasService = hasService(service);
- }
-
- @Override
- public Statement apply(@NonNull Statement base, @NonNull Description description) {
- return new Statement() {
-
- @Override
- public void evaluate() throws Throwable {
- if (!mHasService) {
- Log.d(TAG, "skipping "
- + description.getClassName() + "#" + description.getMethodName()
- + " because device does not have service '" + mService + "'");
- return;
- }
- base.evaluate();
- }
- };
- }
-
- /**
- * Checks if the device has the given service.
- */
- public static boolean hasService(@NonNull String service) {
- // TODO: ideally should call SystemServiceManager directly, but we would need to open
- // some @Testing APIs for that.
- String command = "service check " + service;
- try {
- String commandOutput = SystemUtil.runShellCommand(
- InstrumentationRegistry.getInstrumentation(), command);
- return !commandOutput.contains("not found");
- } catch (Exception e) {
- Log.w(TAG, "Exception running '" + command + "': " + e);
- return false;
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/Result.java b/common/device-side/util/src/com/android/compatibility/common/util/Result.java
deleted file mode 100644
index 0d8a29a..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/Result.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2014 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.compatibility.common.util;
-
-/**
- * Represents the result of a test.
- */
-public interface Result {
- public static final int RESULT_OK = 1;
- public static final int RESULT_FAIL = 2;
- /**
- * Sets the test result of this object.
- *
- * @param resultCode The test result, either {@code RESULT_OK} or {@code RESULT_FAIL}.
- */
- void setResult(int resultCode);
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/RetryRule.java b/common/device-side/util/src/com/android/compatibility/common/util/RetryRule.java
deleted file mode 100644
index 32dedea..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/RetryRule.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import android.util.Log;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * Custom JUnit4 rule that retry tests when they fail due to a {@link RetryableException}.
- */
-public class RetryRule implements TestRule {
-
- private static final String TAG = "RetryRule";
- private final int mMaxAttempts;
-
- /**
- * Retries the underlying test when it catches a {@link RetryableException}.
- *
- * @param retries number of retries. Use {@code 0} to disable rule.
- *
- * @throws IllegalArgumentException if {@code retries} is less than {@code 0}.
- */
- public RetryRule(int retries) {
- if (retries < 0) {
- throw new IllegalArgumentException("retries must be more than 0");
- }
- mMaxAttempts = retries + 1;
- }
-
- @Override
- public Statement apply(Statement base, Description description) {
- return new Statement() {
-
- @Override
- public void evaluate() throws Throwable {
- if (mMaxAttempts <= 1) {
- Log.v(TAG, "Executing " + description.getDisplayName()
- + " right away because mMaxAttempts is " + mMaxAttempts);
- base.evaluate();
- return;
- }
-
- final String name = description.getDisplayName();
- Throwable caught = null;
- for (int i = 1; i <= mMaxAttempts; i++) {
- try {
- base.evaluate();
- if (i == 1) {
- Log.v(TAG, "Good News, Everyone! " + name + " passed right away");
- } else {
- Log.d(TAG,
- "Better late than never: " + name + " passed at attempt #" + i);
- }
- return;
- } catch (RetryableException e) {
- final Timeout timeout = e.getTimeout();
- if (timeout != null) {
- long before = timeout.ms();
- timeout.increase();
- Log.d(TAG, "Increased " + timeout.getName() + " from " + before + "ms"
- + " to " + timeout.ms() + "ms");
- }
- caught = e;
- }
- Log.w(TAG, "Arrrr! " + name + " failed at attempt " + i + "/" + mMaxAttempts
- + ": " + caught);
- }
- Log.e(TAG, "D'OH! " + name + ": giving up after " + mMaxAttempts + " attempts");
- throw caught;
- }
- };
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/RetryableException.java b/common/device-side/util/src/com/android/compatibility/common/util/RetryableException.java
deleted file mode 100644
index 1c6c782..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/RetryableException.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import androidx.annotation.Nullable;
-
-/**
- * Exception that cause the {@link RetryRule} to re-try a test.
- */
-public class RetryableException extends RuntimeException {
-
- @Nullable
- private final Timeout mTimeout;
-
- public RetryableException(String msg) {
- this((Timeout) null, msg);
- }
-
- public RetryableException(String format, Object...args) {
- this((Timeout) null, String.format(format, args));
- }
-
- public RetryableException(Throwable cause, String format, Object...args) {
- this((Timeout) null, cause, String.format(format, args), cause);
- }
-
- public RetryableException(@Nullable Timeout timeout, String msg) {
- super(msg);
- this.mTimeout = timeout;
- }
-
- public RetryableException(@Nullable Timeout timeout, String format, Object...args) {
- super(String.format(format, args));
- this.mTimeout = timeout;
- }
-
- public RetryableException(@Nullable Timeout timeout, Throwable cause, String format,
- Object...args) {
- super(String.format(format, args), cause);
- this.mTimeout = timeout;
- }
-
- @Nullable
- public Timeout getTimeout() {
- return mTimeout;
- }
-
- @Override
- public String getMessage() {
- final String superMessage = super.getMessage();
- return mTimeout == null ? superMessage : superMessage + " (timeout=" + mTimeout + ")";
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/SafeCleanerRule.java b/common/device-side/util/src/com/android/compatibility/common/util/SafeCleanerRule.java
deleted file mode 100644
index 806884c..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/SafeCleanerRule.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import org.junit.AssumptionViolatedException;
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Callable;
-
-/**
- * Rule used to safely run clean up code after a test is finished, so that exceptions thrown by
- * the cleanup code don't hide exception thrown by the test body
- */
-public final class SafeCleanerRule implements TestRule {
-
- private static final String TAG = "SafeCleanerRule";
-
- private final List<ThrowingRunnable> mCleaners = new ArrayList<>();
- private final List<Callable<List<Throwable>>> mExtraThrowables = new ArrayList<>();
- private final List<Throwable> mThrowables = new ArrayList<>();
- private Dumper mDumper;
-
- /**
- * Runs {@code cleaner} after the test is finished, catching any {@link Throwable} thrown by it.
- */
- public SafeCleanerRule run(@NonNull ThrowingRunnable cleaner) {
- mCleaners.add(cleaner);
- return this;
- }
-
- /**
- * Adds exceptions directly.
- *
- * <p>Typically used for exceptions caught asychronously during the test execution.
- */
- public SafeCleanerRule add(@NonNull Callable<List<Throwable>> exceptions) {
- mExtraThrowables.add(exceptions);
- return this;
- }
-
- /**
- * Adds exceptions directly.
- *
- * <p>Typically used for exceptions caught during {@code finally} blocks.
- */
- public SafeCleanerRule add(Throwable exception) {
- Log.w(TAG, "Adding exception directly: " + exception);
- mThrowables.add(exception);
- return this;
- }
-
- /**
- * Sets a {@link Dumper} used to log errors.
- */
- public SafeCleanerRule setDumper(@NonNull Dumper dumper) {
- mDumper = dumper;
- return this;
- }
-
- @Override
- public Statement apply(Statement base, Description description) {
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- // First run the test
- try {
- base.evaluate();
- } catch (Throwable t) {
- Log.w(TAG, "Adding exception from main test at index 0: " + t);
- mThrowables.add(0, t);
- }
-
- // Then the cleanup runners
- for (ThrowingRunnable runner : mCleaners) {
- try {
- runner.run();
- } catch (Throwable t) {
- Log.w(TAG, "Adding exception from cleaner");
- mThrowables.add(t);
- }
- }
-
- // And finally add the extra exceptions
- for (Callable<List<Throwable>> extraThrowablesCallable : mExtraThrowables) {
- final List<Throwable> extraThrowables = extraThrowablesCallable.call();
- if (extraThrowables != null && !extraThrowables.isEmpty()) {
- Log.w(TAG, "Adding " + extraThrowables.size() + " extra exceptions");
- mThrowables.addAll(extraThrowables);
- }
- }
-
- // Ignore all instances of AssumptionViolatedExceptions
- mThrowables.removeIf(t -> t instanceof AssumptionViolatedException);
-
- // Finally, throw up!
- if (mThrowables.isEmpty()) return;
-
- final int numberExceptions = mThrowables.size();
- if (numberExceptions == 1) {
- fail(description, mThrowables.get(0));
- }
- fail(description, new MultipleExceptions(mThrowables));
- }
-
- };
- }
-
- private void fail(Description description, Throwable t) throws Throwable {
- if (mDumper != null) {
- mDumper.dump(description.getDisplayName(), t);
- }
- throw t;
- }
-
- private static String toMesssage(List<Throwable> throwables) {
- String msg = "D'OH!";
- try {
- try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) {
- sw.write("Caught " + throwables.size() + " exceptions\n");
- for (int i = 0; i < throwables.size(); i++) {
- sw.write("\n---- Begin of exception #" + (i + 1) + " ----\n");
- final Throwable exception = throwables.get(i);
- exception.printStackTrace(pw);
- sw.write("---- End of exception #" + (i + 1) + " ----\n\n");
- }
- msg = sw.toString();
- }
- } catch (IOException e) {
- // ignore close() errors - should not happen...
- Log.e(TAG, "Exception closing StringWriter: " + e);
- }
- return msg;
- }
-
- // VisibleForTesting
- static class MultipleExceptions extends AssertionError {
- private final List<Throwable> mThrowables;
-
- private MultipleExceptions(List<Throwable> throwables) {
- super(toMesssage(throwables));
-
- this.mThrowables = throwables;
- }
-
- List<Throwable> getThrowables() {
- return mThrowables;
- }
- }
-
- /**
- * Optional interface used to dump an error.
- */
- public interface Dumper {
-
- /**
- * Dumps an error.
- */
- void dump(@NonNull String testName, @NonNull Throwable t);
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/SettingsStateChangerRule.java b/common/device-side/util/src/com/android/compatibility/common/util/SettingsStateChangerRule.java
deleted file mode 100644
index 3e0662a..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/SettingsStateChangerRule.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.util;
-
-import android.content.Context;
-import android.provider.Settings;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-/**
- * JUnit rule used to set a {@link Settings} preference before the test is run.
- *
- * <p>It stores the current value before the test, changes it (if necessary), then restores it after
- * the test (if necessary).
- */
-public class SettingsStateChangerRule extends StateChangerRule<String> {
-
- /**
- * Default constructor for the 'secure' context.
- *
- * @param context context used to retrieve the {@link Settings} provider.
- * @param key prefence key.
- * @param value value to be set before the test is run.
- */
- public SettingsStateChangerRule(@NonNull Context context, @NonNull String key,
- @Nullable String value) {
- this(context, SettingsUtils.NAMESPACE_SECURE, key, value);
- }
-
- /**
- * Default constructor.
- *
- * @param context context used to retrieve the {@link Settings} provider.
- * @param namespace settings namespace.
- * @param key prefence key.
- * @param value value to be set before the test is run.
- */
- public SettingsStateChangerRule(@NonNull Context context, @NonNull String namespace,
- @NonNull String key, @Nullable String value) {
- super(new SettingsStateManager(context, namespace, key), value);
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/SettingsStateKeeperRule.java b/common/device-side/util/src/com/android/compatibility/common/util/SettingsStateKeeperRule.java
deleted file mode 100644
index 18ca88a..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/SettingsStateKeeperRule.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.util;
-
-import android.content.Context;
-import android.provider.Settings;
-
-import androidx.annotation.NonNull;
-
-/**
- * JUnit rule used to restore a {@link Settings} preference after the test is run.
- *
- * <p>It stores the current value before the test, and restores it after the test (if necessary).
- */
-public class SettingsStateKeeperRule extends StateKeeperRule<String> {
-
- /**
- * Default constructor.
- *
- * @param context context used to retrieve the {@link Settings} provider.
- * @param key prefence key.
- */
- public SettingsStateKeeperRule(@NonNull Context context, @NonNull String key) {
- super(new SettingsStateManager(context, SettingsUtils.NAMESPACE_SECURE, key));
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/SettingsStateManager.java b/common/device-side/util/src/com/android/compatibility/common/util/SettingsStateManager.java
deleted file mode 100644
index bab06a6..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/SettingsStateManager.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import android.content.Context;
-import android.provider.Settings;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.google.common.base.Preconditions;
-
-/**
- * Manages the state of a preference backed by {@link Settings}.
- */
-public class SettingsStateManager implements StateManager<String> {
-
- private final Context mContext;
- private final String mNamespace;
- private final String mKey;
-
- /**
- * Default constructor.
- *
- * @param context context used to retrieve the {@link Settings} provider.
- * @param namespace settings namespace.
- * @param key prefence key.
- */
- public SettingsStateManager(@NonNull Context context, @NonNull String namespace,
- @NonNull String key) {
- mContext = Preconditions.checkNotNull(context);
- mNamespace = Preconditions.checkNotNull(namespace);
- mKey = Preconditions.checkNotNull(key);
- }
-
- @Override
- public void set(@Nullable String value) {
- SettingsUtils.syncSet(mContext, mNamespace, mKey, value);
- }
-
- @Override
- @Nullable
- public String get() {
- return SettingsUtils.get(mNamespace, mKey);
- }
-
- @Override
- public String toString() {
- return "SettingsStateManager[namespace=" + mNamespace + ", key=" + mKey + "]";
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/SettingsUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/SettingsUtils.java
deleted file mode 100644
index c13de45..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/SettingsUtils.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
-
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.content.Context;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-/**
- * Provides utilities to interact with the device's {@link Settings}.
- */
-public final class SettingsUtils {
-
- private static final String TAG = SettingsUtils.class.getSimpleName();
-
- public static final String NAMESPACE_SECURE = "secure";
- public static final String NAMESPACE_GLOBAL = "global";
-
- // TODO(b/123885378): we cannot pass an empty value when using 'cmd settings', so we need
- // to remove the property instead. Once we use the Settings API directly, we can remove this
- // constant and all if() statements that ues it
- static final boolean TMP_HACK_REMOVE_EMPTY_PROPERTIES = true;
-
- /**
- * Uses a Shell command to set the given preference.
- */
- public static void set(@NonNull String namespace, @NonNull String key, @Nullable String value) {
- if (value == null) {
- delete(namespace, key);
- return;
- }
- if (TMP_HACK_REMOVE_EMPTY_PROPERTIES && TextUtils.isEmpty(value)) {
- Log.w(TAG, "Value of " + namespace + ":" + key + " is empty; deleting it instead");
- delete(namespace, key);
- return;
- }
- runShellCommand("settings put %s %s %s default", namespace, key, value);
- }
-
- /**
- * Sets a preference in the {@link #NAMESPACE_SECURE} namespace.
- */
- public static void set(@NonNull String key, @Nullable String value) {
- set(NAMESPACE_SECURE, key, value);
- }
-
- /**
- * Uses a Shell command to set the given preference, and verifies it was correctly set.
- */
- public static void syncSet(@NonNull Context context, @NonNull String namespace,
- @NonNull String key, @Nullable String value) {
- if (value == null) {
- syncDelete(context, namespace, key);
- return;
- }
-
- final String currentValue = get(namespace, key);
- if (value.equals(currentValue)) {
- // Already set, ignore
- return;
- }
-
- final OneTimeSettingsListener observer =
- new OneTimeSettingsListener(context, namespace, key);
- set(namespace, key, value);
- observer.assertCalled();
-
- final String newValue = get(namespace, key);
- if (TMP_HACK_REMOVE_EMPTY_PROPERTIES && TextUtils.isEmpty(value)) {
- assertWithMessage("invalid value for '%s' settings", key).that(newValue)
- .isNull();
- } else {
- assertWithMessage("invalid value for '%s' settings", key).that(newValue)
- .isEqualTo(value);
- }
- }
-
- /**
- * Sets a preference in the {@link #NAMESPACE_SECURE} namespace, using a Settings listener to
- * block until it's set.
- */
- public static void syncSet(@NonNull Context context, @NonNull String key,
- @Nullable String value) {
- syncSet(context, NAMESPACE_SECURE, key, value);
- }
-
- /**
- * Uses a Shell command to delete the given preference.
- */
- public static void delete(@NonNull String namespace, @NonNull String key) {
- runShellCommand("settings delete %s %s", namespace, key);
- }
-
- /**
- * Deletes a preference in the {@link #NAMESPACE_SECURE} namespace.
- */
- public static void delete(@NonNull String key) {
- delete(NAMESPACE_SECURE, key);
- }
-
- /**
- * Uses a Shell command to delete the given preference, and verifies it was correctly deleted.
- */
- public static void syncDelete(@NonNull Context context, @NonNull String namespace,
- @NonNull String key) {
-
- final String currentValue = get(namespace, key);
- if (currentValue == null) {
- // Already set, ignore
- return;
- }
-
- final OneTimeSettingsListener observer = new OneTimeSettingsListener(context, namespace,
- key);
- delete(namespace, key);
- observer.assertCalled();
-
- final String newValue = get(namespace, key);
- assertWithMessage("invalid value for '%s' settings", key).that(newValue).isNull();
- }
-
- /**
- * Deletes a preference in the {@link #NAMESPACE_SECURE} namespace, using a Settings listener to
- * block until it's deleted.
- */
- public static void syncDelete(@NonNull Context context, @NonNull String key) {
- syncDelete(context, NAMESPACE_SECURE, key);
- }
-
- /**
- * Gets the value of a given preference using Shell command.
- */
- @Nullable
- public static String get(@NonNull String namespace, @NonNull String key) {
- final String value = runShellCommand("settings get %s %s", namespace, key);
- if (value == null || value.equals("null")) {
- return null;
- } else {
- return value;
- }
- }
-
- /**
- * Gets the value of a preference in the {@link #NAMESPACE_SECURE} namespace.
- */
- @NonNull
- public static String get(@NonNull String key) {
- return get(NAMESPACE_SECURE, key);
- }
-
- private SettingsUtils() {
- throw new UnsupportedOperationException("contain static methods only");
- }
-
- /**
- * @deprecated - use {@link #set(String, String, String)} with {@link #NAMESPACE_GLOBAL}
- */
- @Deprecated
- public static void putGlobalSetting(String key, String value) {
- set(SettingsUtils.NAMESPACE_GLOBAL, key, value);
-
- }
-
- /**
- * @deprecated - use {@link #set(String, String, String)} with {@link #NAMESPACE_GLOBAL}
- */
- @Deprecated
- public static void putSecureSetting(String key, String value) {
- set(SettingsUtils.NAMESPACE_SECURE, key, value);
-
- }
-
- /**
- * Get a global setting for the current (foreground) user. Trims ending new line.
- */
- public static String getSecureSetting(String key) {
- return SystemUtil.runShellCommand("settings --user current get secure " + key).trim();
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ShellIdentityUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/ShellIdentityUtils.java
deleted file mode 100644
index f3438ee..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/ShellIdentityUtils.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import android.app.UiAutomation;
-import android.support.test.InstrumentationRegistry;
-
-/**
- * Provides utility methods to invoke system and privileged APIs as the shell user.
- */
-public class ShellIdentityUtils {
-
- /**
- * Utility interface to invoke a method against the target object.
- *
- * @param <T> the type returned by the invoked method.
- * @param <U> the type of the object against which the method is invoked.
- */
- public interface ShellPermissionMethodHelper<T, U> {
- /**
- * Invokes the method against the target object.
- *
- * @param targetObject the object against which the method should be invoked.
- * @return the result of the invoked method.
- */
- T callMethod(U targetObject);
- }
-
- /**
- * Utility interface to invoke a method against the target object.
- *
- * @param <U> the type of the object against which the method is invoked.
- */
- public interface ShellPermissionMethodHelperNoReturn<U> {
- /**
- * Invokes the method against the target object.
- *
- * @param targetObject the object against which the method should be invoked.
- */
- void callMethod(U targetObject);
- }
-
- /**
- * Invokes the specified method on the targetObject as the shell user. The method can be invoked
- * as follows:
- *
- * {@code ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
- * (tm) -> tm.getDeviceId());}
- */
- public static <T, U> T invokeMethodWithShellPermissions(U targetObject,
- ShellPermissionMethodHelper<T, U> methodHelper) {
- final UiAutomation uiAutomation =
- InstrumentationRegistry.getInstrumentation().getUiAutomation();
- try {
- uiAutomation.adoptShellPermissionIdentity();
- return methodHelper.callMethod(targetObject);
- } finally {
- uiAutomation.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Invokes the specified method on the targetObject as the shell user. The method can be invoked
- * as follows:
- *
- * {@code ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
- * (tm) -> tm.getDeviceId());}
- */
- public static <U> void invokeMethodWithShellPermissionsNoReturn(
- U targetObject, ShellPermissionMethodHelperNoReturn<U> methodHelper) {
- final UiAutomation uiAutomation =
- InstrumentationRegistry.getInstrumentation().getUiAutomation();
- try {
- uiAutomation.adoptShellPermissionIdentity();
- methodHelper.callMethod(targetObject);
- } finally {
- uiAutomation.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Utility interface to invoke a static method.
- *
- * @param <T> the type returned by the invoked method.
- */
- public interface StaticShellPermissionMethodHelper<T> {
- /**
- * Invokes the static method.
- *
- * @return the result of the invoked method.
- */
- T callMethod();
- }
-
- /**
- * Invokes the specified static method as the shell user. This method can be invoked as follows:
- *
- * {@code ShellIdentityUtils.invokeStaticMethodWithShellPermissions(Build::getSerial));}
- */
- public static <T> T invokeStaticMethodWithShellPermissions(
- StaticShellPermissionMethodHelper<T> methodHelper) {
- final UiAutomation uiAutomation =
- InstrumentationRegistry.getInstrumentation().getUiAutomation();
- try {
- uiAutomation.adoptShellPermissionIdentity();
- return methodHelper.callMethod();
- } finally {
- uiAutomation.dropShellPermissionIdentity();
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ShellUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/ShellUtils.java
deleted file mode 100644
index 8cb3290..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/ShellUtils.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
-
-import android.support.test.InstrumentationRegistry;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.View;
-
-import androidx.annotation.NonNull;
-
-/**
- * Provides Shell-based utilities such as running a command.
- */
-public final class ShellUtils {
-
- private static final String TAG = "ShellHelper";
-
- /**
- * Runs a Shell command, returning a trimmed response.
- */
- @NonNull
- public static String runShellCommand(@NonNull String template, Object...args) {
- final String command = String.format(template, args);
- Log.d(TAG, "runShellCommand(): " + command);
- try {
- final String result = SystemUtil
- .runShellCommand(InstrumentationRegistry.getInstrumentation(), command);
- return TextUtils.isEmpty(result) ? "" : result.trim();
- } catch (Exception e) {
- throw new RuntimeException("Command '" + command + "' failed: ", e);
- }
- }
-
- /**
- * Tap on the view center, it may change window focus.
- */
- public static void tap(View view) {
- final int[] xy = new int[2];
- view.getLocationOnScreen(xy);
- final int viewWidth = view.getWidth();
- final int viewHeight = view.getHeight();
- final int x = (int) (xy[0] + (viewWidth / 2.0f));
- final int y = (int) (xy[1] + (viewHeight / 2.0f));
-
- runShellCommand("input touchscreen tap %d %d", x, y);
- }
-
-
- private ShellUtils() {
- throw new UnsupportedOperationException("contain static methods only");
- }
-
- /**
- * Simulates input of key event.
- *
- * @param keyCode key event to fire.
- */
- public static void sendKeyEvent(String keyCode) {
- runShellCommand("input keyevent " + keyCode);
- }
-
- /**
- * Allows an app to draw overlaid windows.
- */
- public static void setOverlayPermissions(@NonNull String packageName, boolean allowed) {
- final String action = allowed ? "allow" : "ignore";
- runShellCommand("appops set %s SYSTEM_ALERT_WINDOW %s", packageName, action);
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/StateChangerRule.java b/common/device-side/util/src/com/android/compatibility/common/util/StateChangerRule.java
deleted file mode 100644
index 4e59f13..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/StateChangerRule.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.google.common.base.Preconditions;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import java.util.Objects;
-
-/**
- * JUnit rule used to prepare a state before the test is run.
- *
- * <p>It stores the current state before the test, changes it (if necessary), then restores it after
- * the test (if necessary).
- *
- * @param <T> value type
- */
-public class StateChangerRule<T> implements TestRule {
-
- private final StateManager<T> mStateManager;
- private final T mValue;
-
- /**
- * Default constructor.
- *
- * @param stateManager abstraction used to mange the state.
- * @param value value to be set before the test is run.
- */
- public StateChangerRule(@NonNull StateManager<T> stateManager, @Nullable T value) {
- mStateManager = Preconditions.checkNotNull(stateManager);
- mValue = value;
- }
-
- @Override
- public Statement apply(Statement base, Description description) {
- return new Statement() {
-
- @Override
- public void evaluate() throws Throwable {
- final T previousValue = mStateManager.get();
- if (!Objects.equals(previousValue, mValue)) {
- mStateManager.set(mValue);
- }
- try {
- base.evaluate();
- } finally {
- final T currentValue = mStateManager.get();
- if (!Objects.equals(currentValue, previousValue)) {
- mStateManager.set(previousValue);
- // TODO: if set() thowns a RuntimeException, JUnit will silently catch it
- // and re-run the test case; it should fail instead.
- }
- }
- }
- };
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/StateKeeperRule.java b/common/device-side/util/src/com/android/compatibility/common/util/StateKeeperRule.java
deleted file mode 100644
index ecc02a2..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/StateKeeperRule.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import androidx.annotation.NonNull;
-
-import com.google.common.base.Preconditions;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import java.util.Objects;
-
-/**
- * JUnit rule used to restore a state after the test is run.
- *
- * <p>It stores the current state before the test, and restores it after the test (if necessary).
- *
- * @param <T> value type
- */
-public class StateKeeperRule<T> implements TestRule {
-
- private final StateManager<T> mStateManager;
-
- /**
- * Default constructor.
- *
- * @param stateManager abstraction used to mange the state.
- */
- public StateKeeperRule(@NonNull StateManager<T> stateManager) {
- mStateManager = Preconditions.checkNotNull(stateManager);
- }
-
- /**
- * Hook for subclasses.
- */
- protected void preEvaluate(@SuppressWarnings("unused") Description description) {
- }
-
- /**
- * Hook for subclasses.
- */
- protected void postEvaluate(@SuppressWarnings("unused") Description description) {
- }
-
- @Override
- public Statement apply(Statement base, Description description) {
- return new Statement() {
-
- @Override
- public void evaluate() throws Throwable {
- final T previousValue = mStateManager.get();
- preEvaluate(description);
- try {
- base.evaluate();
- } finally {
- final T currentValue = mStateManager.get();
- if (!Objects.equals(previousValue, currentValue)) {
- mStateManager.set(previousValue);
- }
- }
- postEvaluate(description);
- }
- };
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/StateManager.java b/common/device-side/util/src/com/android/compatibility/common/util/StateManager.java
deleted file mode 100644
index 2077e08..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/StateManager.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.util;
-
-import androidx.annotation.Nullable;
-
-/**
- * Abstraction for a state that is managed somewhere, like Android Settings.
- *
- * @param <T> value type
- */
-public interface StateManager<T> {
-
- /**
- * Sets a new state.
- */
- void set(@Nullable T value);
-
- /**
- * Gets the current state.
- */
- @Nullable T get();
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/SystemUtil.java b/common/device-side/util/src/com/android/compatibility/common/util/SystemUtil.java
deleted file mode 100644
index fa7f046..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/SystemUtil.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2014 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.compatibility.common.util;
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.app.ActivityManager;
-import android.app.ActivityManager.MemoryInfo;
-import android.app.Instrumentation;
-import android.app.UiAutomation;
-import android.content.Context;
-import android.os.ParcelFileDescriptor;
-import android.os.StatFs;
-import android.support.test.InstrumentationRegistry;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.concurrent.Callable;
-import java.util.function.Predicate;
-
-public class SystemUtil {
- private static final String TAG = "CtsSystemUtil";
-
- public static long getFreeDiskSize(Context context) {
- final StatFs statFs = new StatFs(context.getFilesDir().getAbsolutePath());
- return (long)statFs.getAvailableBlocks() * statFs.getBlockSize();
- }
-
- public static long getFreeMemory(Context context) {
- final MemoryInfo info = new MemoryInfo();
- ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(info);
- return info.availMem;
- }
-
- public static long getTotalMemory(Context context) {
- final MemoryInfo info = new MemoryInfo();
- ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(info);
- return info.totalMem;
- }
-
- /**
- * Executes a shell command using shell user identity, and return the standard output in string
- * <p>Note: calling this function requires API level 21 or above
- * @param instrumentation {@link Instrumentation} instance, obtained from a test running in
- * instrumentation framework
- * @param cmd the command to run
- * @return the standard output of the command
- * @throws Exception
- */
- public static String runShellCommand(Instrumentation instrumentation, String cmd)
- throws IOException {
- Log.v(TAG, "Running command: " + cmd);
- if (cmd.startsWith("pm grant ") || cmd.startsWith("pm revoke ")) {
- throw new UnsupportedOperationException("Use UiAutomation.grantRuntimePermission() "
- + "or revokeRuntimePermission() directly, which are more robust.");
- }
- ParcelFileDescriptor pfd = instrumentation.getUiAutomation().executeShellCommand(cmd);
- byte[] buf = new byte[512];
- int bytesRead;
- FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
- StringBuffer stdout = new StringBuffer();
- while ((bytesRead = fis.read(buf)) != -1) {
- stdout.append(new String(buf, 0, bytesRead));
- }
- fis.close();
- return stdout.toString();
- }
-
- /**
- * Simpler version of {@link #runShellCommand(Instrumentation, String)}.
- */
- public static String runShellCommand(String cmd) {
- try {
- return runShellCommand(InstrumentationRegistry.getInstrumentation(), cmd);
- } catch (IOException e) {
- fail("Failed reading command output: " + e);
- return "";
- }
- }
-
- /**
- * Same as {@link #runShellCommand(String)}, with optionally
- * check the result using {@code resultChecker}.
- */
- public static String runShellCommand(String cmd, Predicate<String> resultChecker) {
- final String result = runShellCommand(cmd);
- if (resultChecker != null) {
- assertTrue("Assertion failed. Command was: " + cmd + "\n"
- + "Output was:\n" + result,
- resultChecker.test(result));
- }
- return result;
- }
-
- /**
- * Same as {@link #runShellCommand(String)}, but fails if the output is not empty.
- */
- public static String runShellCommandForNoOutput(String cmd) {
- final String result = runShellCommand(cmd);
- assertTrue("Command failed. Command was: " + cmd + "\n"
- + "Didn't expect any output, but the output was:\n" + result,
- result.length() == 0);
- return result;
- }
-
- /**
- * Runs a command and print the result on logcat.
- */
- public static void runCommandAndPrintOnLogcat(String logtag, String cmd) {
- Log.i(logtag, "Executing: " + cmd);
- final String output = runShellCommand(cmd);
- for (String line : output.split("\\n", -1)) {
- Log.i(logtag, line);
- }
- }
-
- /**
- * Runs a command and return the section matching the patterns.
- *
- * @see TextUtils#extractSection
- */
- public static String runCommandAndExtractSection(String cmd,
- String extractionStartRegex, boolean startInclusive,
- String extractionEndRegex, boolean endInclusive) {
- return TextUtils.extractSection(runShellCommand(cmd), extractionStartRegex, startInclusive,
- extractionEndRegex, endInclusive);
- }
-
- /**
- * Runs a {@link ThrowingRunnable} adopting Shell's permissions.
- */
- public static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable runnable) {
- final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
- runWithShellPermissionIdentity(automan, runnable);
- }
-
- /**
- * Runs a {@link ThrowingRunnable} adopting a subset of Shell's permissions.
- */
- public static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable runnable,
- String... permissions) {
- final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
- runWithShellPermissionIdentity(automan, runnable, permissions);
- }
-
- /**
- * Runs a {@link ThrowingRunnable} adopting Shell's permissions, where you can specify the
- * uiAutomation used.
- */
- public static void runWithShellPermissionIdentity(
- @NonNull UiAutomation automan, @NonNull ThrowingRunnable runnable) {
- runWithShellPermissionIdentity(automan, runnable, null /* permissions */);
- }
-
- /**
- * Runs a {@link ThrowingRunnable} adopting Shell's permissions, where you can specify the
- * uiAutomation used.
- * @param automan UIAutomation to use.
- * @param runnable The code to run with Shell's identity.
- * @param permissions A subset of Shell's permissions. Passing {@code null} will use all
- * available permissions.
- */
- public static void runWithShellPermissionIdentity(@NonNull UiAutomation automan,
- @NonNull ThrowingRunnable runnable, String... permissions) {
- automan.adoptShellPermissionIdentity(permissions);
- try {
- runnable.run();
- } catch (Exception e) {
- throw new RuntimeException("Caught exception", e);
- } finally {
- automan.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Calls a {@link Callable} adopting Shell's permissions.
- */
- public static <T> T callWithShellPermissionIdentity(@NonNull Callable<T> callable)
- throws Exception {
- final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
- automan.adoptShellPermissionIdentity();
- try {
- return callable.call();
- } finally {
- automan.dropShellPermissionIdentity();
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/TestNameUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/TestNameUtils.java
deleted file mode 100644
index 2dbeaab..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/TestNameUtils.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-/**
- * Generic helper used to set / get the the name of the test being run.
- *
- * <p>Typically used on {@code @Rule} classes.
- */
-public final class TestNameUtils {
-
- private static String sCurrentTestName;
- private static String sCurrentTestClass;
-
- /**
- * Gets the name of the test current running.
- */
- @NonNull
- public static String getCurrentTestName() {
- if (sCurrentTestName != null) return sCurrentTestName;
- if (sCurrentTestClass != null) return sCurrentTestClass;
- return "(Unknown test)";
- }
-
- /**
- * Sets the name of the test current running
- */
- public static void setCurrentTestName(@Nullable String name) {
- sCurrentTestName = name;
- }
-
- /**
- * Sets the name of the test class current running
- */
- public static void setCurrentTestClass(@Nullable String testClass) {
- sCurrentTestClass = testClass;
- }
-
- /**
- * Checks whether a test is running, based on whether {@link #setCurrentTestName(String)} was
- * called.
- */
- public static boolean isRunningTest() {
- return sCurrentTestName != null;
- }
-
- private TestNameUtils() {
- throw new UnsupportedOperationException("contain static methods only");
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/TestThread.java b/common/device-side/util/src/com/android/compatibility/common/util/TestThread.java
deleted file mode 100644
index 894b9c8..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/TestThread.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2009 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.compatibility.common.util;
-
-/**
- * Thread class for executing a Runnable containing assertions in a separate thread.
- * Uncaught exceptions in the Runnable are rethrown in the context of the the thread
- * calling the <code>runTest()</code> method.
- */
-public final class TestThread extends Thread {
- private Throwable mThrowable;
- private Runnable mTarget;
-
- public TestThread(Runnable target) {
- mTarget = target;
- }
-
- @Override
- public final void run() {
- try {
- mTarget.run();
- } catch (Throwable t) {
- mThrowable = t;
- }
- }
-
- /**
- * Run the target Runnable object and wait until the test finish or throw
- * out Exception if test fail.
- *
- * @param runTime
- * @throws Throwable
- */
- public void runTest(long runTime) throws Throwable {
- start();
- joinAndCheck(runTime);
- }
-
- /**
- * Get the Throwable object which is thrown when test running
- * @return The Throwable object
- */
- public Throwable getThrowable() {
- return mThrowable;
- }
-
- /**
- * Set the Throwable object which is thrown when test running
- * @param t The Throwable object
- */
- public void setThrowable(Throwable t) {
- mThrowable = t;
- }
-
- /**
- * Wait for the test thread to complete and throw the stored exception if there is one.
- *
- * @param runTime The time to wait for the test thread to complete.
- * @throws Throwable
- */
- public void joinAndCheck(long runTime) throws Throwable {
- this.join(runTime);
- if (this.isAlive()) {
- this.interrupt();
- this.join(runTime);
- throw new Exception("Thread did not finish within allotted time.");
- }
- checkException();
- }
-
- /**
- * Check whether there is an exception when running Runnable object.
- * @throws Throwable
- */
- public void checkException() throws Throwable {
- if (mThrowable != null) {
- throw mThrowable;
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/TestUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/TestUtils.java
deleted file mode 100644
index 3b82cb7..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/TestUtils.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import static junit.framework.Assert.fail;
-
-import android.os.SystemClock;
-import android.util.Log;
-
-import java.util.function.BooleanSupplier;
-
-public class TestUtils {
- private static final String TAG = "CtsTestUtils";
-
- private TestUtils() {
- }
-
- public static final int DEFAULT_TIMEOUT_SECONDS = 30;
-
- /** Print an error log and fail. */
- public static void failWithLog(String message) {
- Log.e(TAG, message);
- fail(message);
- }
-
- @FunctionalInterface
- public interface BooleanSupplierWithThrow {
- boolean getAsBoolean() throws Exception;
- }
-
- @FunctionalInterface
- public interface RunnableWithThrow {
- void run() throws Exception;
- }
-
- /**
- * Wait until {@code predicate} is satisfied, or fail, with {@link #DEFAULT_TIMEOUT_SECONDS}.
- */
- public static void waitUntil(String message, BooleanSupplierWithThrow predicate)
- throws Exception {
- waitUntil(message, 0, predicate);
- }
-
- /**
- * Wait until {@code predicate} is satisfied, or fail, with a given timeout.
- */
- public static void waitUntil(
- String message, int timeoutSecond, BooleanSupplierWithThrow predicate)
- throws Exception {
- if (timeoutSecond <= 0) {
- timeoutSecond = DEFAULT_TIMEOUT_SECONDS;
- }
- int sleep = 125;
- final long timeout = SystemClock.uptimeMillis() + timeoutSecond * 1000;
- while (SystemClock.uptimeMillis() < timeout) {
- if (predicate.getAsBoolean()) {
- return; // okay
- }
- Thread.sleep(sleep);
- sleep *= 5;
- sleep = Math.min(2000, sleep);
- }
- failWithLog("Timeout: " + message);
- }
-
- /**
- * Run a Runnable {@code r}, and if it throws, also run {@code onFailure}.
- */
- public static void runWithFailureHook(RunnableWithThrow r, RunnableWithThrow onFailure)
- throws Exception {
- if (r == null) {
- throw new NullPointerException("r");
- }
- if (onFailure == null) {
- throw new NullPointerException("onFailure");
- }
- try {
- r.run();
- } catch (Throwable th) {
- Log.e(TAG, "Caught exception: " + th, th);
- onFailure.run();
- throw th;
- }
- }
-
- /**
- * Synchronized wait for a specified condition.
- *
- * @param notifyLock Lock that will be notified when the condition might have changed
- * @param condition The condition to check
- * @param timeoutMs The timeout in millis
- * @param conditionName The name to include in the assertion. If null, will be given a default.
- */
- public static void waitOn(Object notifyLock, BooleanSupplier condition,
- long timeoutMs, String conditionName) {
- if (conditionName == null) conditionName = "condition";
- if (condition.getAsBoolean()) return;
-
- synchronized (notifyLock) {
- try {
- long timeSlept = 0;
- while (!condition.getAsBoolean() && timeSlept < timeoutMs) {
- long sleepStart = SystemClock.uptimeMillis();
- notifyLock.wait(timeoutMs - timeSlept);
- timeSlept += SystemClock.uptimeMillis() - sleepStart;
- }
- if (!condition.getAsBoolean()) {
- throw new AssertionError("Timed out after " + timeSlept
- + "ms waiting for: " + conditionName);
- }
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
- }
-}
-
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/TextUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/TextUtils.java
deleted file mode 100644
index cca2652..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/TextUtils.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import java.util.regex.Pattern;
-
-public class TextUtils {
- private TextUtils() {
- }
-
- /**
- * Return the first section in {@code source} between the line matches
- * {@code extractionStartRegex} and the line matches {@code extractionEndRegex}.
- */
- public static String extractSection(String source,
- String extractionStartRegex, boolean startInclusive,
- String extractionEndRegex, boolean endInclusive) {
-
- final Pattern start = Pattern.compile(extractionStartRegex);
- final Pattern end = Pattern.compile(extractionEndRegex);
-
- final StringBuilder sb = new StringBuilder();
- final String[] lines = source.split("\\n", -1);
-
- int i = 0;
- for (; i < lines.length; i++) {
- final String line = lines[i];
- if (start.matcher(line).matches()) {
- if (startInclusive) {
- sb.append(line);
- sb.append('\n');
- }
- i++;
- break;
- }
- }
-
- for (; i < lines.length; i++) {
- final String line = lines[i];
- if (end.matcher(line).matches()) {
- if (endInclusive) {
- sb.append(line);
- sb.append('\n');
- }
- break;
- }
- sb.append(line);
- sb.append('\n');
- }
- return sb.toString();
- }
-
- /**
- * Creates a string consisted of {@code size} chars {@code c}.
- */
- public static String repeat(char c, int size) {
- StringBuilder builder = new StringBuilder(size);
- for (int i = 1; i <= size; i++) {
- builder.append(c);
- }
- return builder.toString();
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ThermalUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/ThermalUtils.java
deleted file mode 100644
index a61ffc1..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/ThermalUtils.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import android.util.Log;
-
-/**
- * Device-side utility class for override/reset thermal status.
- */
-public final class ThermalUtils {
- private static final String TAG = "CtsThermalUtils";
-
- private ThermalUtils() {}
-
- /** Make the target device think it's not throttling. */
- public static void overrideThermalNotThrottling() throws Exception {
- overrideThermalStatus(0);
- }
-
- /**
- * Make the target device think it's in given throttling status.
- * @param status thermal status defined in android.os.Temperature
- */
- public static void overrideThermalStatus(int status) throws Exception {
- SystemUtil.runShellCommandForNoOutput("cmd thermalservice override-status " + status);
-
- Log.d(TAG, "override-status " + status);
- }
-
- /** Cancel the thermal override status on target device. */
- public static void resetThermalStatus() throws Exception {
- SystemUtil.runShellCommandForNoOutput("cmd thermalservice reset");
-
- Log.d(TAG, "reset");
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ThreadUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/ThreadUtils.java
deleted file mode 100644
index 3948628..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/ThreadUtils.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import android.os.SystemClock;
-
-public final class ThreadUtils {
- private ThreadUtils() {
- }
-
- public static void sleepUntilRealtime(long realtime) throws Exception {
- Thread.sleep(Math.max(0, realtime - SystemClock.elapsedRealtime()));
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/Timeout.java b/common/device-side/util/src/com/android/compatibility/common/util/Timeout.java
deleted file mode 100644
index 9ac6323..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/Timeout.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.util;
-
-import android.os.SystemClock;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
-
-import java.util.concurrent.Callable;
-
-/**
- * A "smart" timeout that supports exponential backoff.
- */
-//TODO: move to common CTS Code
-public final class Timeout {
-
- private static final String TAG = "Timeout";
- private static final boolean VERBOSE = true;
-
- private final String mName;
- private long mCurrentValue;
- private final float mMultiplier;
- private final long mMaxValue;
-
- private final Sleeper mSleeper;
-
- private static final Sleeper DEFAULT_SLEEPER = (t) -> SystemClock.sleep(t);
-
- /**
- * Default constructor.
- *
- * @param name name to be used for logging purposes.
- * @param initialValue initial timeout value, in ms.
- * @param multiplier multiplier for {@link #increase()}.
- * @param maxValue max timeout value (in ms) set by {@link #increase()}.
- *
- * @throws IllegalArgumentException if {@code name} is {@code null} or empty,
- * {@code initialValue}, {@code multiplir} or {@code maxValue} are less than {@code 1},
- * or if {@code initialValue} is higher than {@code maxValue}
- */
- public Timeout(String name, long initialValue, float multiplier, long maxValue) {
- this(DEFAULT_SLEEPER, name, initialValue, multiplier, maxValue);
- }
-
- @VisibleForTesting
- Timeout(@NonNull Sleeper sleeper, String name, long initialValue, float multiplier,
- long maxValue) {
- if (initialValue < 1 || maxValue < 1 || initialValue > maxValue) {
- throw new IllegalArgumentException(
- "invalid initial and/or max values: " + initialValue + " and " + maxValue);
- }
- if (multiplier <= 1) {
- throw new IllegalArgumentException("multiplier must be higher than 1: " + multiplier);
- }
- if (TextUtils.isEmpty(name)) {
- throw new IllegalArgumentException("no name");
- }
- mSleeper = sleeper;
- mName = name;
- mCurrentValue = initialValue;
- mMultiplier = multiplier;
- mMaxValue = maxValue;
- Log.d(TAG, "Constructor: " + this + " at " + TestNameUtils.getCurrentTestName());
- }
-
- /**
- * Gets the current timeout, in ms.
- */
- public long ms() {
- return mCurrentValue;
- }
-
- /**
- * Gets the max timeout, in ms.
- */
- public long getMaxValue() {
- return mMaxValue;
- }
-
- /**
- * @return the mMultiplier
- */
- public float getMultiplier() {
- return mMultiplier;
- }
-
- /**
- * Gets the user-friendly name of this timeout.
- */
- @NonNull
- public String getName() {
- return mName;
- }
-
- /**
- * Increases the current value by the {@link #getMultiplier()}, up to {@link #getMaxValue()}.
- *
- * @return previous current value.
- */
- public long increase() {
- final long oldValue = mCurrentValue;
- mCurrentValue = Math.min(mMaxValue, (long) (mCurrentValue * mMultiplier));
- if (oldValue != mCurrentValue) {
- Log.w(TAG, mName + " increased from " + oldValue + "ms to " + mCurrentValue + "ms at "
- + TestNameUtils.getCurrentTestName());
- }
- return oldValue;
- }
-
- /**
- * Runs a {@code job} many times before giving up, sleeping between failed attempts up to
- * {@link #ms()}.
- *
- * @param description description of the job for logging purposes.
- * @param job job to be run, must return {@code null} if it failed and should be retried.
- * @throws RetryableException if all attempts failed.
- * @throws IllegalArgumentException if {@code description} is {@code null} or empty, if
- * {@code job} is {@code null}, or if {@code maxAttempts} is less than 1.
- * @throws Exception any other exception thrown by helper methods.
- *
- * @return job's result.
- */
- public <T> T run(String description, Callable<T> job) throws Exception {
- return run(description, 100, job);
- }
-
- /**
- * Runs a {@code job} many times before giving up, sleeping between failed attempts up to
- * {@link #ms()}.
- *
- * @param description description of the job for logging purposes.
- * @param job job to be run, must return {@code null} if it failed and should be retried.
- * @param retryMs how long to sleep between failures.
- * @throws RetryableException if all attempts failed.
- * @throws IllegalArgumentException if {@code description} is {@code null} or empty, if
- * {@code job} is {@code null}, or if {@code maxAttempts} is less than 1.
- * @throws Exception any other exception thrown by helper methods.
- *
- * @return job's result.
- */
- public <T> T run(String description, long retryMs, Callable<T> job) throws Exception {
- if (TextUtils.isEmpty(description)) {
- throw new IllegalArgumentException("no description");
- }
- if (job == null) {
- throw new IllegalArgumentException("no job");
- }
- if (retryMs < 1) {
- throw new IllegalArgumentException("need to sleep at least 1ms, right?");
- }
- long startTime = SystemClock.elapsedRealtime();
- int attempt = 0;
- long totalSlept = 0;
- while (SystemClock.elapsedRealtime() - startTime <= mCurrentValue) {
- final T result = job.call();
- if (result != null) {
- // Good news, everyone: job succeeded on first attempt!
- return result;
- }
- attempt++;
- final long napTime = Math.min(retryMs, mCurrentValue - totalSlept);
- if (VERBOSE) {
- Log.v(TAG, description + " failed at attempt #" + attempt + "; sleeping for "
- + napTime + "ms before trying again");
- }
- mSleeper.sleep(napTime);
- totalSlept += napTime;
-
- retryMs *= mMultiplier;
- }
- Log.w(TAG, description + " failed after " + attempt + " attempts and " + totalSlept + "ms: "
- + this);
- throw new RetryableException(this, description);
- }
-
- @Override
- public String toString() {
- return mName + ": [current=" + mCurrentValue + "ms; multiplier=" + mMultiplier + "x; max="
- + mMaxValue + "ms]";
- }
-
- @VisibleForTesting
- interface Sleeper {
- void sleep(long napTimeMs);
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/Visitor.java b/common/device-side/util/src/com/android/compatibility/common/util/Visitor.java
deleted file mode 100644
index ab4bbfb..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/Visitor.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2018 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.compatibility.common.util;
-
-import androidx.annotation.NonNull;
-
-/**
- * Implements the Visitor design pattern
- *
- * @param <V> visited object
- */
-public interface Visitor<V> {
-
- /**
- * Visit that object.
- */
- void visit(@NonNull V visited);
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/WatchDog.java b/common/device-side/util/src/com/android/compatibility/common/util/WatchDog.java
deleted file mode 100644
index efcc693..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/WatchDog.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2012 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.compatibility.common.util;
-
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-import android.util.Log;
-
-import junit.framework.Assert;
-
-/**
- * class for checking if rendering function is alive or not.
- * panic if watch-dog is not reset over certain amount of time
- */
-public class WatchDog implements Runnable {
- private static final String TAG = "WatchDog";
- private Thread mThread;
- private Semaphore mSemaphore;
- private volatile boolean mStopRequested;
- private final long mTimeoutInMilliSecs;
- private TimeoutCallback mCallback = null;
-
- public WatchDog(long timeoutInMilliSecs) {
- mTimeoutInMilliSecs = timeoutInMilliSecs;
- }
-
- public WatchDog(long timeoutInMilliSecs, TimeoutCallback callback) {
- this(timeoutInMilliSecs);
- mCallback = callback;
- }
-
- /** start watch-dog */
- public void start() {
- Log.i(TAG, "start");
- mStopRequested = false;
- mSemaphore = new Semaphore(0);
- mThread = new Thread(this);
- mThread.start();
- }
-
- /** stop watch-dog */
- public void stop() {
- Log.i(TAG, "stop");
- if (mThread == null) {
- return; // already finished
- }
- mStopRequested = true;
- mSemaphore.release();
- try {
- mThread.join();
- } catch (InterruptedException e) {
- // ignore
- }
- mThread = null;
- mSemaphore = null;
- }
-
- /** resets watch-dog, thus prevent it from panic */
- public void reset() {
- if (!mStopRequested) { // stop requested, but rendering still on-going
- mSemaphore.release();
- }
- }
-
- @Override
- public void run() {
- while (!mStopRequested) {
- try {
- boolean success = mSemaphore.tryAcquire(mTimeoutInMilliSecs, TimeUnit.MILLISECONDS);
- if (mCallback == null) {
- Assert.assertTrue("Watchdog timed-out", success);
- } else if (!success) {
- mCallback.onTimeout();
- }
- } catch (InterruptedException e) {
- // this thread will not be interrupted,
- // but if it happens, just check the exit condition.
- }
- }
- }
-
- /**
- * Called by the Watchdog when it has timed out.
- */
- public interface TimeoutCallback {
-
- public void onTimeout();
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/WidgetTestUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/WidgetTestUtils.java
deleted file mode 100644
index 2f2b8f7..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/WidgetTestUtils.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright (C) 2008 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.compatibility.common.util;
-
-import static android.view.ViewTreeObserver.OnDrawListener;
-import static android.view.ViewTreeObserver.OnGlobalLayoutListener;
-
-import static org.mockito.hamcrest.MockitoHamcrest.argThat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.support.test.rule.ActivityTestRule;
-import android.text.Editable;
-import android.text.TextUtils;
-import android.view.View;
-import android.view.ViewTreeObserver;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import junit.framework.Assert;
-
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * The useful methods for widget test.
- */
-public class WidgetTestUtils {
- /**
- * Assert that two bitmaps have identical content (same dimensions, same configuration,
- * same pixel content).
- *
- * @param b1 the first bitmap which needs to compare.
- * @param b2 the second bitmap which needs to compare.
- */
- public static void assertEquals(Bitmap b1, Bitmap b2) {
- if (b1 == b2) {
- return;
- }
-
- if (b1 == null || b2 == null) {
- Assert.fail("the bitmaps are not equal");
- }
-
- // b1 and b2 are all not null.
- if (b1.getWidth() != b2.getWidth() || b1.getHeight() != b2.getHeight()
- || b1.getConfig() != b2.getConfig()) {
- Assert.fail("the bitmaps are not equal");
- }
-
- int w = b1.getWidth();
- int h = b1.getHeight();
- int s = w * h;
- int[] pixels1 = new int[s];
- int[] pixels2 = new int[s];
-
- b1.getPixels(pixels1, 0, w, 0, 0, w, h);
- b2.getPixels(pixels2, 0, w, 0, 0, w, h);
-
- for (int i = 0; i < s; i++) {
- if (pixels1[i] != pixels2[i]) {
- Assert.fail("the bitmaps are not equal");
- }
- }
- }
-
- /**
- * Find beginning of the special element.
- * @param parser XmlPullParser will be parsed.
- * @param firstElementName the target element name.
- *
- * @throws XmlPullParserException if XML Pull Parser related faults occur.
- * @throws IOException if I/O-related error occur when parsing.
- */
- public static final void beginDocument(XmlPullParser parser, String firstElementName)
- throws XmlPullParserException, IOException {
- Assert.assertNotNull(parser);
- Assert.assertNotNull(firstElementName);
-
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- ;
- }
-
- if (!parser.getName().equals(firstElementName)) {
- throw new XmlPullParserException("Unexpected start tag: found " + parser.getName()
- + ", expected " + firstElementName);
- }
- }
-
- /**
- * Compare the expected pixels with actual, scaling for the target context density
- *
- * @throws AssertionFailedError
- */
- public static void assertScaledPixels(int expected, int actual, Context context) {
- Assert.assertEquals(expected * context.getResources().getDisplayMetrics().density,
- actual, 3);
- }
-
- /** Converts dips into pixels using the {@link Context}'s density. */
- public static int convertDipToPixels(Context context, int dip) {
- float density = context.getResources().getDisplayMetrics().density;
- return Math.round(density * dip);
- }
-
- /**
- * Retrieve a bitmap that can be used for comparison on any density
- * @param resources
- * @return the {@link Bitmap} or <code>null</code>
- */
- public static Bitmap getUnscaledBitmap(Resources resources, int resId) {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inScaled = false;
- return BitmapFactory.decodeResource(resources, resId, options);
- }
-
- /**
- * Retrieve a dithered bitmap that can be used for comparison on any density
- * @param resources
- * @param config the preferred config for the returning bitmap
- * @return the {@link Bitmap} or <code>null</code>
- */
- public static Bitmap getUnscaledAndDitheredBitmap(Resources resources,
- int resId, Bitmap.Config config) {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inDither = true;
- options.inScaled = false;
- options.inPreferredConfig = config;
- return BitmapFactory.decodeResource(resources, resId, options);
- }
-
- /**
- * Argument matcher for equality check of a CharSequence.
- *
- * @param expected expected CharSequence
- *
- * @return
- */
- public static CharSequence sameCharSequence(final CharSequence expected) {
- return argThat(new BaseMatcher<CharSequence>() {
- @Override
- public boolean matches(Object o) {
- if (o instanceof CharSequence) {
- return TextUtils.equals(expected, (CharSequence) o);
- }
- return false;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("doesn't match " + expected);
- }
- });
- }
-
- /**
- * Argument matcher for equality check of an Editable.
- *
- * @param expected expected Editable
- *
- * @return
- */
- public static Editable sameEditable(final Editable expected) {
- return argThat(new BaseMatcher<Editable>() {
- @Override
- public boolean matches(Object o) {
- if (o instanceof Editable) {
- return TextUtils.equals(expected, (Editable) o);
- }
- return false;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("doesn't match " + expected);
- }
- });
- }
-
- /**
- * Runs the specified {@link Runnable} on the main thread and ensures that the specified
- * {@link View}'s tree is drawn before returning.
- *
- * @param activityTestRule the activity test rule used to run the test
- * @param view the view whose tree should be drawn before returning
- * @param runner the runnable to run on the main thread, or {@code null} to
- * simply force invalidation and a draw pass
- */
- public static void runOnMainAndDrawSync(@NonNull final ActivityTestRule activityTestRule,
- @NonNull final View view, @Nullable final Runnable runner) {
- final CountDownLatch latch = new CountDownLatch(1);
-
- try {
- activityTestRule.runOnUiThread(() -> {
- final OnDrawListener listener = new OnDrawListener() {
- @Override
- public void onDraw() {
- // posting so that the sync happens after the draw that's about to happen
- view.post(() -> {
- activityTestRule.getActivity().getWindow().getDecorView()
- .getViewTreeObserver().removeOnDrawListener(this);
- latch.countDown();
- });
- }
- };
-
- activityTestRule.getActivity().getWindow().getDecorView()
- .getViewTreeObserver().addOnDrawListener(listener);
-
- if (runner != null) {
- runner.run();
- }
- view.invalidate();
- });
-
- Assert.assertTrue("Expected draw pass occurred within 5 seconds",
- latch.await(5, TimeUnit.SECONDS));
- } catch (Throwable t) {
- throw new RuntimeException(t);
- }
- }
-
- /**
- * Runs the specified Runnable on the main thread and ensures that the activity's view tree is
- * laid out before returning.
- *
- * @param activityTestRule the activity test rule used to run the test
- * @param runner the runnable to run on the main thread. {@code null} is
- * allowed, and simply means that there no runnable is required.
- * @param forceLayout true if there should be an explicit call to requestLayout(),
- * false otherwise
- */
- public static void runOnMainAndLayoutSync(@NonNull final ActivityTestRule activityTestRule,
- @Nullable final Runnable runner, boolean forceLayout)
- throws Throwable {
- runOnMainAndLayoutSync(activityTestRule,
- activityTestRule.getActivity().getWindow().getDecorView(), runner, forceLayout);
- }
-
- /**
- * Runs the specified Runnable on the main thread and ensures that the specified view is
- * laid out before returning.
- *
- * @param activityTestRule the activity test rule used to run the test
- * @param view The view
- * @param runner the runnable to run on the main thread. {@code null} is
- * allowed, and simply means that there no runnable is required.
- * @param forceLayout true if there should be an explicit call to requestLayout(),
- * false otherwise
- */
- public static void runOnMainAndLayoutSync(@NonNull final ActivityTestRule activityTestRule,
- @NonNull final View view, @Nullable final Runnable runner, boolean forceLayout)
- throws Throwable {
- final View rootView = view.getRootView();
-
- final CountDownLatch latch = new CountDownLatch(1);
-
- activityTestRule.runOnUiThread(() -> {
- final OnGlobalLayoutListener listener = new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
- // countdown immediately since the layout we were waiting on has happened
- latch.countDown();
- }
- };
-
- rootView.getViewTreeObserver().addOnGlobalLayoutListener(listener);
-
- if (runner != null) {
- runner.run();
- }
-
- if (forceLayout) {
- rootView.requestLayout();
- }
- });
-
- try {
- Assert.assertTrue("Expected layout pass within 5 seconds",
- latch.await(5, TimeUnit.SECONDS));
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
-
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/WifiConfigCreator.java b/common/device-side/util/src/com/android/compatibility/common/util/WifiConfigCreator.java
deleted file mode 100755
index f2d1f65..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/WifiConfigCreator.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2015 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.compatibility.common.util;
-
-import static android.net.wifi.WifiManager.EXTRA_WIFI_STATE;
-import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.ProxyInfo;
-import android.net.Uri;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiManager;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A simple activity to create and manage wifi configurations.
- */
-public class WifiConfigCreator {
- public static final String ACTION_CREATE_WIFI_CONFIG =
- "com.android.compatibility.common.util.CREATE_WIFI_CONFIG";
- public static final String ACTION_UPDATE_WIFI_CONFIG =
- "com.android.compatibility.common.util.UPDATE_WIFI_CONFIG";
- public static final String ACTION_REMOVE_WIFI_CONFIG =
- "com.android.compatibility.common.util.REMOVE_WIFI_CONFIG";
- public static final String EXTRA_NETID = "extra-netid";
- public static final String EXTRA_SSID = "extra-ssid";
- public static final String EXTRA_SECURITY_TYPE = "extra-security-type";
- public static final String EXTRA_PASSWORD = "extra-password";
-
- public static final int SECURITY_TYPE_NONE = 1;
- public static final int SECURITY_TYPE_WPA = 2;
- public static final int SECURITY_TYPE_WEP = 3;
-
- private static final String TAG = "WifiConfigCreator";
-
- private static final long ENABLE_WIFI_WAIT_SEC = 10L;
-
- private final Context mContext;
- private final WifiManager mWifiManager;
-
- public WifiConfigCreator(Context context) {
- mContext = context;
- mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- }
-
- /**
- * Adds a new WiFi network.
- * @return network id or -1 in case of error
- */
- public int addNetwork(String ssid, boolean hidden, int securityType,
- String password) throws InterruptedException, SecurityException {
- checkAndEnableWifi();
-
- WifiConfiguration wifiConf = createConfig(ssid, hidden, securityType, password);
-
- int netId = mWifiManager.addNetwork(wifiConf);
-
- if (netId != -1) {
- mWifiManager.enableNetwork(netId, true);
- } else {
- Log.w(TAG, "Unable to add SSID '" + ssid + "': netId = " + netId);
- }
- return netId;
- }
-
- /**
- * Adds a new wifiConfiguration with OPEN security type, and the given pacProxy
- * verifies that the proxy is added by getting the configuration back, and checking it.
- * @return returns the PAC proxy URL after adding the network and getting it from WifiManager
- * @throws IllegalStateException if any of the WifiManager operations fail
- */
- public String addHttpProxyNetworkVerifyAndRemove(String ssid, String pacProxyUrl)
- throws IllegalStateException {
- String retrievedPacProxyUrl = null;
- int netId = -1;
- try {
- WifiConfiguration conf = createConfig(ssid, false, SECURITY_TYPE_NONE, null);
- if (pacProxyUrl != null) {
- conf.setHttpProxy(ProxyInfo.buildPacProxy(Uri.parse(pacProxyUrl)));
- }
- netId = mWifiManager.addNetwork(conf);
- if (netId == -1) {
- throw new IllegalStateException("Failed to addNetwork: " + ssid);
- }
- for (final WifiConfiguration w : mWifiManager.getConfiguredNetworks()) {
- if (w.SSID.equals(ssid)) {
- conf = w;
- break;
- }
- }
- if (conf == null) {
- throw new IllegalStateException("Failed to get WifiConfiguration for: " + ssid);
- }
- Uri pacProxyFileUri = null;
- ProxyInfo httpProxy = conf.getHttpProxy();
- if (httpProxy != null) pacProxyFileUri = httpProxy.getPacFileUrl();
- if (pacProxyFileUri != null) {
- retrievedPacProxyUrl = conf.getHttpProxy().getPacFileUrl().toString();
- }
- if (!mWifiManager.removeNetwork(netId)) {
- throw new IllegalStateException("Failed to remove WifiConfiguration: " + ssid);
- }
- } finally {
- mWifiManager.removeNetwork(netId);
- }
- return retrievedPacProxyUrl;
- }
-
- /**
- * Updates a new WiFi network.
- * @return network id (may differ from original) or -1 in case of error
- */
- public int updateNetwork(WifiConfiguration wifiConf, String ssid, boolean hidden,
- int securityType, String password) throws InterruptedException, SecurityException {
- checkAndEnableWifi();
- if (wifiConf == null) {
- return -1;
- }
-
- WifiConfiguration conf = createConfig(ssid, hidden, securityType, password);
- conf.networkId = wifiConf.networkId;
-
- int newNetId = mWifiManager.updateNetwork(conf);
-
- if (newNetId != -1) {
- mWifiManager.saveConfiguration();
- mWifiManager.enableNetwork(newNetId, true);
- } else {
- Log.w(TAG, "Unable to update SSID '" + ssid + "': netId = " + newNetId);
- }
- return newNetId;
- }
-
- /**
- * Updates a new WiFi network.
- * @return network id (may differ from original) or -1 in case of error
- */
- public int updateNetwork(int netId, String ssid, boolean hidden,
- int securityType, String password) throws InterruptedException, SecurityException {
- checkAndEnableWifi();
-
- WifiConfiguration wifiConf = null;
- List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
- for (WifiConfiguration config : configs) {
- if (config.networkId == netId) {
- wifiConf = config;
- break;
- }
- }
- return updateNetwork(wifiConf, ssid, hidden, securityType, password);
- }
-
- public boolean removeNetwork(int netId) {
- return mWifiManager.removeNetwork(netId);
- }
-
- /**
- * Creates a WifiConfiguration set up according to given parameters
- * @param ssid SSID of the network
- * @param hidden Is SSID not broadcast?
- * @param securityType One of {@link #SECURITY_TYPE_NONE}, {@link #SECURITY_TYPE_WPA} or
- * {@link #SECURITY_TYPE_WEP}
- * @param password Password for WPA or WEP
- * @return Created configuration object
- */
- private WifiConfiguration createConfig(String ssid, boolean hidden, int securityType,
- String password) {
- WifiConfiguration wifiConf = new WifiConfiguration();
- if (!TextUtils.isEmpty(ssid)) {
- wifiConf.SSID = '"' + ssid + '"';
- }
- wifiConf.status = WifiConfiguration.Status.ENABLED;
- wifiConf.hiddenSSID = hidden;
- switch (securityType) {
- case SECURITY_TYPE_NONE:
- wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
- break;
- case SECURITY_TYPE_WPA:
- updateForWPAConfiguration(wifiConf, password);
- break;
- case SECURITY_TYPE_WEP:
- updateForWEPConfiguration(wifiConf, password);
- break;
- }
- return wifiConf;
- }
-
- private void updateForWPAConfiguration(WifiConfiguration wifiConf, String wifiPassword) {
- wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
- if (!TextUtils.isEmpty(wifiPassword)) {
- wifiConf.preSharedKey = '"' + wifiPassword + '"';
- }
- }
-
- private void updateForWEPConfiguration(WifiConfiguration wifiConf, String password) {
- wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
- wifiConf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
- wifiConf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
- if (!TextUtils.isEmpty(password)) {
- int length = password.length();
- if ((length == 10 || length == 26
- || length == 58) && password.matches("[0-9A-Fa-f]*")) {
- wifiConf.wepKeys[0] = password;
- } else {
- wifiConf.wepKeys[0] = '"' + password + '"';
- }
- wifiConf.wepTxKeyIndex = 0;
- }
- }
-
- private void checkAndEnableWifi() throws InterruptedException {
- final CountDownLatch enabledLatch = new CountDownLatch(1);
-
- // Register a change receiver first to pick up events between isEnabled and setEnabled
- final BroadcastReceiver watcher = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getIntExtra(EXTRA_WIFI_STATE, -1) == WIFI_STATE_ENABLED) {
- enabledLatch.countDown();
- }
- }
- };
-
- mContext.registerReceiver(watcher, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));
- try {
- // In case wifi is not already enabled, wait for it to come up
- if (!mWifiManager.isWifiEnabled()) {
- SystemUtil.runShellCommand("svc wifi enable");
- enabledLatch.await(ENABLE_WIFI_WAIT_SEC, TimeUnit.SECONDS);
- }
- } finally {
- mContext.unregisterReceiver(watcher);
- }
- }
-}
-
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/Within.java b/common/device-side/util/src/com/android/compatibility/common/util/Within.java
deleted file mode 100644
index 4d9ff80..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/Within.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2016 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.compatibility.common.util;
-
-import android.os.SystemClock;
-
-import org.mockito.Mockito;
-import org.mockito.exceptions.base.MockitoAssertionError;
-import org.mockito.internal.verification.api.VerificationData;
-import org.mockito.invocation.Invocation;
-import org.mockito.verification.VerificationMode;
-
-import java.util.List;
-
-/**
- * Custom verification mode that allows waiting for the specific invocation to happen within
- * a certain time interval. Not that unlike {@link Mockito#timeout(int)}, this mode will not
- * return early and throw exception if the expected method was called with a different set of
- * parameters before the call that we're waiting for.
- */
-public class Within implements VerificationMode {
- private static final long TIME_SLICE = 50;
- private final long mTimeout;
-
- public Within(long timeout) {
- mTimeout = timeout;
- }
-
- @Override
- public void verify(VerificationData data) {
- long timeout = mTimeout;
- MockitoAssertionError errorToRethrow = null;
- // Loop in the same way we do in PollingCheck, sleeping and then testing for the target
- // invocation
- while (timeout > 0) {
- SystemClock.sleep(TIME_SLICE);
-
- try {
- final List<Invocation> actualInvocations = data.getAllInvocations();
- // Iterate over all invocations so far to see if we have a match
- for (Invocation invocation : actualInvocations) {
- if (data.getWanted().matches(invocation)) {
- // Found our match within our timeout. Mark all invocations as verified
- markAllInvocationsAsVerified(data);
- // and return
- return;
- }
- }
- } catch (MockitoAssertionError assertionError) {
- errorToRethrow = assertionError;
- }
-
- timeout -= TIME_SLICE;
- }
-
- if (errorToRethrow != null) {
- throw errorToRethrow;
- }
-
- throw new MockitoAssertionError(
- "Timed out while waiting " + mTimeout + "ms for " + data.getWanted().toString());
- }
-
- // TODO: Uncomment once upgraded to 2.7.13
- // @Override
- public VerificationMode description(String description) {
- // Return this for now.
- // TODO: Return wrapper once upgraded to 2.7.13
- return this;
- }
-
- private void markAllInvocationsAsVerified(VerificationData data) {
- for (Invocation invocation : data.getAllInvocations()) {
- invocation.markVerified();
- data.getWanted().captureArgumentsFrom(invocation);
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/IBooleanCallback.aidl b/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/IBooleanCallback.aidl
deleted file mode 100644
index 2fdb26b..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/IBooleanCallback.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.util.devicepolicy.provisioning;
-
-interface IBooleanCallback {
- oneway void onResult(boolean result);
-}
\ No newline at end of file
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java b/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java
deleted file mode 100644
index 05edf1a..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.util.devicepolicy.provisioning;
-
-import static android.app.admin.DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED;
-import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
-import static android.content.Intent.ACTION_MANAGED_PROFILE_ADDED;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.uiautomator.UiDevice;
-import android.util.Log;
-
-import com.android.compatibility.common.util.BlockingBroadcastReceiver;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-public class SilentProvisioningTestManager {
- private static final long TIMEOUT_SECONDS = 120L;
- private static final String TAG = "SilentProvisioningTest";
-
- private final LinkedBlockingQueue<Boolean> mProvisioningResults = new LinkedBlockingQueue(1);
-
- private final IBooleanCallback mProvisioningResultCallback = new IBooleanCallback.Stub() {
- @Override
- public void onResult(boolean result) {
- try {
- mProvisioningResults.put(result);
- } catch (InterruptedException e) {
- Log.e(TAG, "IBooleanCallback.callback", e);
- }
- }
- };
-
- private final Context mContext;
- private Intent mReceivedProfileProvisionedIntent;
-
- public SilentProvisioningTestManager(Context context) {
- mContext = context.getApplicationContext();
- }
-
- public Intent getReceviedProfileProvisionedIntent() {
- return mReceivedProfileProvisionedIntent;
- }
-
- public boolean startProvisioningAndWait(Intent provisioningIntent) throws InterruptedException {
- wakeUpAndDismissInsecureKeyguard();
- mContext.startActivity(getStartIntent(provisioningIntent));
- Log.i(TAG, "startActivity with intent: " + provisioningIntent);
-
- if (ACTION_PROVISION_MANAGED_PROFILE.equals(provisioningIntent.getAction())) {
- return waitManagedProfileProvisioning();
- } else {
- return waitDeviceOwnerProvisioning();
- }
- }
-
- private boolean waitDeviceOwnerProvisioning() throws InterruptedException {
- return pollProvisioningResult();
- }
-
- private boolean waitManagedProfileProvisioning() throws InterruptedException {
- BlockingBroadcastReceiver managedProfileProvisionedReceiver =
- new BlockingBroadcastReceiver(mContext, ACTION_MANAGED_PROFILE_PROVISIONED);
- BlockingBroadcastReceiver managedProfileAddedReceiver =
- new BlockingBroadcastReceiver(mContext, ACTION_MANAGED_PROFILE_ADDED);
- try {
- managedProfileProvisionedReceiver.register();
- managedProfileAddedReceiver.register();
-
- if (!pollProvisioningResult()) {
- return false;
- }
-
- mReceivedProfileProvisionedIntent =
- managedProfileProvisionedReceiver.awaitForBroadcast();
- if (mReceivedProfileProvisionedIntent == null) {
- Log.i(TAG, "managedProfileProvisionedReceiver.awaitForBroadcast(): failed");
- return false;
- }
-
- if (managedProfileAddedReceiver.awaitForBroadcast() == null) {
- Log.i(TAG, "managedProfileAddedReceiver.awaitForBroadcast(): failed");
- return false;
- }
- } finally {
- managedProfileProvisionedReceiver.unregisterQuietly();
- managedProfileAddedReceiver.unregisterQuietly();
- }
- return true;
- }
-
- private boolean pollProvisioningResult() throws InterruptedException {
- Boolean result = mProvisioningResults.poll(TIMEOUT_SECONDS, TimeUnit.SECONDS);
- if (result == null) {
- Log.i(TAG, "ManagedProvisioning doesn't return result within "
- + TIMEOUT_SECONDS + " seconds ");
- return false;
- }
-
- if (!result) {
- Log.i(TAG, "Failed to provision");
- return false;
- }
- return true;
- }
-
- private Intent getStartIntent(Intent intent) {
- final Bundle bundle = new Bundle();
- bundle.putParcelable(Intent.EXTRA_INTENT, intent);
- bundle.putBinder(StartProvisioningActivity.EXTRA_BOOLEAN_CALLBACK,
- mProvisioningResultCallback.asBinder());
- return new Intent(mContext, StartProvisioningActivity.class)
- .putExtras(bundle)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- }
-
- private static void wakeUpAndDismissInsecureKeyguard() {
- try {
- UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- uiDevice.wakeUp();
- uiDevice.pressMenu();
- } catch (RemoteException e) {
- Log.e(TAG, "wakeUpScreen", e);
- }
- }
-
- private static class BlockingReceiver extends BroadcastReceiver {
-
- private final CountDownLatch mLatch = new CountDownLatch(1);
- private final Context mContext;
- private final String mAction;
- private Intent mReceivedIntent;
-
- private BlockingReceiver(Context context, String action) {
- mContext = context;
- mAction = action;
- mReceivedIntent = null;
- }
-
- public void register() {
- mContext.registerReceiver(this, new IntentFilter(mAction));
- }
-
- public boolean await() throws InterruptedException {
- return mLatch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS);
- }
-
- public Intent getReceivedIntent() {
- return mReceivedIntent;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- mReceivedIntent = intent;
- mLatch.countDown();
- }
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/StartProvisioningActivity.java b/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/StartProvisioningActivity.java
deleted file mode 100644
index 4a98794..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/StartProvisioningActivity.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.util.devicepolicy.provisioning;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.WindowManager;
-
-/**
- * Must register it in AndroidManifest.xml
- * <activity android:name="com.android.compatibility.common.util.devicepolicy.provisioning.StartProvisioningActivity"></activity>
- */
-public class StartProvisioningActivity extends Activity {
- private static final int REQUEST_CODE = 1;
- private static final String TAG = "StartProvisionActivity";
-
- public static final String EXTRA_BOOLEAN_CALLBACK = "EXTRA_BOOLEAN_CALLBACK";
-
- IBooleanCallback mResultCallback;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Reduce flakiness of the test
- // Show activity on top of keyguard
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
- // Turn on screen to prevent activity being paused by system
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-
- mResultCallback = IBooleanCallback.Stub.asInterface(
- getIntent().getExtras().getBinder(EXTRA_BOOLEAN_CALLBACK));
- Log.i(TAG, "result callback class name " + mResultCallback);
-
- // Only provision it if the activity is not re-created
- if (savedInstanceState == null) {
- Intent provisioningIntent = getIntent().getParcelableExtra(Intent.EXTRA_INTENT);
-
- startActivityForResult(provisioningIntent, REQUEST_CODE);
- Log.i(TAG, "Start provisioning intent");
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == REQUEST_CODE) {
- try {
- boolean result = resultCode == RESULT_OK;
- mResultCallback.onResult(result);
- Log.i(TAG, "onActivityResult result: " + result);
- } catch (RemoteException e) {
- Log.e(TAG, "onActivityResult", e);
- }
- } else {
- super.onActivityResult(requestCode, resultCode, data);
- }
- }
-}
\ No newline at end of file
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/transition/TargetTracking.java b/common/device-side/util/src/com/android/compatibility/common/util/transition/TargetTracking.java
deleted file mode 100644
index 7c53921..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/transition/TargetTracking.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2016 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.compatibility.common.util.transition;
-
-import android.graphics.Rect;
-import android.view.View;
-
-import java.util.ArrayList;
-
-public interface TargetTracking {
- ArrayList<View> getTrackedTargets();
- void clearTargets();
- Rect getCapturedEpicenter();
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/transition/TrackingTransition.java b/common/device-side/util/src/com/android/compatibility/common/util/transition/TrackingTransition.java
deleted file mode 100644
index 55b235d..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/transition/TrackingTransition.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2016 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.compatibility.common.util.transition;
-
-import android.animation.Animator;
-import android.graphics.Rect;
-import android.transition.Transition;
-import android.transition.TransitionValues;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.ArrayList;
-
-/**
- * A transition that tracks which targets are applied to it.
- * It will assume any target that it applies to will have differences
- * between the start and end state, regardless of the differences
- * that actually exist. In other words, it doesn't actually check
- * any size or position differences or any other property of the view.
- * It just records the difference.
- * <p>
- * Both start and end value Views are recorded, but no actual animation
- * is created.
- */
-public class TrackingTransition extends Transition implements TargetTracking {
- public final ArrayList<View> targets = new ArrayList<>();
- private final Rect[] mEpicenter = new Rect[1];
- private static String PROP = "tracking:prop";
- private static String[] PROPS = { PROP };
-
- @Override
- public String[] getTransitionProperties() {
- return PROPS;
- }
-
- @Override
- public void captureStartValues(TransitionValues transitionValues) {
- transitionValues.values.put(PROP, 0);
- }
-
- @Override
- public void captureEndValues(TransitionValues transitionValues) {
- transitionValues.values.put(PROP, 1);
- }
-
- @Override
- public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
- TransitionValues endValues) {
- if (startValues != null) {
- targets.add(startValues.view);
- }
- if (endValues != null) {
- targets.add(endValues.view);
- }
- Rect epicenter = getEpicenter();
- if (epicenter != null) {
- mEpicenter[0] = new Rect(epicenter);
- } else {
- mEpicenter[0] = null;
- }
- return null;
- }
-
- @Override
- public ArrayList<View> getTrackedTargets() {
- return targets;
- }
-
- @Override
- public void clearTargets() {
- targets.clear();
- }
-
- @Override
- public Rect getCapturedEpicenter() {
- return mEpicenter[0];
- }
-}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/transition/TrackingVisibility.java b/common/device-side/util/src/com/android/compatibility/common/util/transition/TrackingVisibility.java
deleted file mode 100644
index 8a5a19e..0000000
--- a/common/device-side/util/src/com/android/compatibility/common/util/transition/TrackingVisibility.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2016 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.compatibility.common.util.transition;
-
-import android.animation.Animator;
-import android.graphics.Rect;
-import android.transition.TransitionValues;
-import android.transition.Visibility;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.ArrayList;
-
-/**
- * Visibility transition that tracks which targets are applied to it.
- * This transition does no animation.
- */
-public class TrackingVisibility extends Visibility implements TargetTracking {
- public final ArrayList<View> targets = new ArrayList<>();
- private final Rect[] mEpicenter = new Rect[1];
-
- @Override
- public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
- TransitionValues endValues) {
- targets.add(endValues.view);
- Rect epicenter = getEpicenter();
- if (epicenter != null) {
- mEpicenter[0] = new Rect(epicenter);
- } else {
- mEpicenter[0] = null;
- }
- return null;
- }
-
- @Override
- public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
- TransitionValues endValues) {
- targets.add(startValues.view);
- Rect epicenter = getEpicenter();
- if (epicenter != null) {
- mEpicenter[0] = new Rect(epicenter);
- } else {
- mEpicenter[0] = null;
- }
- return null;
- }
-
- @Override
- public ArrayList<View> getTrackedTargets() {
- return targets;
- }
-
- @Override
- public void clearTargets() {
- targets.clear();
- }
-
- @Override
- public Rect getCapturedEpicenter() {
- return mEpicenter[0];
- }
-}
diff --git a/common/device-side/util/tests/Android.bp b/common/device-side/util/tests/Android.bp
deleted file mode 100644
index 2abba37..0000000
--- a/common/device-side/util/tests/Android.bp
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (C) 2015 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.
-
-java_test {
- name: "compatibility-device-util-tests",
-
- srcs: ["src/**/*.java"],
-
- static_libs: [
- "compatibility-device-util",
- "junit",
- "testng", // TODO: remove once Android migrates to JUnit 4.12, which provide assertThrows
- "truth-prebuilt"
- ],
-
- sdk_version: "test_current",
-}
diff --git a/common/device-side/util/tests/src/com/android/compatibility/common/util/ApiLevelUtilTest.java b/common/device-side/util/tests/src/com/android/compatibility/common/util/ApiLevelUtilTest.java
deleted file mode 100644
index 13305c3..0000000
--- a/common/device-side/util/tests/src/com/android/compatibility/common/util/ApiLevelUtilTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-package com.android.compatibility.common.util;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import android.os.Build;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for {@line ApiLevelUtil}.
- */
-@RunWith(AndroidJUnit4.class)
-public class ApiLevelUtilTest {
-
- @Test
- public void testComparisonByInt() throws Exception {
- int version = Build.VERSION.SDK_INT;
-
- assertFalse(ApiLevelUtil.isBefore(version - 1));
- assertFalse(ApiLevelUtil.isBefore(version));
- assertTrue(ApiLevelUtil.isBefore(version + 1));
-
- assertTrue(ApiLevelUtil.isAfter(version - 1));
- assertFalse(ApiLevelUtil.isAfter(version));
- assertFalse(ApiLevelUtil.isAfter(version + 1));
-
- assertTrue(ApiLevelUtil.isAtLeast(version - 1));
- assertTrue(ApiLevelUtil.isAtLeast(version));
- assertFalse(ApiLevelUtil.isAtLeast(version + 1));
-
- assertFalse(ApiLevelUtil.isAtMost(version - 1));
- assertTrue(ApiLevelUtil.isAtMost(version));
- assertTrue(ApiLevelUtil.isAtMost(version + 1));
- }
-
- @Test
- public void testComparisonByString() throws Exception {
- // test should pass as long as device SDK version is at least 12
- assertTrue(ApiLevelUtil.isAtLeast("HONEYCOMB_MR1"));
- assertTrue(ApiLevelUtil.isAtLeast("12"));
- }
-
- @Test
- public void testResolveVersionString() throws Exception {
- // can only test versions known to the device build
- assertEquals(ApiLevelUtil.resolveVersionString("GINGERBREAD_MR1"), 10);
- assertEquals(ApiLevelUtil.resolveVersionString("10"), 10);
- assertEquals(ApiLevelUtil.resolveVersionString("HONEYCOMB"), 11);
- assertEquals(ApiLevelUtil.resolveVersionString("11"), 11);
- assertEquals(ApiLevelUtil.resolveVersionString("honeycomb_mr1"), 12);
- assertEquals(ApiLevelUtil.resolveVersionString("12"), 12);
- }
-
- @Test(expected = RuntimeException.class)
- public void testResolveMisspelledVersionString() throws Exception {
- ApiLevelUtil.resolveVersionString("GINGERBEARD");
- }
-}
diff --git a/common/device-side/util/tests/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutorTest.java b/common/device-side/util/tests/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutorTest.java
deleted file mode 100644
index 9f3ca47..0000000
--- a/common/device-side/util/tests/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutorTest.java
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-package com.android.compatibility.common.util;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
-import static org.junit.Assume.assumeTrue;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.AssumptionViolatedException;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import junit.framework.AssertionFailedError;
-
-/**
- * Tests for {@line BusinessLogicDeviceExecutor}.
- */
-@RunWith(AndroidJUnit4.class)
-public class BusinessLogicDeviceExecutorTest {
-
- private static final String THIS_CLASS =
- "com.android.compatibility.common.util.BusinessLogicDeviceExecutorTest";
- private static final String METHOD_1 = THIS_CLASS + ".method1";
- private static final String METHOD_2 = THIS_CLASS + ".method2";
- private static final String METHOD_3 = THIS_CLASS + ".method3";
- private static final String METHOD_4 = THIS_CLASS + ".method4";
- private static final String METHOD_5 = THIS_CLASS + ".method5";
- private static final String METHOD_6 = THIS_CLASS + ".method6";
- private static final String METHOD_7 = THIS_CLASS + ".method7";
- private static final String METHOD_8 = THIS_CLASS + ".method8";
- private static final String METHOD_9 = THIS_CLASS + ".method9";
- private static final String METHOD_10 = THIS_CLASS + ".method10";
- private static final String FAKE_METHOD = THIS_CLASS + ".methodDoesntExist";
- private static final String ARG_STRING_1 = "arg1";
- private static final String ARG_STRING_2 = "arg2";
-
- private static final String OTHER_METHOD_1 = THIS_CLASS + "$OtherClass.method1";
-
- private String mInvoked = null;
- private Object[] mArgsUsed = null;
- private Context mContext;
- private BusinessLogicExecutor mExecutor;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getTargetContext();
- mExecutor = new BusinessLogicDeviceExecutor(mContext, this);
- // reset the instance variables tracking the method invoked and the args used
- mInvoked = null;
- mArgsUsed = null;
- // reset the OtherClass class variable tracking the method invoked
- OtherClass.otherInvoked = null;
- }
-
- @Test
- public void testInvokeMethodInThisClass() throws Exception {
- mExecutor.invokeMethod(METHOD_1);
- // assert that mInvoked was set for this BusinessLogicDeviceExecutorTest instance
- assertEquals("Failed to invoke method in this class", mInvoked, METHOD_1);
- }
-
- @Test
- public void testInvokeMethodInOtherClass() throws Exception {
- mExecutor.invokeMethod(OTHER_METHOD_1);
- // assert that OtherClass.method1 was invoked, and static field of OtherClass was changed
- assertEquals("Failed to invoke method in other class", OtherClass.otherInvoked,
- OTHER_METHOD_1);
- }
-
- @Test
- public void testInvokeMethodWithStringArgs() throws Exception {
- mExecutor.invokeMethod(METHOD_2, ARG_STRING_1, ARG_STRING_2);
- assertEquals("Failed to invoke method in this class", mInvoked, METHOD_2);
- // assert both String arguments were correctly set for method2
- assertEquals("Failed to set first argument", mArgsUsed[0], ARG_STRING_1);
- assertEquals("Failed to set second argument", mArgsUsed[1], ARG_STRING_2);
- }
-
- @Test
- public void testInvokeMethodWithStringAndContextArgs() throws Exception {
- mExecutor.invokeMethod(METHOD_3, ARG_STRING_1);
- assertEquals("Failed to invoke method in this class", mInvoked, METHOD_3);
- // assert that String arg and Context arg were correctly set for method3
- assertEquals("Failed to set first argument", mArgsUsed[0], ARG_STRING_1);
- assertEquals("Failed to set second argument", mArgsUsed[1], mContext);
- }
-
- @Test
- public void testInvokeMethodWithContextAndStringArgs() throws Exception {
- mExecutor.invokeMethod(METHOD_4, ARG_STRING_1);
- assertEquals("Failed to invoke method in this class", mInvoked, METHOD_4);
- // Like testInvokeMethodWithStringAndContextArgs, but flip the args for method4
- assertEquals("Failed to set first argument", mArgsUsed[0], mContext);
- assertEquals("Failed to set second argument", mArgsUsed[1], ARG_STRING_1);
- }
-
- @Test
- public void testInvokeMethodWithStringArrayArg() throws Exception {
- mExecutor.invokeMethod(METHOD_5, ARG_STRING_1, ARG_STRING_2);
- assertEquals("Failed to invoke method in this class", mInvoked, METHOD_5);
- // assert both String arguments were correctly set for method5
- assertEquals("Failed to set first argument", mArgsUsed[0], ARG_STRING_1);
- assertEquals("Failed to set second argument", mArgsUsed[1], ARG_STRING_2);
- }
-
- @Test
- public void testInvokeMethodWithEmptyStringArrayArg() throws Exception {
- mExecutor.invokeMethod(METHOD_5);
- assertEquals("Failed to invoke method in this class", mInvoked, METHOD_5);
- // assert no String arguments were set for method5
- assertEquals("Incorrectly set args", mArgsUsed.length, 0);
- }
-
- @Test
- public void testInvokeMethodWithStringAndStringArrayArgs() throws Exception {
- mExecutor.invokeMethod(METHOD_6, ARG_STRING_1, ARG_STRING_2);
- assertEquals("Failed to invoke method in this class", mInvoked, METHOD_6);
- // assert both String arguments were correctly set for method6
- assertEquals("Failed to set first argument", mArgsUsed[0], ARG_STRING_1);
- assertEquals("Failed to set second argument", mArgsUsed[1], ARG_STRING_2);
- }
-
- @Test
- public void testInvokeMethodWithAllArgTypes() throws Exception {
- mExecutor.invokeMethod(METHOD_7, ARG_STRING_1, ARG_STRING_2);
- assertEquals("Failed to invoke method in this class", mInvoked, METHOD_7);
- // assert all arguments were correctly set for method7
- assertEquals("Failed to set first argument", mArgsUsed[0], ARG_STRING_1);
- assertEquals("Failed to set second argument", mArgsUsed[1], mContext);
- assertEquals("Failed to set third argument", mArgsUsed[2], ARG_STRING_2);
- }
-
- @Test
- public void testInvokeOverloadedMethodOneArg() throws Exception {
- mExecutor.invokeMethod(METHOD_1, ARG_STRING_1);
- assertEquals("Failed to invoke method in this class", mInvoked, METHOD_1);
- assertEquals("Set wrong number of arguments", mArgsUsed.length, 1);
- assertEquals("Failed to set first argument", mArgsUsed[0], ARG_STRING_1);
- }
-
- @Test
- public void testInvokeOverloadedMethodTwoArgs() throws Exception {
- mExecutor.invokeMethod(METHOD_1, ARG_STRING_1, ARG_STRING_2);
- assertEquals("Failed to invoke method in this class", mInvoked, METHOD_1);
- assertEquals("Set wrong number of arguments", mArgsUsed.length, 2);
- assertEquals("Failed to set first argument", mArgsUsed[0], ARG_STRING_1);
- assertEquals("Failed to set second argument", mArgsUsed[1], ARG_STRING_2);
- }
-
- @Test(expected = RuntimeException.class)
- public void testInvokeNonExistentMethod() throws Exception {
- mExecutor.invokeMethod(FAKE_METHOD, ARG_STRING_1, ARG_STRING_2);
- }
-
- @Test(expected = RuntimeException.class)
- public void testInvokeMethodTooManyArgs() throws Exception {
- mExecutor.invokeMethod(METHOD_3, ARG_STRING_1, ARG_STRING_2);
- }
-
- @Test(expected = RuntimeException.class)
- public void testInvokeMethodTooFewArgs() throws Exception {
- mExecutor.invokeMethod(METHOD_2, ARG_STRING_1);
- }
-
- @Test(expected = RuntimeException.class)
- public void testInvokeMethodIncompatibleArgs() throws Exception {
- mExecutor.invokeMethod(METHOD_8, ARG_STRING_1);
- }
-
- @Test
- public void testExecuteConditionCheckReturnValue() throws Exception {
- assertTrue("Wrong return value",
- mExecutor.executeCondition(METHOD_2, ARG_STRING_1, ARG_STRING_1));
- assertFalse("Wrong return value",
- mExecutor.executeCondition(METHOD_2, ARG_STRING_1, ARG_STRING_2));
- }
-
- @Test(expected = RuntimeException.class)
- public void testExecuteInvalidCondition() throws Exception {
- mExecutor.executeCondition(METHOD_1); // method1 does not return type boolean
- }
-
- @Test
- public void testExecuteAction() throws Exception {
- mExecutor.executeAction(METHOD_2, ARG_STRING_1, ARG_STRING_2);
- assertEquals("Failed to invoke method in this class", mInvoked, METHOD_2);
- // assert both String arguments were correctly set for method2
- assertEquals("Failed to set first argument", mArgsUsed[0], ARG_STRING_1);
- assertEquals("Failed to set second argument", mArgsUsed[1], ARG_STRING_2);
- }
-
- @Test(expected = RuntimeException.class)
- public void testExecuteActionThrowException() throws Exception {
- mExecutor.executeAction(METHOD_9);
- }
-
- @Test
- public void testExecuteActionViolateAssumption() throws Exception {
- try {
- mExecutor.executeAction(METHOD_10);
- // JUnit4 doesn't support expecting AssumptionViolatedException with "expected"
- // attribute on @Test annotation, so test using Assert.fail()
- fail("Expected assumption failure");
- } catch (AssumptionViolatedException e) {
- // expected
- }
- }
-
- public void method1() {
- mInvoked = METHOD_1;
- }
-
- // overloaded method with one arg
- public void method1(String arg1) {
- mInvoked = METHOD_1;
- mArgsUsed = new Object[]{arg1};
- }
-
- // overloaded method with two args
- public void method1(String arg1, String arg2) {
- mInvoked = METHOD_1;
- mArgsUsed = new Object[]{arg1, arg2};
- }
-
- public boolean method2(String arg1, String arg2) {
- mInvoked = METHOD_2;
- mArgsUsed = new Object[]{arg1, arg2};
- return arg1.equals(arg2);
- }
-
- public void method3(String arg1, Context arg2) {
- mInvoked = METHOD_3;
- mArgsUsed = new Object[]{arg1, arg2};
- }
-
- // Same as method3, but flipped args
- public void method4(Context arg1, String arg2) {
- mInvoked = METHOD_4;
- mArgsUsed = new Object[]{arg1, arg2};
- }
-
- public void method5(String... args) {
- mInvoked = METHOD_5;
- mArgsUsed = args;
- }
-
- public void method6(String arg1, String... moreArgs) {
- mInvoked = METHOD_6;
- List<String> allArgs = new ArrayList<>();
- allArgs.add(arg1);
- allArgs.addAll(Arrays.asList(moreArgs));
- mArgsUsed = allArgs.toArray(new String[0]);
- }
-
- public void method7(String arg1, Context arg2, String... moreArgs) {
- mInvoked = METHOD_7;
- List<Object> allArgs = new ArrayList<>();
- allArgs.add(arg1);
- allArgs.add(arg2);
- allArgs.addAll(Arrays.asList(moreArgs));
- mArgsUsed = allArgs.toArray(new Object[0]);
- }
-
- public void method8(String arg1, Integer arg2) {
- // This method should never be successfully invoked, since Integer parameter types are
- // unsupported for the BusinessLogic service
- }
-
- // throw AssertionFailedError
- @Ignore
- public void method9() throws AssertionFailedError {
- assertTrue(false);
- }
-
- // throw AssumptionViolatedException
- public void method10() throws AssumptionViolatedException {
- assumeTrue(false);
- }
-
- public static class OtherClass {
-
- public static String otherInvoked = null;
-
- public void method1() {
- otherInvoked = OTHER_METHOD_1;
- }
- }
-}
diff --git a/common/device-side/util/tests/src/com/android/compatibility/common/util/BusinessLogicTestCaseTest.java b/common/device-side/util/tests/src/com/android/compatibility/common/util/BusinessLogicTestCaseTest.java
deleted file mode 100644
index ad4acbb..0000000
--- a/common/device-side/util/tests/src/com/android/compatibility/common/util/BusinessLogicTestCaseTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-package com.android.compatibility.common.util;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
-
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Tests for {@line BusinessLogicTestCase}.
- */
-@RunWith(AndroidJUnit4.class)
-public class BusinessLogicTestCaseTest {
-
- private static final String KEY_1 = "key1";
- private static final String KEY_2 = "key2";
- private static final String VALUE_1 = "value1";
- private static final String VALUE_2 = "value2";
-
- DummyTest mDummyTest;
- DummyTest mOtherDummyTest;
-
- @Before
- public void setUp() {
- mDummyTest = new DummyTest();
- mOtherDummyTest = new DummyTest();
- }
-
- @Test
- public void testMapPut() throws Exception {
- mDummyTest.mapPut("instanceMap", KEY_1, VALUE_1);
- assertTrue("mapPut failed for instanceMap", mDummyTest.instanceMap.containsKey(KEY_1));
- assertEquals("mapPut failed for instanceMap", mDummyTest.instanceMap.get(KEY_1), VALUE_1);
- assertTrue("mapPut affected wrong instance", mOtherDummyTest.instanceMap.isEmpty());
- }
-
- @Test
- public void testStaticMapPut() throws Exception {
- mDummyTest.mapPut("staticMap", KEY_2, VALUE_2);
- assertTrue("mapPut failed for staticMap", mDummyTest.staticMap.containsKey(KEY_2));
- assertEquals("mapPut failed for staticMap", mDummyTest.staticMap.get(KEY_2), VALUE_2);
- assertTrue("mapPut on static map should affect all instances",
- mOtherDummyTest.staticMap.containsKey(KEY_2));
- }
-
- public static class DummyTest extends BusinessLogicTestCase {
- public Map<String, String> instanceMap = new HashMap<>();
- public static Map<String, String> staticMap = new HashMap<>();
- }
-}
diff --git a/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceReportTest.java b/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceReportTest.java
deleted file mode 100644
index ab42b32..0000000
--- a/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceReportTest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2015 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.compatibility.common.util;
-
-import android.app.Instrumentation;
-import android.os.Bundle;
-import android.os.Environment;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.lang.StringBuilder;
-
-import junit.framework.TestCase;
-
-import org.json.JSONObject;
-
-/**
- * Tests for {@line DeviceReportLog}.
- */
-public class DeviceReportTest extends TestCase {
-
- /**
- * A stub of {@link Instrumentation}
- */
- public class TestInstrumentation extends Instrumentation {
-
- private int mResultCode = -1;
- private Bundle mResults = null;
-
- @Override
- public void sendStatus(int resultCode, Bundle results) {
- mResultCode = resultCode;
- mResults = results;
- }
- }
-
- private static final int RESULT_CODE = 2;
- private static final String RESULT_KEY = "COMPATIBILITY_TEST_RESULT";
- private static final String TEST_MESSAGE_1 = "Foo";
- private static final double TEST_VALUE_1 = 3;
- private static final ResultType TEST_TYPE_1 = ResultType.HIGHER_BETTER;
- private static final ResultUnit TEST_UNIT_1 = ResultUnit.SCORE;
- private static final String TEST_MESSAGE_2 = "Bar";
- private static final double TEST_VALUE_2 = 5;
- private static final ResultType TEST_TYPE_2 = ResultType.LOWER_BETTER;
- private static final ResultUnit TEST_UNIT_2 = ResultUnit.COUNT;
- private static final String TEST_MESSAGE_3 = "Sample";
- private static final double TEST_VALUE_3 = 7;
- private static final ResultType TEST_TYPE_3 = ResultType.LOWER_BETTER;
- private static final ResultUnit TEST_UNIT_3 = ResultUnit.COUNT;
- private static final String TEST_MESSAGE_4 = "Message";
- private static final double TEST_VALUE_4 = 9;
- private static final ResultType TEST_TYPE_4 = ResultType.LOWER_BETTER;
- private static final ResultUnit TEST_UNIT_4 = ResultUnit.COUNT;
- private static final String REPORT_NAME_1 = "TestReport1";
- private static final String REPORT_NAME_2 = "TestReport2";
- private static final String STREAM_NAME_1 = "SampleStream1";
- private static final String STREAM_NAME_2 = "SampleStream2";
- private static final String STREAM_NAME_3 = "SampleStream3";
- private static final String STREAM_NAME_4 = "SampleStream4";
-
- public void testSubmit() throws Exception {
- DeviceReportLog log = new DeviceReportLog(REPORT_NAME_1, STREAM_NAME_1);
- log.addValue(TEST_MESSAGE_1, TEST_VALUE_1, TEST_TYPE_1, TEST_UNIT_1);
- log.setSummary(TEST_MESSAGE_2, TEST_VALUE_2, TEST_TYPE_2, TEST_UNIT_2);
- TestInstrumentation inst = new TestInstrumentation();
- log.submit(inst);
- assertEquals("Incorrect result code", RESULT_CODE, inst.mResultCode);
- assertNotNull("Bundle missing", inst.mResults);
- String metrics = inst.mResults.getString(RESULT_KEY);
- assertNotNull("Metrics missing", metrics);
- ReportLog result = ReportLog.parse(metrics);
- assertNotNull("Metrics could not be decoded", result);
- }
-
- public void testFile() throws Exception {
- assertTrue("External storage is not mounted",
- Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED));
- final File dir = new File(Environment.getExternalStorageDirectory(), "report-log-files");
- assertTrue("Report Log directory missing", dir.isDirectory() || dir.mkdirs());
-
- // Remove files from earlier possible runs.
- File[] files = dir.listFiles();
- for (File file : files) {
- file.delete();
- }
-
- TestInstrumentation inst = new TestInstrumentation();
-
- DeviceReportLog log1 = new DeviceReportLog(REPORT_NAME_1, STREAM_NAME_1);
- log1.addValue(TEST_MESSAGE_1, TEST_VALUE_1, TEST_TYPE_1, TEST_UNIT_1);
- log1.setSummary(TEST_MESSAGE_1, TEST_VALUE_1, TEST_TYPE_1, TEST_UNIT_1);
- log1.submit(inst);
-
- DeviceReportLog log2 = new DeviceReportLog(REPORT_NAME_1, STREAM_NAME_2);
- log2.addValue(TEST_MESSAGE_2, TEST_VALUE_2, TEST_TYPE_2, TEST_UNIT_2);
- log2.setSummary(TEST_MESSAGE_2, TEST_VALUE_2, TEST_TYPE_2, TEST_UNIT_2);
- log2.submit(inst);
-
- DeviceReportLog log3 = new DeviceReportLog(REPORT_NAME_2, STREAM_NAME_3);
- log3.addValue(TEST_MESSAGE_3, TEST_VALUE_3, TEST_TYPE_3, TEST_UNIT_3);
- log3.setSummary(TEST_MESSAGE_3, TEST_VALUE_3, TEST_TYPE_3, TEST_UNIT_3);
- log3.submit(inst);
-
- DeviceReportLog log4 = new DeviceReportLog(REPORT_NAME_2, STREAM_NAME_4);
- log4.addValue(TEST_MESSAGE_4, TEST_VALUE_4, TEST_TYPE_4, TEST_UNIT_4);
- log4.setSummary(TEST_MESSAGE_4, TEST_VALUE_4, TEST_TYPE_4, TEST_UNIT_4);
- log4.submit(inst);
-
- File jsonFile1 = new File(dir, REPORT_NAME_1 + ".reportlog.json");
- File jsonFile2 = new File(dir, REPORT_NAME_2 + ".reportlog.json");
- assertTrue("Report Log missing", jsonFile1.exists());
- assertTrue("Report Log missing", jsonFile2.exists());
-
- BufferedReader jsonReader = new BufferedReader(new FileReader(jsonFile1));
- StringBuilder metricsBuilder = new StringBuilder();
- String line;
- while ((line = jsonReader.readLine()) != null) {
- metricsBuilder.append(line);
- }
- String metrics = metricsBuilder.toString().trim();
- JSONObject jsonObject = new JSONObject(metrics);
- assertTrue("Incorrect metrics",
- jsonObject.getJSONObject(STREAM_NAME_1).getDouble(TEST_MESSAGE_1) == TEST_VALUE_1);
- assertTrue("Incorrect metrics",
- jsonObject.getJSONObject(STREAM_NAME_2).getDouble(TEST_MESSAGE_2) == TEST_VALUE_2);
-
- jsonReader = new BufferedReader(new FileReader(jsonFile2));
- metricsBuilder = new StringBuilder();
- while ((line = jsonReader.readLine()) != null) {
- metricsBuilder.append(line);
- }
- metrics = metricsBuilder.toString().trim();
- jsonObject = new JSONObject(metrics);
- assertTrue("Incorrect metrics",
- jsonObject.getJSONObject(STREAM_NAME_3).getDouble(TEST_MESSAGE_3) == TEST_VALUE_3);
- assertTrue("Incorrect metrics",
- jsonObject.getJSONObject(STREAM_NAME_4).getDouble(TEST_MESSAGE_4) == TEST_VALUE_4);
- }
-}
diff --git a/common/device-side/util/tests/src/com/android/compatibility/common/util/RetryRuleTest.java b/common/device-side/util/tests/src/com/android/compatibility/common/util/RetryRuleTest.java
deleted file mode 100644
index 644d95f..0000000
--- a/common/device-side/util/tests/src/com/android/compatibility/common/util/RetryRuleTest.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
-
-import org.junit.Test;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
-import org.junit.runners.model.Statement;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-@RunWith(MockitoJUnitRunner.class)
-public class RetryRuleTest {
-
- private final Description mDescription = Description.createSuiteDescription("Whatever");
-
- private static final RetryableException sRetryableException =
- new RetryableException("Y U NO RETRY?");
-
- private static class RetryableStatement<T extends Exception> extends Statement {
- private final int mNumberFailures;
- private int mNumberCalls;
- private final T mException;
-
- RetryableStatement(int numberFailures, T exception) {
- mNumberFailures = numberFailures;
- mException = exception;
- }
-
- @Override
- public void evaluate() throws Throwable {
- mNumberCalls++;
- if (mNumberCalls <= mNumberFailures) {
- throw mException;
- }
- }
-
- @Override
- public String toString() {
- return "RetryableStatement: failures=" + mNumberFailures + ", calls=" + mNumberCalls;
- }
- }
-
- private @Mock Statement mMockStatement;
-
- @Test
- public void testInvalidConstructor() throws Throwable {
- assertThrows(IllegalArgumentException.class, () -> new RetryRule(-1));
- }
-
- @Test
- public void testPassOnRetryableException() throws Throwable {
- final RetryRule rule = new RetryRule(1);
- rule.apply(new RetryableStatement<RetryableException>(1, sRetryableException), mDescription)
- .evaluate();
- }
-
- @Test
- public void testPassOnRetryableExceptionWithTimeout() throws Throwable {
- final Timeout timeout = new Timeout("YOUR TIME IS GONE", 1, 2, 10);
- final RetryableException exception = new RetryableException(timeout, "Y U NO?");
-
- final RetryRule rule = new RetryRule(1);
- rule.apply(new RetryableStatement<RetryableException>(1, exception), mDescription)
- .evaluate();
-
- // Assert timeout was increased
- assertThat(timeout.ms()).isEqualTo(2);
- }
-
- @Test
- public void testFailOnRetryableException() throws Throwable {
- final RetryRule rule = new RetryRule(1);
-
- final RetryableException actualException = expectThrows(RetryableException.class,
- () -> rule.apply(new RetryableStatement<RetryableException>(2, sRetryableException),
- mDescription).evaluate());
-
- assertThat(actualException).isSameAs(sRetryableException);
- }
-
- @Test
- public void testPassWhenDisabledAndStatementPass() throws Throwable {
- final RetryRule rule = new RetryRule(0);
-
- rule.apply(mMockStatement, mDescription).evaluate();
-
- verify(mMockStatement, times(1)).evaluate();
- }
-
- @Test
- public void testFailWhenDisabledAndStatementThrowsRetryableException() throws Throwable {
- final RetryableException exception = new RetryableException("Y U NO?");
- final RetryRule rule = new RetryRule(0);
- doThrow(exception).when(mMockStatement).evaluate();
-
- final RetryableException actualException = expectThrows(RetryableException.class,
- () -> rule.apply(mMockStatement, mDescription).evaluate());
-
- assertThat(actualException).isSameAs(exception);
- verify(mMockStatement, times(1)).evaluate();
- }
-
- @Test
- public void testFailWhenDisabledAndStatementThrowsNonRetryableException() throws Throwable {
- final RuntimeException exception = new RuntimeException("Y U NO?");
- final RetryRule rule = new RetryRule(0);
- doThrow(exception).when(mMockStatement).evaluate();
-
- final RuntimeException actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(mMockStatement, mDescription).evaluate());
-
- assertThat(actualException).isSameAs(exception);
- verify(mMockStatement, times(1)).evaluate();
- }
-}
diff --git a/common/device-side/util/tests/src/com/android/compatibility/common/util/SafeCleanerRuleTest.java b/common/device-side/util/tests/src/com/android/compatibility/common/util/SafeCleanerRuleTest.java
deleted file mode 100644
index a56d7b2..0000000
--- a/common/device-side/util/tests/src/com/android/compatibility/common/util/SafeCleanerRuleTest.java
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.verify;
-import static org.testng.Assert.expectThrows;
-
-import com.android.compatibility.common.util.SafeCleanerRule.Dumper;
-
-import com.google.common.collect.ImmutableList;
-
-import org.junit.AssumptionViolatedException;
-import org.junit.Test;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
-import org.junit.runners.model.Statement;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-import java.util.List;
-import java.util.concurrent.Callable;
-
-@RunWith(MockitoJUnitRunner.class)
-public class SafeCleanerRuleTest {
-
- private static class FailureStatement extends Statement {
- private final Throwable mThrowable;
-
- FailureStatement(Throwable t) {
- mThrowable = t;
- }
-
- @Override
- public void evaluate() throws Throwable {
- throw mThrowable;
- }
- }
-
- private final Description mDescription = Description.createSuiteDescription("Whatever");
- private final RuntimeException mRuntimeException = new RuntimeException("D'OH!");
-
- @Mock private Dumper mDumper;
-
- // Use mocks for objects that don't throw any exception.
- @Mock private ThrowingRunnable mGoodGuyRunner1;
- @Mock private ThrowingRunnable mGoodGuyRunner2;
- @Mock private Callable<List<Throwable>> mGoodGuyExtraExceptions1;
- @Mock private Callable<List<Throwable>> mGoodGuyExtraExceptions2;
- @Mock private Statement mGoodGuyStatement;
-
- @Test
- public void testEmptyRule_testPass() throws Throwable {
- final SafeCleanerRule rule = new SafeCleanerRule();
- rule.apply(mGoodGuyStatement, mDescription).evaluate();
- }
-
- @Test
- public void testEmptyRule_testFails() throws Throwable {
- final SafeCleanerRule rule = new SafeCleanerRule();
- final Throwable actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(new FailureStatement(mRuntimeException), mDescription).evaluate());
- assertThat(actualException).isSameAs(mRuntimeException);
- }
-
- @Test
- public void testEmptyRule_testFails_withDumper() throws Throwable {
- final SafeCleanerRule rule = new SafeCleanerRule().setDumper(mDumper);
- final Throwable actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(new FailureStatement(mRuntimeException), mDescription).evaluate());
- assertThat(actualException).isSameAs(mRuntimeException);
- verify(mDumper).dump("Whatever", actualException);
- }
-
- @Test
- public void testOnlyTestFails() throws Throwable {
- final SafeCleanerRule rule = new SafeCleanerRule()
- .run(mGoodGuyRunner1)
- .add(mGoodGuyExtraExceptions1);
- final Throwable actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(new FailureStatement(mRuntimeException), mDescription).evaluate());
- assertThat(actualException).isSameAs(mRuntimeException);
- verify(mGoodGuyRunner1).run();
- verify(mGoodGuyExtraExceptions1).call();
- }
-
- @Test
- public void testOnlyTestFails_withDumper() throws Throwable {
- final SafeCleanerRule rule = new SafeCleanerRule()
- .setDumper(mDumper)
- .run(mGoodGuyRunner1)
- .add(mGoodGuyExtraExceptions1);
- final Throwable actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(new FailureStatement(mRuntimeException), mDescription).evaluate());
- assertThat(actualException).isSameAs(mRuntimeException);
- verify(mGoodGuyRunner1).run();
- verify(mGoodGuyExtraExceptions1).call();
- verify(mDumper).dump("Whatever", actualException);
- }
-
- @Test
- public void testTestPass_oneRunnerFails() throws Throwable {
- final SafeCleanerRule rule = new SafeCleanerRule()
- .run(mGoodGuyRunner1)
- .run(() -> { throw mRuntimeException; })
- .run(mGoodGuyRunner2)
- .add(mGoodGuyExtraExceptions1);
- final Throwable actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(mGoodGuyStatement, mDescription).evaluate());
- assertThat(actualException).isSameAs(mRuntimeException);
- verify(mGoodGuyRunner1).run();
- verify(mGoodGuyRunner2).run();
- verify(mGoodGuyExtraExceptions1).call();
- }
-
- @Test
- public void testTestPass_oneRunnerFails_withDumper() throws Throwable {
- final SafeCleanerRule rule = new SafeCleanerRule()
- .setDumper(mDumper)
- .run(mGoodGuyRunner1)
- .run(() -> {
- throw mRuntimeException;
- })
- .run(mGoodGuyRunner2)
- .add(mGoodGuyExtraExceptions1);
- final Throwable actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(mGoodGuyStatement, mDescription).evaluate());
- assertThat(actualException).isSameAs(mRuntimeException);
- verify(mGoodGuyRunner1).run();
- verify(mGoodGuyRunner2).run();
- verify(mGoodGuyExtraExceptions1).call();
- verify(mDumper).dump("Whatever", actualException);
- }
-
- @Test
- public void testTestPass_oneExtraExceptionThrownAsCallable() throws Throwable {
- final SafeCleanerRule rule = new SafeCleanerRule()
- .run(mGoodGuyRunner1)
- .add(mRuntimeException)
- .add(mGoodGuyExtraExceptions1)
- .run(mGoodGuyRunner2);
- final Throwable actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(mGoodGuyStatement, mDescription).evaluate());
- assertThat(actualException).isSameAs(mRuntimeException);
- verify(mGoodGuyRunner1).run();
- verify(mGoodGuyRunner2).run();
- verify(mGoodGuyExtraExceptions1).call();
- }
-
- @Test
- public void testTestPass_oneExtraExceptionThrown() throws Throwable {
- final SafeCleanerRule rule = new SafeCleanerRule()
- .run(mGoodGuyRunner1)
- .add(() -> {
- return ImmutableList.of(mRuntimeException);
- })
- .add(mGoodGuyExtraExceptions1)
- .run(mGoodGuyRunner2);
- final Throwable actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(mGoodGuyStatement, mDescription).evaluate());
- assertThat(actualException).isSameAs(mRuntimeException);
- verify(mGoodGuyRunner1).run();
- verify(mGoodGuyRunner2).run();
- verify(mGoodGuyExtraExceptions1).call();
- }
-
- @Test
- public void testTestPass_oneExtraExceptionThrown_withDumper() throws Throwable {
- final SafeCleanerRule rule = new SafeCleanerRule()
- .setDumper(mDumper)
- .run(mGoodGuyRunner1)
- .add(() -> { return ImmutableList.of(mRuntimeException); })
- .add(mGoodGuyExtraExceptions1)
- .run(mGoodGuyRunner2);
- final Throwable actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(mGoodGuyStatement, mDescription).evaluate());
- assertThat(actualException).isSameAs(mRuntimeException);
- verify(mGoodGuyRunner1).run();
- verify(mGoodGuyRunner2).run();
- verify(mGoodGuyExtraExceptions1).call();
- verify(mDumper).dump("Whatever", actualException);
- }
-
- @Test
- public void testThrowTheKitchenSinkAKAEverybodyThrows() throws Throwable {
- final Exception extra1 = new Exception("1");
- final Exception extra2 = new Exception("2");
- final Exception extra3 = new Exception("3");
- final Error error1 = new Error("one");
- final Error error2 = new Error("two");
- final RuntimeException testException = new RuntimeException("TEST, Y U NO PASS?");
- final SafeCleanerRule rule = new SafeCleanerRule()
- .run(mGoodGuyRunner1)
- .add(mGoodGuyExtraExceptions1)
- .add(mRuntimeException)
- .add(() -> {
- return ImmutableList.of(extra1, extra2);
- })
- .run(() -> {
- throw error1;
- })
- .run(mGoodGuyRunner2)
- .add(() -> {
- return ImmutableList.of(extra3);
- })
- .add(mGoodGuyExtraExceptions2)
- .run(() -> {
- throw error2;
- });
-
- final SafeCleanerRule.MultipleExceptions actualException = expectThrows(
- SafeCleanerRule.MultipleExceptions.class,
- () -> rule.apply(new FailureStatement(testException), mDescription).evaluate());
- assertThat(actualException.getThrowables())
- .containsExactly(testException, mRuntimeException, error1, error2, extra1, extra2,
- extra3)
- .inOrder();
- verify(mGoodGuyRunner1).run();
- verify(mGoodGuyRunner2).run();
- verify(mGoodGuyExtraExceptions1).call();
- }
-
- @Test
- public void testIgnoreAssumptionViolatedException() throws Throwable {
- final AssumptionViolatedException ave = new AssumptionViolatedException(
- "tis an assumption violation");
- final RuntimeException testException = new RuntimeException("TEST, Y U NO PASS?");
- final SafeCleanerRule rule = new SafeCleanerRule()
- .run(mGoodGuyRunner1)
- .add(mRuntimeException)
- .run(() -> {
- throw ave;
- });
-
- final SafeCleanerRule.MultipleExceptions actualException = expectThrows(
- SafeCleanerRule.MultipleExceptions.class,
- () -> rule.apply(new FailureStatement(testException), mDescription).evaluate());
- assertThat(actualException.getThrowables())
- .containsExactly(testException, mRuntimeException)
- .inOrder();
- verify(mGoodGuyRunner1).run();
- }
-
- @Test
- public void testThrowTheKitchenSinkAKAEverybodyThrows_withDumper() throws Throwable {
- final Exception extra1 = new Exception("1");
- final Exception extra2 = new Exception("2");
- final Exception extra3 = new Exception("3");
- final Exception extra4 = new Exception("4");
- final Error error1 = new Error("one");
- final Error error2 = new Error("two");
- final RuntimeException testException = new RuntimeException("TEST, Y U NO PASS?");
- final SafeCleanerRule rule = new SafeCleanerRule()
- .setDumper(mDumper)
- .run(mGoodGuyRunner1)
- .add(mGoodGuyExtraExceptions1)
- .add(() -> {
- return ImmutableList.of(extra1, extra2);
- })
- .run(() -> {
- throw error1;
- })
- .run(mGoodGuyRunner2)
- .add(() -> { return ImmutableList.of(extra3); })
- .add(mGoodGuyExtraExceptions2)
- .run(() -> {
- throw error2;
- })
- .run(() -> {
- throw extra4;
- });
-
- final SafeCleanerRule.MultipleExceptions actualException = expectThrows(
- SafeCleanerRule.MultipleExceptions.class,
- () -> rule.apply(new FailureStatement(testException), mDescription).evaluate());
- assertThat(actualException.getThrowables())
- .containsExactly(testException, error1, error2, extra4, extra1, extra2, extra3)
- .inOrder();
- verify(mGoodGuyRunner1).run();
- verify(mGoodGuyRunner2).run();
- verify(mGoodGuyExtraExceptions1).call();
- verify(mDumper).dump("Whatever", actualException);
- }
-}
diff --git a/common/device-side/util/tests/src/com/android/compatibility/common/util/StateChangerRuleTest.java b/common/device-side/util/tests/src/com/android/compatibility/common/util/StateChangerRuleTest.java
deleted file mode 100644
index 9b1851e..0000000
--- a/common/device-side/util/tests/src/com/android/compatibility/common/util/StateChangerRuleTest.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
-
-import org.junit.Test;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
-import org.junit.runners.model.Statement;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-@RunWith(MockitoJUnitRunner.class)
-public class StateChangerRuleTest {
-
- private final RuntimeException mRuntimeException = new RuntimeException("D'OH");
- private final Description mDescription = Description.createSuiteDescription("Whatever");
-
- @Mock
- private StateManager<String> mStateManager;
-
- @Mock
- private Statement mStatement;
-
- @Test
- public void testInvalidConstructor() {
- assertThrows(NullPointerException.class,
- () -> new StateChangerRule<Object>(null, "value"));
- }
-
- @Test
- public void testSetAndRestoreOnSuccess() throws Throwable {
- final StateChangerRule<String> rule = new StateChangerRule<>(mStateManager,
- "newValue");
- when(mStateManager.get()).thenReturn("before", "changed");
-
- rule.apply(mStatement, mDescription).evaluate();
-
- verify(mStatement, times(1)).evaluate();
- verify(mStateManager, times(2)).get(); // Needed because of verifyNoMoreInteractions()
- verify(mStateManager, times(1)).set("newValue");
- verify(mStateManager, times(1)).set("before");
- verifyNoMoreInteractions(mStateManager); // Make sure set() was not called again
- }
-
- @Test
- public void testDontSetIfSameValueOnSuccess() throws Throwable {
- final StateChangerRule<String> rule = new StateChangerRule<>(mStateManager,
- "sameValue");
- when(mStateManager.get()).thenReturn("sameValue");
-
- rule.apply(mStatement, mDescription).evaluate();
-
- verify(mStatement, times(1)).evaluate();
- verify(mStateManager, never()).set(anyString());
- }
-
- @Test
- public void testSetButDontRestoreIfSameValueOnSuccess() throws Throwable {
- final StateChangerRule<String> rule = new StateChangerRule<>(mStateManager,
- "newValue");
- when(mStateManager.get()).thenReturn("before", "before");
-
- rule.apply(mStatement, mDescription).evaluate();
-
- verify(mStatement, times(1)).evaluate();
- verify(mStateManager, times(2)).get(); // Needed because of verifyNoMoreInteractions()
- verify(mStateManager, times(1)).set("newValue");
- verifyNoMoreInteractions(mStateManager); // Make sure set() was not called again
- }
-
- @Test
- public void testDontSetButRestoreIfValueChangedOnSuccess() throws Throwable {
- final StateChangerRule<String> rule = new StateChangerRule<>(mStateManager,
- "sameValue");
- when(mStateManager.get()).thenReturn("sameValue", "changed");
-
- rule.apply(mStatement, mDescription).evaluate();
-
- verify(mStateManager, times(2)).get(); // Needed because of verifyNoMoreInteractions()
- verify(mStatement, times(1)).evaluate();
- verify(mStateManager, times(1)).set("sameValue");
- verifyNoMoreInteractions(mStateManager); // Make sure set() was not called again
- }
-
- @Test
- public void testSetAndRestoreOnFailure() throws Throwable {
- final StateChangerRule<String> rule = new StateChangerRule<>(mStateManager,
- "newValue");
- when(mStateManager.get()).thenReturn("before", "changed");
- doThrow(mRuntimeException).when(mStatement).evaluate();
-
- final RuntimeException actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(mStatement, mDescription).evaluate());
- assertThat(actualException).isSameAs(mRuntimeException);
-
- verify(mStateManager, times(2)).get(); // Needed because of verifyNoMoreInteractions()
- verify(mStateManager, times(1)).set("newValue");
- verify(mStateManager, times(1)).set("before");
- verifyNoMoreInteractions(mStateManager); // Make sure set() was not called again
- }
-
- @Test
- public void testDontSetIfSameValueOnFailure() throws Throwable {
- final StateChangerRule<String> rule = new StateChangerRule<>(mStateManager,
- "sameValue");
- when(mStateManager.get()).thenReturn("sameValue");
- doThrow(mRuntimeException).when(mStatement).evaluate();
-
- final RuntimeException actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(mStatement, mDescription).evaluate());
- assertThat(actualException).isSameAs(mRuntimeException);
-
- verify(mStateManager, never()).set(anyString());
- }
-
- @Test
- public void testSetButDontRestoreIfSameValueOnFailure() throws Throwable {
- final StateChangerRule<String> rule = new StateChangerRule<>(mStateManager,
- "newValue");
- when(mStateManager.get()).thenReturn("before", "before");
- doThrow(mRuntimeException).when(mStatement).evaluate();
-
- final RuntimeException actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(mStatement, mDescription).evaluate());
- assertThat(actualException).isSameAs(mRuntimeException);
-
- verify(mStateManager, times(2)).get(); // Needed because of verifyNoMoreInteractions()
- verify(mStateManager, times(1)).set("newValue");
- verifyNoMoreInteractions(mStateManager); // Make sure set() was not called again
- }
-
- @Test
- public void testDontSetButRestoreIfValueChangedOnFailure() throws Throwable {
- final StateChangerRule<String> rule = new StateChangerRule<>(mStateManager,
- "sameValue");
- when(mStateManager.get()).thenReturn("sameValue", "changed");
- doThrow(mRuntimeException).when(mStatement).evaluate();
-
- final RuntimeException actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(mStatement, mDescription).evaluate());
- assertThat(actualException).isSameAs(mRuntimeException);
-
- verify(mStateManager, times(2)).get(); // Needed because of verifyNoMoreInteractions()
- verify(mStateManager, times(1)).set("sameValue");
- verifyNoMoreInteractions(mStateManager); // Make sure set() was not called again
- }
-}
diff --git a/common/device-side/util/tests/src/com/android/compatibility/common/util/StateKeeperRuleTest.java b/common/device-side/util/tests/src/com/android/compatibility/common/util/StateKeeperRuleTest.java
deleted file mode 100644
index 4599aca..0000000
--- a/common/device-side/util/tests/src/com/android/compatibility/common/util/StateKeeperRuleTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
-
-import org.junit.Test;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
-import org.junit.runners.model.Statement;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-@RunWith(MockitoJUnitRunner.class)
-public class StateKeeperRuleTest {
-
- private final RuntimeException mRuntimeException = new RuntimeException("D'OH");
- private final Description mDescription = Description.createSuiteDescription("Whatever");
-
- @Mock
- private StateManager<String> mStateManager;
-
- @Mock
- private Statement mStatement;
-
- @Test
- public void testInvalidConstructor() {
- assertThrows(NullPointerException.class, () -> new StateKeeperRule<Object>(null));
- }
-
- @Test
- public void testRestoreOnSuccess() throws Throwable {
- final StateKeeperRule<String> rule = new StateKeeperRule<>(mStateManager);
- when(mStateManager.get()).thenReturn("before", "changed");
-
- rule.apply(mStatement, mDescription).evaluate();
-
- verify(mStatement, times(1)).evaluate();
- verify(mStateManager, times(2)).get(); // Needed because of verifyNoMoreInteractions()
- verify(mStateManager, times(1)).set("before");
- verifyNoMoreInteractions(mStateManager); // Make sure set() was not called again
- }
-
- @Test
- public void testRestoreOnFailure() throws Throwable {
- final StateKeeperRule<String> rule = new StateKeeperRule<>(mStateManager);
- when(mStateManager.get()).thenReturn("before", "changed");
- doThrow(mRuntimeException).when(mStatement).evaluate();
-
- final RuntimeException actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(mStatement, mDescription).evaluate());
-
- assertThat(actualException).isSameAs(mRuntimeException);
- verify(mStateManager, times(2)).get(); // Needed because of verifyNoMoreInteractions()
- verify(mStateManager, times(1)).set("before");
- verifyNoMoreInteractions(mStateManager); // Make sure set() was not called again
- }
-
- @Test
- public void testDoNotRestoreWhenNotChanged() throws Throwable {
- final StateKeeperRule<String> rule = new StateKeeperRule<>(mStateManager);
- when(mStateManager.get()).thenReturn("not_changed");
-
- rule.apply(mStatement, mDescription).evaluate();
-
- verify(mStatement, times(1)).evaluate();
- verify(mStateManager, never()).set(anyString());
- }
-
- @Test
- public void testDoNotRestoreOnFailure() throws Throwable {
- final StateKeeperRule<String> rule = new StateKeeperRule<>(mStateManager);
- when(mStateManager.get()).thenReturn("not_changed");
- doThrow(mRuntimeException).when(mStatement).evaluate();
-
- final RuntimeException actualException = expectThrows(RuntimeException.class,
- () -> rule.apply(mStatement, mDescription).evaluate());
-
- assertThat(actualException).isSameAs(mRuntimeException);
-
- verify(mStateManager, never()).set(anyString());
- }
-}
diff --git a/common/device-side/util/tests/src/com/android/compatibility/common/util/TimeoutTest.java b/common/device-side/util/tests/src/com/android/compatibility/common/util/TimeoutTest.java
deleted file mode 100644
index 8992d18..0000000
--- a/common/device-side/util/tests/src/com/android/compatibility/common/util/TimeoutTest.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
-
-import android.os.SystemClock;
-
-import com.android.compatibility.common.util.Timeout.Sleeper;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-import java.util.concurrent.Callable;
-
-@RunWith(MockitoJUnitRunner.class)
-public class TimeoutTest {
-
- private static final String NAME = "TIME, Y U NO OUT?";
- private static final String DESC = "something";
-
- @Mock
- private Callable<Object> mJob;
-
- private final MySleeper mSleeper = new MySleeper();
-
- @Test
- public void testInvalidConstructor() {
- // Invalid name
- assertThrows(IllegalArgumentException.class, ()-> new Timeout(null, 1, 2, 2));
- assertThrows(IllegalArgumentException.class, ()-> new Timeout("", 1, 2, 2));
- // Invalid initial value
- assertThrows(IllegalArgumentException.class, ()-> new Timeout(NAME, -1, 2, 2));
- assertThrows(IllegalArgumentException.class, ()-> new Timeout(NAME, 0, 2, 2));
- // Invalid multiplier
- assertThrows(IllegalArgumentException.class, ()-> new Timeout(NAME, 1, -1, 2));
- assertThrows(IllegalArgumentException.class, ()-> new Timeout(NAME, 1, 0, 2));
- assertThrows(IllegalArgumentException.class, ()-> new Timeout(NAME, 1, 1, 2));
- // Invalid max value
- assertThrows(IllegalArgumentException.class, ()-> new Timeout(NAME, 1, 2, -1));
- assertThrows(IllegalArgumentException.class, ()-> new Timeout(NAME, 1, 2, 0));
- // Max value cannot be less than initial
- assertThrows(IllegalArgumentException.class, ()-> new Timeout(NAME, 2, 2, 1));
- }
-
- @Test
- public void testGetters() {
- final Timeout timeout = new Timeout(NAME, 1, 2, 5);
- assertThat(timeout.ms()).isEqualTo(1);
- assertFloat(timeout.getMultiplier(), 2);
- assertThat(timeout.getMaxValue()).isEqualTo(5);
- assertThat(timeout.getName()).isEqualTo(NAME);
- }
-
- @Test
- public void testIncrease() {
- final Timeout timeout = new Timeout(NAME, 1, 2, 5);
- // Pre-maximum
- assertThat(timeout.increase()).isEqualTo(1);
- assertThat(timeout.ms()).isEqualTo(2);
- assertThat(timeout.increase()).isEqualTo(2);
- assertThat(timeout.ms()).isEqualTo(4);
- // Post-maximum
- assertThat(timeout.increase()).isEqualTo(4);
- assertThat(timeout.ms()).isEqualTo(5);
- assertThat(timeout.increase()).isEqualTo(5);
- assertThat(timeout.ms()).isEqualTo(5);
- }
-
- @Test
- public void testRun_invalidArgs() {
- final Timeout timeout = new Timeout(NAME, 1, 2, 5);
- // Invalid description
- assertThrows(IllegalArgumentException.class, ()-> timeout.run(null, mJob));
- assertThrows(IllegalArgumentException.class, ()-> timeout.run("", mJob));
- // Invalid max attempts
- assertThrows(IllegalArgumentException.class, ()-> timeout.run(DESC, -1, mJob));
- assertThrows(IllegalArgumentException.class, ()-> timeout.run(DESC, 0, mJob));
- // Invalid job
- assertThrows(IllegalArgumentException.class, ()-> timeout.run(DESC, null));
- }
-
- @Test
- public void testRun_successOnFirstAttempt() throws Exception {
- final Timeout timeout = new Timeout(mSleeper, NAME, 100, 2, 500);
- final Object result = new Object();
- when(mJob.call()).thenReturn(result);
- assertThat(timeout.run(DESC, 1, mJob)).isSameAs(result);
- assertThat(mSleeper.totalSleepingTime).isEqualTo(0);
- }
-
- @Test
- public void testRun_successOnSecondAttempt() throws Exception {
- final Timeout timeout = new Timeout(mSleeper, NAME, 100, 2, 500);
- final Object result = new Object();
- when(mJob.call()).thenReturn((Object) null, result);
- assertThat(timeout.run(DESC, 10, mJob)).isSameAs(result);
- assertThat(mSleeper.totalSleepingTime).isEqualTo(10);
- }
-
- @Test
- public void testRun_allAttemptsFailed() throws Exception {
- final Timeout timeout = new Timeout(mSleeper, NAME, 100, 2, 500);
- final RetryableException e = expectThrows(RetryableException.class,
- () -> timeout.run(DESC, 10, mJob));
- assertThat(e.getMessage()).contains(DESC);
- assertThat(e.getTimeout()).isSameAs(timeout);
- assertThat(mSleeper.totalSleepingTime).isEqualTo(100);
- }
-
- private static final class MySleeper implements Sleeper {
- public long totalSleepingTime;
-
- @Override
- public void sleep(long napTimeMs) {
- // We still need to sleep, as the retry is based on ellapsed time. We could use a
- // Mockito spy, but let's keep it simple
- SystemClock.sleep(napTimeMs);
- totalSleepingTime += napTimeMs;
- }
- }
-
- public static void assertFloat(float actualValue, float expectedValue) {
- assertThat(actualValue).isWithin(1.0e-10f).of(expectedValue);
- }
-}
diff --git a/hostsidetests/appbinding/hostside/OWNERS b/hostsidetests/appbinding/hostside/OWNERS
new file mode 100644
index 0000000..77d350b
--- /dev/null
+++ b/hostsidetests/appbinding/hostside/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 533114
+omakoto@google.com
+yamasani@google.com
diff --git a/hostsidetests/appsecurity/OWNERS b/hostsidetests/appsecurity/OWNERS
index f86fd96..ea12403 100644
--- a/hostsidetests/appsecurity/OWNERS
+++ b/hostsidetests/appsecurity/OWNERS
@@ -25,8 +25,10 @@
per-file PermissionsHostTest.java = moltmann@google.com
per-file PkgInstallSignatureVerificationTest.java = cbrubaker@google.com
per-file PrivilegedUpdateTests.java = toddke@google.com
+per-file ReviewPermissionHelper = moltmann@google.com
+per-file RequestsOnlyCalendarApp22.java = moltmann@google.com
per-file ScopedDirectoryAccessTest.java = jsharkey@google.com
per-file SplitTests.java = toddke@google.com
per-file StorageHostTest.java = jsharkey@google.com
per-file UseEmbeddedDexTest.java = victorhsieh@google.com
-per-file UsePermission*.java = moltmann@google.com
+per-file UsePermission*.java = moltmann@google.com
\ No newline at end of file
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppOpsTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppOpsTest.java
deleted file mode 100644
index 5c53f20..0000000
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppOpsTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.appsecurity.cts;
-
-import android.platform.test.annotations.AppModeFull;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test for app ops behaviors.
- */
-@RunWith(DeviceJUnit4ClassRunner.class)
-@AppModeFull(reason = "No instant specific behaviors")
-public final class AppOpsTest extends BaseHostJUnit4Test {
-
- @Test
- public void testBadConfigCannotCauseBootLoop() throws Exception {
- setAppOpHistoryParameters("mode=HISTORICAL_MODE_ENABLED_ACTIVE,baseIntervalMillis=1000"
- + ",intervalMultiplier=10");
- try {
- createBadHistoricalFile();
- getDevice().reboot();
- } finally {
- deleteHistoricalFiles();
- setAppOpHistoryParameters(null);
- }
- }
-
- private void setAppOpHistoryParameters(String value) throws Exception {
- getDevice().executeShellCommand("settings put global appop_history_parameters " + value);
- }
-
- private void createBadHistoricalFile() throws Exception {
- getDevice().executeShellCommand("touch data/system/appops/history/1000.xml");
- }
-
- private void deleteHistoricalFiles() throws Exception {
- getDevice().executeShellCommand("rm -rf data/system/appops/history");
- }
-}
diff --git a/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/OWNERS b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/OWNERS
new file mode 100644
index 0000000..8075c9c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/OWNERS
@@ -0,0 +1,2 @@
+moltmann@google.com
+eugenesusla@google.com
diff --git a/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/OWNERS b/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/OWNERS
new file mode 100644
index 0000000..8075c9c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/OWNERS
@@ -0,0 +1,2 @@
+moltmann@google.com
+eugenesusla@google.com
diff --git a/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/OWNERS b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/OWNERS
new file mode 100644
index 0000000..8075c9c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/OWNERS
@@ -0,0 +1,2 @@
+moltmann@google.com
+eugenesusla@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/OWNERS b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/OWNERS
new file mode 100644
index 0000000..8075c9c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/OWNERS
@@ -0,0 +1,2 @@
+moltmann@google.com
+eugenesusla@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/OWNERS b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/OWNERS
new file mode 100644
index 0000000..8075c9c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/OWNERS
@@ -0,0 +1,2 @@
+moltmann@google.com
+eugenesusla@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PermissionPolicy25/OWNERS b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/OWNERS
new file mode 100644
index 0000000..8075c9c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/OWNERS
@@ -0,0 +1,2 @@
+moltmann@google.com
+eugenesusla@google.com
diff --git a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/AndroidManifest.xml
index 7b254dc..30d73f5 100644
--- a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/AndroidManifest.xml
@@ -19,7 +19,7 @@
package="com.android.cts.reviewpermissionhelper">
<application>
- <activity android:name=".ActivityStarter" />
+ <activity android:name="com.android.compatibility.common.util.FutureResultActivity" />
<uses-library android:name="android.test.runner" />
</application>
diff --git a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/OWNERS b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/OWNERS
new file mode 100644
index 0000000..8075c9c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/OWNERS
@@ -0,0 +1,2 @@
+moltmann@google.com
+eugenesusla@google.com
diff --git a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/src/com/android/cts/reviewpermissionhelper/ActivityStarter.kt b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/src/com/android/cts/reviewpermissionhelper/ActivityStarter.kt
deleted file mode 100644
index 90dbca9..0000000
--- a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/src/com/android/cts/reviewpermissionhelper/ActivityStarter.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2018 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.cts.reviewpermissionhelper
-
-import android.app.Activity
-import android.content.Intent
-import android.os.Bundle
-import java.util.concurrent.LinkedBlockingQueue
-
-val installDialogResults = LinkedBlockingQueue<Int>()
-
-class ActivityStarter : Activity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- savedInstanceState ?: installDialogResults.clear()
- }
-
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- installDialogResults.offer(resultCode)
- }
-}
diff --git a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/src/com/android/cts/reviewpermissionhelper/ReviewPermissionsTest.kt b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/src/com/android/cts/reviewpermissionhelper/ReviewPermissionsTest.kt
index 15fdff3..b07a4bb 100644
--- a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/src/com/android/cts/reviewpermissionhelper/ReviewPermissionsTest.kt
+++ b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/src/com/android/cts/reviewpermissionhelper/ReviewPermissionsTest.kt
@@ -32,11 +32,13 @@
import android.support.test.uiautomator.By
import android.support.test.uiautomator.UiDevice
import android.support.test.uiautomator.Until
+import com.android.compatibility.common.util.FutureResultActivity
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import java.util.concurrent.CompletableFuture
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit
@@ -47,16 +49,22 @@
@RunWith(AndroidJUnit4::class)
class ReviewPermissionsTest {
@get:Rule
- val activityStarter = ActivityTestRule(ActivityStarter::class.java)
+ val activityStarter = ActivityTestRule(FutureResultActivity::class.java)
val instrumentation = InstrumentationRegistry.getInstrumentation()
val uiDevice = UiDevice.getInstance(instrumentation)
- fun startActivityInReviewedAp() {
+ fun startActivityInReviewedAp(): CompletableFuture<Int> {
val startAutoClosingActivity = Intent()
startAutoClosingActivity.component = ComponentName(USE_PERMISSION_PKG,
USE_PERMISSION_PKG + ".AutoClosingActivity")
- activityStarter.activity.startActivityForResult(startAutoClosingActivity, 42)
+ return activityStarter.activity.startActivityForResult(startAutoClosingActivity)
+ }
+
+ private inline fun startActivityInReviewedAp(expectedResult: Int, runAfterStart: () -> Unit) {
+ val activityResult = startActivityInReviewedAp()
+ runAfterStart()
+ assertEquals(expectedResult, activityResult.get(UI_TIMEOUT, TimeUnit.MILLISECONDS))
}
fun clickContinue() {
@@ -66,24 +74,23 @@
@Test
fun approveReviewPermissions() {
- startActivityInReviewedAp()
- clickContinue()
- assertEquals(RESULT_OK, installDialogResults.poll(UI_TIMEOUT, TimeUnit.MILLISECONDS))
+ startActivityInReviewedAp(expectedResult = RESULT_OK) {
+ clickContinue()
+ }
}
@Test
fun cancelReviewPermissions() {
- startActivityInReviewedAp()
-
- uiDevice.wait(Until.findObject(
- By.res("com.android.permissioncontroller:id/cancel_button")), UI_TIMEOUT).click()
- assertEquals(RESULT_CANCELED, installDialogResults.poll(UI_TIMEOUT, TimeUnit.MILLISECONDS))
+ startActivityInReviewedAp(expectedResult = RESULT_CANCELED) {
+ uiDevice.wait(Until.findObject(
+ By.res("com.android.permissioncontroller:id/cancel_button")), UI_TIMEOUT)
+ .click()
+ }
}
@Test
fun assertNoReviewPermissionsNeeded() {
- startActivityInReviewedAp()
- assertEquals(RESULT_OK, installDialogResults.poll(UI_TIMEOUT, TimeUnit.MILLISECONDS))
+ startActivityInReviewedAp(expectedResult = RESULT_OK) {}
}
@Test
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/OWNERS
new file mode 100644
index 0000000..8075c9c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/OWNERS
@@ -0,0 +1,2 @@
+moltmann@google.com
+eugenesusla@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/src/com/android/cts/usepermission/UsePermissionTest22.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/src/com/android/cts/usepermission/UsePermissionTest22.java
index 20be2cc..a1bd122 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/src/com/android/cts/usepermission/UsePermissionTest22.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/src/com/android/cts/usepermission/UsePermissionTest22.java
@@ -36,7 +36,6 @@
* Runtime permission behavior tests for apps targeting API 22
*/
public class UsePermissionTest22 extends BasePermissionsTest {
- private static final int REQUEST_CODE_PERMISSIONS = 42;
private final Context mContext = getInstrumentation().getContext();
@@ -137,11 +136,9 @@
public void testNoRuntimePrompt() throws Exception {
// Request the permission and do nothing
BasePermissionActivity.Result result = requestPermissions(
- new String[] {Manifest.permission.SEND_SMS}, REQUEST_CODE_PERMISSIONS,
- BasePermissionActivity.class, null);
+ new String[]{Manifest.permission.SEND_SMS}, null);
// Expect the permission is not granted
- assertEquals(REQUEST_CODE_PERMISSIONS, result.requestCode);
assertTrue(Arrays.equals(result.permissions, new String[0]));
assertTrue(Arrays.equals(result.grantResults, new int[0]));
}
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/OWNERS
new file mode 100644
index 0000000..8075c9c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/OWNERS
@@ -0,0 +1,2 @@
+moltmann@google.com
+eugenesusla@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionActivity.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionActivity.java
index cacfa80..48dafef 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionActivity.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionActivity.java
@@ -20,23 +20,33 @@
import android.os.Bundle;
import android.view.WindowManager;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
public class BasePermissionActivity extends Activity {
private static final long OPERATION_TIMEOUT_MILLIS = 5000;
- private final SynchronousQueue<Result> mResult = new SynchronousQueue<>();
+ /**
+ * Static to ensure correct behavior if {@link Activity} instance was recreated before
+ * result delivery.
+ *
+ * requestCode -> Future<Result>
+ */
+ private static Map<Integer, CompletableFuture<Result>> sPendingResults =
+ new ConcurrentHashMap<>();
+ private static AtomicInteger sNextRequestCode = new AtomicInteger(0);
+
private final CountDownLatch mOnCreateSync = new CountDownLatch(1);
public static class Result {
- public final int requestCode;
public final String[] permissions;
public final int[] grantResults;
- public Result(int requestCode, String[] permissions, int[] grantResults) {
- this.requestCode = requestCode;
+ public Result(String[] permissions, int[] grantResults) {
this.permissions = permissions;
this.grantResults = grantResults;
}
@@ -53,14 +63,18 @@
mOnCreateSync.countDown();
}
+ public CompletableFuture<Result> requestPermissions(String[] permissions) {
+ int requestCode = sNextRequestCode.getAndIncrement();
+ CompletableFuture<Result> future = new CompletableFuture<>();
+ sPendingResults.put(requestCode, future);
+ requestPermissions(permissions, requestCode);
+ return future;
+ }
+
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
- try {
- mResult.offer(new Result(requestCode, permissions, grantResults), 5, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
+ sPendingResults.get(requestCode).complete(new Result(permissions, grantResults));
}
public void waitForOnCreate() {
@@ -70,12 +84,4 @@
throw new RuntimeException(e);
}
}
-
- public Result getResult() {
- try {
- return mResult.poll(OPERATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
}
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
index 2723a6d..6f2efd1 100755
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
@@ -21,6 +21,9 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
import android.Manifest;
import android.app.Activity;
import android.app.Instrumentation;
@@ -51,6 +54,10 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.ExceptionUtils;
+import com.android.compatibility.common.util.ThrowingRunnable;
+import com.android.compatibility.common.util.UiDumpUtils;
+
import junit.framework.Assert;
import org.junit.Before;
@@ -59,6 +66,8 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.regex.Pattern;
@@ -83,11 +92,11 @@
}
protected static void assertPermissionRequestResult(BasePermissionActivity.Result result,
- int requestCode, String[] permissions, boolean[] granted) {
- assertEquals(requestCode, result.requestCode);
+ String[] permissions, boolean[] granted) {
for (int i = 0; i < permissions.length; i++) {
assertEquals(permissions[i], result.permissions[i]);
- assertEquals(granted[i] ? PackageManager.PERMISSION_GRANTED
+ assertEquals(granted[i]
+ ? PackageManager.PERMISSION_GRANTED
: PackageManager.PERMISSION_DENIED, result.grantResults[i]);
}
@@ -269,74 +278,71 @@
}
protected BasePermissionActivity.Result requestPermissions(
- String[] permissions, int requestCode, Class<?> clazz, Runnable postRequestAction)
+ String[] permissions, ThrowingRunnable postRequestAction)
throws Exception {
- // Start an activity
- BasePermissionActivity activity = (BasePermissionActivity) launchActivity(
- getInstrumentation().getTargetContext().getPackageName(), clazz, null);
+ return ExceptionUtils.wrappingExceptions(UiDumpUtils::wrapWithUiDump, () -> {
+ // Start an activity
+ BasePermissionActivity activity = (BasePermissionActivity) launchActivity(
+ getInstrumentation().getTargetContext().getPackageName(),
+ BasePermissionActivity.class, null);
- activity.waitForOnCreate();
+ activity.waitForOnCreate();
- // Request the permissions
- activity.requestPermissions(permissions, requestCode);
+ // Request the permissions
+ CompletableFuture<BasePermissionActivity.Result> futureResult =
+ activity.requestPermissions(permissions);
- // Define a more conservative idle criteria
- getInstrumentation().getUiAutomation().waitForIdle(
- IDLE_TIMEOUT_MILLIS, GLOBAL_TIMEOUT_MILLIS);
+ // Define a more conservative idle criteria
+ getInstrumentation().getUiAutomation().waitForIdle(
+ IDLE_TIMEOUT_MILLIS, GLOBAL_TIMEOUT_MILLIS);
- // Perform the post-request action
- if (postRequestAction != null) {
- postRequestAction.run();
- }
+ // Perform the post-request action
+ if (postRequestAction != null) {
+ postRequestAction.run();
+ }
- BasePermissionActivity.Result result = activity.getResult();
- activity.finish();
- return result;
+ BasePermissionActivity.Result result =
+ futureResult.get(GLOBAL_TIMEOUT_MILLIS, MILLISECONDS);
+ activity.finish();
+ return result;
+ });
}
protected void clickAllowButton() throws Exception {
- scrollToBottomIfWatch();
- waitForIdle();
- getUiDevice().wait(Until.findObject(By.res(
- "com.android.permissioncontroller:id/permission_allow_button")),
- GLOBAL_TIMEOUT_MILLIS).click();
+ scrollToBottom();
+ click("com.android.permissioncontroller:id/permission_allow_button");
}
protected void clickAllowAlwaysButton() throws Exception {
- waitForIdle();
- getUiDevice().wait(Until.findObject(By.res(
- "com.android.permissioncontroller:id/permission_allow_always_button")),
- GLOBAL_TIMEOUT_MILLIS).click();
+ click("com.android.permissioncontroller:id/permission_allow_always_button");
}
protected void clickAllowForegroundButton() throws Exception {
- waitForIdle();
- getUiDevice().wait(Until.findObject(By.res(
- "com.android.permissioncontroller:id/permission_allow_foreground_only_button")),
- GLOBAL_TIMEOUT_MILLIS).click();
+ click("com.android.permissioncontroller:id/permission_allow_foreground_only_button");
}
protected void clickDenyButton() throws Exception {
- scrollToBottomIfWatch();
- waitForIdle();
- getUiDevice().wait(Until.findObject(By.res(
- "com.android.permissioncontroller:id/permission_deny_button")),
- GLOBAL_TIMEOUT_MILLIS).click();
+ scrollToBottom();
+ click("com.android.permissioncontroller:id/permission_deny_button");
}
protected void clickDenyAndDontAskAgainButton() throws Exception {
- waitForIdle();
- getUiDevice().wait(Until.findObject(By.res(
- "com.android.permissioncontroller:id/permission_deny_and_dont_ask_again_button")),
- GLOBAL_TIMEOUT_MILLIS).click();
+ scrollToBottom();
+ click("com.android.permissioncontroller:id/permission_deny_and_dont_ask_again_button");
}
protected void clickDontAskAgainButton() throws Exception {
- scrollToBottomIfWatch();
- waitForIdle();
- getUiDevice().wait(Until.findObject(By.res(
- "com.android.permissioncontroller:id/permission_deny_dont_ask_again_button")),
- GLOBAL_TIMEOUT_MILLIS).click();
+ scrollToBottom();
+ click("com.android.permissioncontroller:id/permission_deny_dont_ask_again_button");
+ }
+
+ private void click(String resourceName) throws TimeoutException {
+ ExceptionUtils.wrappingExceptions(UiDumpUtils::wrapWithUiDump, () -> {
+ waitForIdle();
+ getUiDevice().wait(Until.findObject(By.res(
+ resourceName)),
+ GLOBAL_TIMEOUT_MILLIS).click();
+ });
}
protected void grantPermission(String permission) throws Exception {
@@ -355,114 +361,115 @@
setPermissionGrantState(permissions, false, legacyApp);
}
- private void scrollToBottomIfWatch() throws Exception {
- if (mWatch) {
- getUiDevice().wait(Until.findObject(By.clazz(ScrollView.class)), GLOBAL_TIMEOUT_MILLIS);
- UiScrollable scrollable =
- new UiScrollable(new UiSelector().className(ScrollView.class));
- if (scrollable.exists()) {
- scrollable.flingToEnd(10);
- }
+ private void scrollToBottom() throws Exception {
+ getUiDevice().wait(Until.findObject(By.clazz(ScrollView.class)), GLOBAL_TIMEOUT_MILLIS);
+ UiScrollable scrollable =
+ new UiScrollable(new UiSelector().className(ScrollView.class));
+ if (scrollable.exists()) {
+ scrollable.flingToEnd(10);
}
}
private void setPermissionGrantState(String[] permissions, boolean granted,
boolean legacyApp) throws Exception {
- getUiDevice().pressBack();
- waitForIdle();
- getUiDevice().pressBack();
- waitForIdle();
- getUiDevice().pressBack();
- waitForIdle();
-
- if (isTv()) {
- getUiDevice().pressHome();
+ ExceptionUtils.wrappingExceptions(UiDumpUtils::wrapWithUiDump, () -> {
+ getUiDevice().pressBack();
waitForIdle();
- }
+ getUiDevice().pressBack();
+ waitForIdle();
+ getUiDevice().pressBack();
+ waitForIdle();
- // Open the app details settings
- Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setData(Uri.parse("package:" + mContext.getPackageName()));
- startActivity(intent);
-
- waitForIdle();
-
- // Open the permissions UI
- String label = mContext.getResources().getString(R.string.Permissions);
- AccessibilityNodeInfo permLabelView = getNodeTimed(() -> findByText(label), true);
- Assert.assertNotNull("Permissions label should be present", permLabelView);
-
- AccessibilityNodeInfo permItemView = findCollectionItem(permLabelView);
-
- click(permItemView);
-
- waitForIdle();
-
- for (String permission : permissions) {
- // Find the permission screen
- String permissionLabel = getPermissionLabel(permission);
-
- UiObject2 permissionView = null;
- long start = System.currentTimeMillis();
- while (permissionView == null && start + RETRY_TIMEOUT > System.currentTimeMillis()) {
- permissionView = getUiDevice().wait(Until.findObject(By.text(permissionLabel)),
- GLOBAL_TIMEOUT_MILLIS);
-
- if (permissionView == null) {
- getUiDevice().findObject(By.res("android:id/list_container"))
- .scroll(Direction.DOWN, 1);
- }
+ if (isTv()) {
+ getUiDevice().pressHome();
+ waitForIdle();
}
- permissionView.click();
+ // Open the app details settings
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setData(Uri.parse("package:" + mContext.getPackageName()));
+ startActivity(intent);
+
waitForIdle();
- String denyLabel = mContext.getResources().getString(R.string.Deny);
+ // Open the permissions UI
+ String label = mContext.getResources().getString(R.string.Permissions);
+ AccessibilityNodeInfo permLabelView = getNodeTimed(() -> findByText(label), true);
+ Assert.assertNotNull("Permissions label should be present", permLabelView);
- final boolean wasGranted = !getUiDevice().wait(Until.findObject(By.text(denyLabel)),
- GLOBAL_TIMEOUT_MILLIS).isChecked();
- if (granted != wasGranted) {
- // Toggle the permission
+ AccessibilityNodeInfo permItemView = findCollectionItem(permLabelView);
- if (granted) {
- String allowLabel = mContext.getResources().getString(R.string.Allow);
- getUiDevice().findObject(By.text(allowLabel)).click();
- } else {
- getUiDevice().findObject(By.text(denyLabel)).click();
+ click(permItemView);
+
+ waitForIdle();
+
+ for (String permission : permissions) {
+ // Find the permission screen
+ String permissionLabel = getPermissionLabel(permission);
+
+ UiObject2 permissionView = null;
+ long start = System.currentTimeMillis();
+ while (permissionView == null
+ && start + RETRY_TIMEOUT > System.currentTimeMillis()) {
+ permissionView = getUiDevice().wait(Until.findObject(By.text(permissionLabel)),
+ GLOBAL_TIMEOUT_MILLIS);
+
+ if (permissionView == null) {
+ getUiDevice().findObject(By.res("android:id/list_container"))
+ .scroll(Direction.DOWN, 1);
+ }
}
+
+ permissionView.click();
waitForIdle();
- if (wasGranted && legacyApp) {
- scrollToBottomIfWatch();
- Context context = getInstrumentation().getContext();
- String packageName = context.getPackageManager()
- .getPermissionControllerPackageName();
- String resIdName = "com.android.permissioncontroller"
- + ":string/grant_dialog_button_deny_anyway";
- Resources resources = context
- .createPackageContext(packageName, 0).getResources();
- final int confirmResId = resources.getIdentifier(resIdName, null, null);
- String confirmTitle = CaseMap.toUpper().apply(
- resources.getConfiguration().getLocales().get(0),
- resources.getString(confirmResId));
- getUiDevice().wait(Until.findObject(
- byTextStartsWithCaseInsensitive(confirmTitle)),
- GLOBAL_TIMEOUT_MILLIS).click();
+ String denyLabel = mContext.getResources().getString(R.string.Deny);
+ final boolean wasGranted = !getUiDevice().wait(Until.findObject(By.text(denyLabel)),
+ GLOBAL_TIMEOUT_MILLIS).isChecked();
+ if (granted != wasGranted) {
+ // Toggle the permission
+
+ if (granted) {
+ String allowLabel = mContext.getResources().getString(R.string.Allow);
+ getUiDevice().findObject(By.text(allowLabel)).click();
+ } else {
+ getUiDevice().findObject(By.text(denyLabel)).click();
+ }
waitForIdle();
+
+ if (wasGranted && legacyApp) {
+ scrollToBottom();
+ Context context = getInstrumentation().getContext();
+ String packageName = context.getPackageManager()
+ .getPermissionControllerPackageName();
+ String resIdName = "com.android.permissioncontroller"
+ + ":string/grant_dialog_button_deny_anyway";
+ Resources resources = context
+ .createPackageContext(packageName, 0).getResources();
+ final int confirmResId = resources.getIdentifier(resIdName, null, null);
+ String confirmTitle = CaseMap.toUpper().apply(
+ resources.getConfiguration().getLocales().get(0),
+ resources.getString(confirmResId));
+ getUiDevice().wait(Until.findObject(
+ byTextStartsWithCaseInsensitive(confirmTitle)),
+ GLOBAL_TIMEOUT_MILLIS).click();
+
+ waitForIdle();
+ }
}
+
+ getUiDevice().pressBack();
+ waitForIdle();
}
getUiDevice().pressBack();
waitForIdle();
- }
-
- getUiDevice().pressBack();
- waitForIdle();
- getUiDevice().pressBack();
- waitForIdle();
+ getUiDevice().pressBack();
+ waitForIdle();
+ });
}
private BySelector byTextStartsWithCaseInsensitive(String prefix) {
@@ -587,12 +594,14 @@
}
private static void click(AccessibilityNodeInfo node) throws Exception {
- getInstrumentation().getUiAutomation().executeAndWaitForEvent(
- () -> node.performAction(AccessibilityNodeInfo.ACTION_CLICK),
- (AccessibilityEvent event) -> event.getEventType()
- == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
- || event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED,
- GLOBAL_TIMEOUT_MILLIS);
+ ExceptionUtils.wrappingExceptions(UiDumpUtils::wrapWithUiDump, () -> {
+ getInstrumentation().getUiAutomation().executeAndWaitForEvent(
+ () -> node.performAction(AccessibilityNodeInfo.ACTION_CLICK),
+ (AccessibilityEvent event) -> event.getEventType()
+ == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
+ || event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED,
+ GLOBAL_TIMEOUT_MILLIS);
+ });
}
private static AccessibilityNodeInfo findCollectionItem(AccessibilityNodeInfo current)
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
index 9482df0..dc7ec3b 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
@@ -26,7 +26,6 @@
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
-import android.os.Build;
import android.provider.CalendarContract;
import androidx.test.InstrumentationRegistry;
@@ -41,7 +40,6 @@
* Runtime permission behavior tests for apps targeting API 23
*/
public class UsePermissionTest23 extends BasePermissionsTest {
- private static final int REQUEST_CODE_PERMISSIONS = 42;
private final Context mContext = getInstrumentation().getContext();
@@ -105,21 +103,13 @@
}
// Go through normal grant flow
- BasePermissionActivity.Result result = requestPermissions(new String[] {
+ BasePermissionActivity.Result result = requestPermissions(new String[]{
Manifest.permission.READ_CALENDAR,
- Manifest.permission.WRITE_CALENDAR},
- REQUEST_CODE_PERMISSIONS,
- BasePermissionActivity.class,
- () -> {
- try {
- clickAllowButton();
- getUiDevice().waitForIdle();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ Manifest.permission.WRITE_CALENDAR}, () -> {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ });
- assertEquals(REQUEST_CODE_PERMISSIONS, result.requestCode);
assertEquals(Manifest.permission.READ_CALENDAR, result.permissions[0]);
assertEquals(Manifest.permission.WRITE_CALENDAR, result.permissions[1]);
assertEquals(PackageManager.PERMISSION_GRANTED, result.grantResults[0]);
@@ -147,21 +137,13 @@
String[] permissions = new String[] {Manifest.permission.WRITE_CONTACTS};
// request only one permission from the 'contacts' permission group
- BasePermissionActivity.Result result = requestPermissions(permissions,
- REQUEST_CODE_PERMISSIONS,
- BasePermissionActivity.class,
- () -> {
- try {
- clickAllowButton();
- getUiDevice().waitForIdle();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ BasePermissionActivity.Result result = requestPermissions(permissions, () -> {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ });
// Expect the permission is granted
- assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
- permissions, new boolean[] {true});
+ assertPermissionRequestResult(result, permissions, new boolean[] {true});
// Make sure no undeclared as used permissions are granted
assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
@@ -181,21 +163,13 @@
// request only one permission from the 'SMS' permission group at runtime,
// but two from this group are <uses-permission> in the manifest
// request only one permission from the 'contacts' permission group
- BasePermissionActivity.Result result = requestPermissions(permissions,
- REQUEST_CODE_PERMISSIONS,
- BasePermissionActivity.class,
- () -> {
- try {
- clickAllowButton();
- getUiDevice().waitForIdle();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ BasePermissionActivity.Result result = requestPermissions(permissions, () -> {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ });
// Expect the permission is granted
- assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
- permissions, new boolean[] {true});
+ assertPermissionRequestResult(result, permissions, new boolean[] {true});
// We should now have been granted both of the permissions from this group.
assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
@@ -211,21 +185,13 @@
String[] permissions = new String[] {Manifest.permission.WRITE_CONTACTS};
// Request the permission and cancel the request
- BasePermissionActivity.Result result = requestPermissions(permissions,
- REQUEST_CODE_PERMISSIONS,
- BasePermissionActivity.class,
- () -> {
- try {
- clickDenyButton();
- getUiDevice().waitForIdle();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ BasePermissionActivity.Result result = requestPermissions(permissions, () -> {
+ clickDenyButton();
+ getUiDevice().waitForIdle();
+ });
// Expect the permission is not granted
- assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
- permissions, new boolean[] {false});
+ assertPermissionRequestResult(result, permissions, new boolean[] {false});
}
@Test
@@ -237,29 +203,20 @@
String[] permissions = new String[] {Manifest.permission.WRITE_CONTACTS};
// Request the permission and allow it
- BasePermissionActivity.Result firstResult = requestPermissions(permissions,
- REQUEST_CODE_PERMISSIONS,
- BasePermissionActivity.class, () -> {
- try {
- clickAllowButton();
- getUiDevice().waitForIdle();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ BasePermissionActivity.Result firstResult = requestPermissions(permissions, () -> {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ });
// Expect the permission is granted
- assertPermissionRequestResult(firstResult, REQUEST_CODE_PERMISSIONS,
- permissions, new boolean[] {true});
+ assertPermissionRequestResult(firstResult, permissions, new boolean[] {true});
// Request the permission and do nothing
- BasePermissionActivity.Result secondResult = requestPermissions(new String[] {
- Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_PERMISSIONS + 1,
- BasePermissionActivity.class, null);
+ BasePermissionActivity.Result secondResult = requestPermissions(new String[]{
+ Manifest.permission.WRITE_CONTACTS}, null);
// Expect the permission is granted
- assertPermissionRequestResult(secondResult, REQUEST_CODE_PERMISSIONS + 1,
- permissions, new boolean[] {true});
+ assertPermissionRequestResult(secondResult, permissions, new boolean[] {true});
}
@Test
@@ -271,45 +228,30 @@
String[] permissions = new String[] {Manifest.permission.WRITE_CONTACTS};
// Request the permission and deny it
- BasePermissionActivity.Result firstResult = requestPermissions(
- permissions, REQUEST_CODE_PERMISSIONS,
- BasePermissionActivity.class, () -> {
- try {
- clickDenyButton();
- getUiDevice().waitForIdle();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ BasePermissionActivity.Result firstResult = requestPermissions(permissions, () -> {
+ clickDenyButton();
+ getUiDevice().waitForIdle();
+ });
// Expect the permission is not granted
- assertPermissionRequestResult(firstResult, REQUEST_CODE_PERMISSIONS,
- permissions, new boolean[] {false});
+ assertPermissionRequestResult(firstResult, permissions, new boolean[] {false});
// Request the permission and choose don't ask again
- BasePermissionActivity.Result secondResult = requestPermissions(new String[] {
- Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_PERMISSIONS + 1,
- BasePermissionActivity.class, () -> {
- try {
- denyWithPrejudice();
- getUiDevice().waitForIdle();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ BasePermissionActivity.Result secondResult = requestPermissions(new String[]{
+ Manifest.permission.WRITE_CONTACTS}, () -> {
+ denyWithPrejudice();
+ getUiDevice().waitForIdle();
+ });
// Expect the permission is not granted
- assertPermissionRequestResult(secondResult, REQUEST_CODE_PERMISSIONS + 1,
- permissions, new boolean[] {false});
+ assertPermissionRequestResult(secondResult, permissions, new boolean[] {false});
// Request the permission and do nothing
- BasePermissionActivity.Result thirdResult = requestPermissions(new String[] {
- Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_PERMISSIONS + 2,
- BasePermissionActivity.class, null);
+ BasePermissionActivity.Result thirdResult = requestPermissions(new String[]{
+ Manifest.permission.WRITE_CONTACTS}, null);
// Expect the permission is not granted
- assertPermissionRequestResult(thirdResult, REQUEST_CODE_PERMISSIONS + 2,
- permissions, new boolean[] {false});
+ assertPermissionRequestResult(thirdResult, permissions, new boolean[] {false});
}
@Test
@@ -347,36 +289,23 @@
String[] permissions = new String[] {Manifest.permission.READ_CALENDAR};
// Request the permission and deny it
- BasePermissionActivity.Result firstResult = requestPermissions(
- permissions, REQUEST_CODE_PERMISSIONS,
- BasePermissionActivity.class, () -> {
- try {
- clickDenyButton();
- getUiDevice().waitForIdle();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ BasePermissionActivity.Result firstResult = requestPermissions(permissions, () -> {
+ clickDenyButton();
+ getUiDevice().waitForIdle();
+ });
// Expect the permission is not granted
- assertPermissionRequestResult(firstResult, REQUEST_CODE_PERMISSIONS,
- permissions, new boolean[] {false});
+ assertPermissionRequestResult(firstResult, permissions, new boolean[] {false});
// Request the permission and choose don't ask again
- BasePermissionActivity.Result secondResult = requestPermissions(new String[] {
- Manifest.permission.READ_CALENDAR}, REQUEST_CODE_PERMISSIONS + 1,
- BasePermissionActivity.class, () -> {
- try {
- denyWithPrejudice();
- getUiDevice().waitForIdle();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ BasePermissionActivity.Result secondResult = requestPermissions(new String[]{
+ Manifest.permission.READ_CALENDAR}, () -> {
+ denyWithPrejudice();
+ getUiDevice().waitForIdle();
+ });
// Expect the permission is not granted
- assertPermissionRequestResult(secondResult, REQUEST_CODE_PERMISSIONS + 1,
- permissions, new boolean[] {false});
+ assertPermissionRequestResult(secondResult, permissions, new boolean[] {false});
// Clear the denial with prejudice
grantPermission(Manifest.permission.READ_CALENDAR);
@@ -392,20 +321,15 @@
.checkSelfPermission(Manifest.permission.READ_CALENDAR));
// Request the permission and allow it
- BasePermissionActivity.Result thirdResult = requestPermissions(new String[] {
- Manifest.permission.READ_CALENDAR}, REQUEST_CODE_PERMISSIONS + 2,
- BasePermissionActivity.class, () -> {
- try {
- clickAllowButton();
- getUiDevice().waitForIdle();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ BasePermissionActivity.Result thirdResult = requestPermissions(new String[]{
+ Manifest.permission.READ_CALENDAR}, () -> {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ });
// Make sure the permission is granted
- assertPermissionRequestResult(thirdResult, REQUEST_CODE_PERMISSIONS + 2,
- new String[] {Manifest.permission.READ_CALENDAR}, new boolean[] {true});
+ assertPermissionRequestResult(thirdResult, new String[] {Manifest.permission.READ_CALENDAR},
+ new boolean[] {true});
}
@Test
@@ -417,12 +341,10 @@
String[] permissions = new String[] {Manifest.permission.BIND_PRINT_SERVICE};
// Request the permission and do nothing
- BasePermissionActivity.Result result = requestPermissions(permissions,
- REQUEST_CODE_PERMISSIONS, BasePermissionActivity.class, null);
+ BasePermissionActivity.Result result = requestPermissions(permissions, null);
// Expect the permission is not granted
- assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
- permissions, new boolean[] {false});
+ assertPermissionRequestResult(result, permissions, new boolean[] {false});
}
@Test
@@ -434,12 +356,10 @@
String[] permissions = new String[] {"permission.does.not.exist"};
// Request the permission and do nothing
- BasePermissionActivity.Result result = requestPermissions(permissions,
- REQUEST_CODE_PERMISSIONS, BasePermissionActivity.class, null);
+ BasePermissionActivity.Result result = requestPermissions(permissions, null);
// Expect the permission is not granted
- assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
- permissions, new boolean[] {false});
+ assertPermissionRequestResult(result, permissions, new boolean[] {false});
}
@Test
@@ -456,8 +376,7 @@
};
// Request the permission and allow it
- BasePermissionActivity.Result result = requestPermissions(permissions,
- REQUEST_CODE_PERMISSIONS, BasePermissionActivity.class, () -> {
+ BasePermissionActivity.Result result = requestPermissions(permissions, () -> {
try {
clickAllowButton();
getUiDevice().waitForIdle();
@@ -469,8 +388,7 @@
});
// Expect the permission are reported as granted
- assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
- permissions, new boolean[] {true, true});
+ assertPermissionRequestResult(result, permissions, new boolean[] {true, true});
// The permissions are granted
assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
@@ -534,20 +452,19 @@
.checkSelfPermission(Manifest.permission.READ_CALENDAR));
// Request the permission and allow it
- BasePermissionActivity.Result thirdResult = requestPermissions(new String[] {
- Manifest.permission.READ_CALENDAR}, REQUEST_CODE_PERMISSIONS,
- BasePermissionActivity.class, () -> {
- try {
- clickAllowButton();
- getUiDevice().waitForIdle();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ BasePermissionActivity.Result thirdResult = requestPermissions(new String[]{
+ Manifest.permission.READ_CALENDAR}, () -> {
+ try {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
// Make sure the permission is granted
- assertPermissionRequestResult(thirdResult, REQUEST_CODE_PERMISSIONS,
- new String[] {Manifest.permission.READ_CALENDAR}, new boolean[] {true});
+ assertPermissionRequestResult(thirdResult, new String[] {Manifest.permission.READ_CALENDAR},
+ new boolean[] {true});
}
@Test
@@ -571,12 +488,9 @@
// Go through normal grant flow
BasePermissionActivity.Result result = requestPermissions(permissions,
- REQUEST_CODE_PERMISSIONS,
- BasePermissionActivity.class,
() -> { /* empty */ });
- assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
- permissions, new boolean[] {false});
+ assertPermissionRequestResult(result, permissions, new boolean[] {false});
}
@Test
@@ -595,21 +509,19 @@
};
// Request the permission and allow it
- BasePermissionActivity.Result result = requestPermissions(permissions,
- REQUEST_CODE_PERMISSIONS, BasePermissionActivity.class, () -> {
- try {
- clickAllowButton();
- getUiDevice().waitForIdle();
- clickAllowButton();
- getUiDevice().waitForIdle();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ BasePermissionActivity.Result result = requestPermissions(permissions, () -> {
+ try {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
// Expect the permission are reported as granted
- assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
- permissions, new boolean[] {false, true, false, true});
+ assertPermissionRequestResult(result, permissions, new boolean[] {false, true, false, true});
// The permissions are granted
assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
@@ -626,13 +538,10 @@
// Request the permission and allow it
BasePermissionActivity.Result result = requestPermissions(permissions,
- REQUEST_CODE_PERMISSIONS,
- BasePermissionActivity.class,
() -> { /* empty */ });
// Expect the permissions is not granted
- assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
- permissions, new boolean[] {false});
+ assertPermissionRequestResult(result, permissions, new boolean[] {false});
}
private void assertAllPermissionsRevoked() {
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp25/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp25/OWNERS
new file mode 100644
index 0000000..8075c9c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp25/OWNERS
@@ -0,0 +1,2 @@
+moltmann@google.com
+eugenesusla@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp26/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/OWNERS
new file mode 100644
index 0000000..8075c9c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/OWNERS
@@ -0,0 +1,2 @@
+moltmann@google.com
+eugenesusla@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp26/src/com/android/cts/usepermission/UsePermissionTest26.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/src/com/android/cts/usepermission/UsePermissionTest26.java
index e64838b..85b3529 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp26/src/com/android/cts/usepermission/UsePermissionTest26.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/src/com/android/cts/usepermission/UsePermissionTest26.java
@@ -42,21 +42,17 @@
// request only one permission from the 'SMS' permission group at runtime,
// but two from this group are <uses-permission> in the manifest
// request only one permission from the 'contacts' permission group
- BasePermissionActivity.Result result = requestPermissions(permissions,
- REQUEST_CODE_PERMISSIONS,
- BasePermissionActivity.class,
- () -> {
- try {
- clickAllowButton();
- getUiDevice().waitForIdle();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ BasePermissionActivity.Result result = requestPermissions(permissions, () -> {
+ try {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
// Expect the permission is granted
- assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
- permissions, new boolean[]{true});
+ assertPermissionRequestResult(result, permissions, new boolean[]{true});
assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getTargetContext()
.checkSelfPermission(Manifest.permission.SEND_SMS));
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp28/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp28/OWNERS
new file mode 100644
index 0000000..8075c9c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp28/OWNERS
@@ -0,0 +1,2 @@
+moltmann@google.com
+eugenesusla@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp28/src/com/android/cts/usepermission/UsePermissionTest28.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp28/src/com/android/cts/usepermission/UsePermissionTest28.java
index 1c32d39..4dd5349 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp28/src/com/android/cts/usepermission/UsePermissionTest28.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp28/src/com/android/cts/usepermission/UsePermissionTest28.java
@@ -23,9 +23,7 @@
import static junit.framework.Assert.assertEquals;
-import android.Manifest;
import android.content.Context;
-import android.content.pm.PackageManager;
import org.junit.Test;
@@ -46,19 +44,15 @@
// request only foreground permission. This should automatically also add the background
// permission
- BasePermissionActivity.Result result = requestPermissions(permissions,
- REQUEST_CODE_PERMISSIONS,
- BasePermissionActivity.class,
- () -> {
- try {
- clickAllowAlwaysButton();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ BasePermissionActivity.Result result = requestPermissions(permissions, () -> {
+ try {
+ clickAllowAlwaysButton();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
- assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS, permissions,
- new boolean[]{true});
+ assertPermissionRequestResult(result, permissions, new boolean[]{true});
assertEquals(PERMISSION_GRANTED, context.checkSelfPermission(ACCESS_FINE_LOCATION));
assertEquals(PERMISSION_GRANTED, context.checkSelfPermission(ACCESS_BACKGROUND_LOCATION));
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp29/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp29/OWNERS
new file mode 100644
index 0000000..8075c9c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp29/OWNERS
@@ -0,0 +1,2 @@
+moltmann@google.com
+eugenesusla@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp29/src/com/android/cts/usepermission/UsePermissionTest29.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp29/src/com/android/cts/usepermission/UsePermissionTest29.java
index e0e21eb..4fdc6c8 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp29/src/com/android/cts/usepermission/UsePermissionTest29.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp29/src/com/android/cts/usepermission/UsePermissionTest29.java
@@ -48,25 +48,21 @@
private BasePermissionActivity.Result requestPermissions(String[] permissions,
UiInteraction... uiInteractions) throws Exception {
- return super.requestPermissions(permissions,
- REQUEST_CODE_PERMISSIONS,
- BasePermissionActivity.class,
- () -> {
- try {
- for (UiInteraction uiInteraction : uiInteractions) {
- uiInteraction.run();
- getUiDevice().waitForIdle();
- }
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ return requestPermissions(permissions, () -> {
+ try {
+ for (UiInteraction uiInteraction : uiInteractions) {
+ uiInteraction.run();
+ getUiDevice().waitForIdle();
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
}
- private static void assertPermissionRequestResult(BasePermissionActivity.Result result,
+ protected static void assertPermissionRequestResult(BasePermissionActivity.Result result,
String[] permissions, boolean... granted) {
- BasePermissionsTest.assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
- permissions, granted);
+ BasePermissionsTest.assertPermissionRequestResult(result, permissions, granted);
}
@Before
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/Android.mk
index 6becbc8..cddfe17 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/Android.mk
@@ -23,7 +23,8 @@
androidx.test.rules \
compatibility-device-util-axt \
ctstestrunner-axt \
- ub-uiautomator
+ ub-uiautomator \
+ compatibility-device-util-axt \
LOCAL_SRC_FILES := $(call all-java-files-under, ../UsePermissionApp26/src) \
$(call all-java-files-under, ../UsePermissionApp29/src) \
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/OWNERS
new file mode 100644
index 0000000..8075c9c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/OWNERS
@@ -0,0 +1,2 @@
+moltmann@google.com
+eugenesusla@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/OWNERS
new file mode 100644
index 0000000..8075c9c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/OWNERS
@@ -0,0 +1,2 @@
+moltmann@google.com
+eugenesusla@google.com
diff --git a/hostsidetests/backup/KeyValueApp/src/android/cts/backup/keyvaluerestoreapp/KeyValueBackupAgent.java b/hostsidetests/backup/KeyValueApp/src/android/cts/backup/keyvaluerestoreapp/KeyValueBackupAgent.java
index f79baa9..85a96b1 100644
--- a/hostsidetests/backup/KeyValueApp/src/android/cts/backup/keyvaluerestoreapp/KeyValueBackupAgent.java
+++ b/hostsidetests/backup/KeyValueApp/src/android/cts/backup/keyvaluerestoreapp/KeyValueBackupAgent.java
@@ -17,6 +17,10 @@
package android.cts.backup.keyvaluerestoreapp;
import android.app.backup.BackupAgentHelper;
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.os.ParcelFileDescriptor;
+import java.io.IOException;
public class KeyValueBackupAgent extends BackupAgentHelper {
@@ -31,4 +35,20 @@
addHelper(KEY_BACKUP_TEST_FILES_PREFIX,
KeyValueBackupRestoreTest.getFileBackupHelper(this));
}
+
+ @Override
+ public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState) throws IOException {
+ // Explicitly override and call super() to help go/android-api-coverage-dashboard pick up
+ // the test coverage (b/113067697).
+ super.onBackup(oldState, data, newState);
+ }
+
+ @Override
+ public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
+ throws IOException {
+ // Explicitly override and call super() to help go/android-api-coverage-dashboard pick up
+ // the test coverage (b/113067697).
+ super.onRestore(data, appVersionCode, newState);
+ }
}
diff --git a/hostsidetests/backup/OWNERS b/hostsidetests/backup/OWNERS
index 3637e32..c28c4d8 100644
--- a/hostsidetests/backup/OWNERS
+++ b/hostsidetests/backup/OWNERS
@@ -1,3 +1,4 @@
+# Bug component: 41666
# Use this reviewer by default.
br-framework-team+reviews@google.com
diff --git a/hostsidetests/backup/src/android/cts/backup/BackupPreparer.java b/hostsidetests/backup/src/android/cts/backup/BackupPreparer.java
index 11a1dbc..2bbd8ff 100644
--- a/hostsidetests/backup/src/android/cts/backup/BackupPreparer.java
+++ b/hostsidetests/backup/src/android/cts/backup/BackupPreparer.java
@@ -16,6 +16,7 @@
package android.cts.backup;
+import com.android.compatibility.common.util.BackupHostSideUtils;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
@@ -27,6 +28,7 @@
import com.android.tradefed.targetprep.ITargetCleaner;
import com.android.tradefed.targetprep.TargetSetupError;
+import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -53,9 +55,6 @@
private static final String LOCAL_TRANSPORT =
"com.android.localtransport/.LocalTransport";
- private static final int BACKUP_PROVISIONING_TIMEOUT_SECONDS = 30;
- private static final int BACKUP_PROVISIONING_POLL_INTERVAL_SECONDS = 1;
-
private boolean mIsBackupSupported;
private boolean mWasBackupEnabled;
private String mOldTransport;
@@ -87,7 +86,11 @@
mOldTransport = setBackupTransport(LOCAL_TRANSPORT);
CLog.d("Old transport : %s", mOldTransport);
}
- waitForBackupInitialization();
+ try {
+ BackupHostSideUtils.createBackupUtils(mDevice).waitForBackupInitialization();
+ } catch (IOException e) {
+ throw new TargetSetupError("Backup not initialized", e);
+ }
}
}
}
@@ -149,27 +152,6 @@
}
}
- private void waitForBackupInitialization()
- throws TargetSetupError, DeviceNotAvailableException {
- long tryUntilNanos = System.nanoTime()
- + TimeUnit.SECONDS.toNanos(BACKUP_PROVISIONING_TIMEOUT_SECONDS);
- while (System.nanoTime() < tryUntilNanos) {
- String output = mDevice.executeShellCommand("dumpsys backup");
- if (output.matches("(?s)" // DOTALL
- + "^Backup Manager is .* not pending init.*")) {
- return;
- }
- try {
- Thread.sleep(TimeUnit.SECONDS.toMillis(BACKUP_PROVISIONING_POLL_INTERVAL_SECONDS));
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- break;
- }
- }
- throw new TargetSetupError("Timed out waiting for backup initialization",
- mDevice.getDeviceDescriptor());
- }
-
// Copied over from BaseDevicePolicyTest
private void waitForBroadcastIdle() throws DeviceNotAvailableException, TargetSetupError {
CollectingOutputReceiver receiver = new CollectingOutputReceiver();
diff --git a/hostsidetests/backup/src/android/cts/backup/BaseMultiUserBackupHostSideTest.java b/hostsidetests/backup/src/android/cts/backup/BaseMultiUserBackupHostSideTest.java
index 81737e9..1956562 100644
--- a/hostsidetests/backup/src/android/cts/backup/BaseMultiUserBackupHostSideTest.java
+++ b/hostsidetests/backup/src/android/cts/backup/BaseMultiUserBackupHostSideTest.java
@@ -58,7 +58,7 @@
FULL_BACKUP_TEST_PACKAGE + ".ProfileFullBackupRestoreTest";
protected final BackupUtils mBackupUtils = getBackupUtils();
- protected ITestDevice mDevice;
+ private ITestDevice mDevice;
// Store initial device state as Optional as tearDown() will execute even if we have assumption
// failures in setUp().
diff --git a/hostsidetests/backup/src/android/cts/backup/MultiUserBackupStateTest.java b/hostsidetests/backup/src/android/cts/backup/MultiUserBackupStateTest.java
index 4fa4469..673416c 100644
--- a/hostsidetests/backup/src/android/cts/backup/MultiUserBackupStateTest.java
+++ b/hostsidetests/backup/src/android/cts/backup/MultiUserBackupStateTest.java
@@ -44,7 +44,7 @@
public void setUp() throws Exception {
super.setUp();
- int profileUserId = createProfileUser(mDevice.getCurrentUser(), "MU-State");
+ int profileUserId = createProfileUser(getDevice().getCurrentUser(), "MU-State");
mProfileUserId = Optional.of(profileUserId);
startUser(profileUserId);
}
@@ -54,7 +54,7 @@
@Override
public void tearDown() throws Exception {
if (mProfileUserId.isPresent()) {
- assertTrue(mDevice.removeUser(mProfileUserId.get()));
+ assertTrue(getDevice().removeUser(mProfileUserId.get()));
mProfileUserId = Optional.empty();
}
super.tearDown();
@@ -77,7 +77,7 @@
assertTrue(mBackupUtils.isBackupActivatedForUser(profileUserId));
- assertTrue(mDevice.removeUser(profileUserId));
+ assertTrue(getDevice().removeUser(profileUserId));
mProfileUserId = Optional.empty();
HostSideTestUtils.waitUntil("wait for backup to be deactivated for removed user",
diff --git a/hostsidetests/bootstats/OWNERS b/hostsidetests/bootstats/OWNERS
new file mode 100644
index 0000000..1f99e96
--- /dev/null
+++ b/hostsidetests/bootstats/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 183496
+keunyoung@google.com
diff --git a/hostsidetests/classloaders/OWNERS b/hostsidetests/classloaders/OWNERS
new file mode 100644
index 0000000..137abb9
--- /dev/null
+++ b/hostsidetests/classloaders/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 86431
+calin@google.com
+ngeoffray@google.com
+sehr@google.com
diff --git a/hostsidetests/compilation/OWNERS b/hostsidetests/compilation/OWNERS
new file mode 100644
index 0000000..f386ff2
--- /dev/null
+++ b/hostsidetests/compilation/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 86431
+include ../classloaders/OWNERS
diff --git a/hostsidetests/compilation/app/Android.bp b/hostsidetests/compilation/app/Android.bp
index f4954c7..770baea 100644
--- a/hostsidetests/compilation/app/Android.bp
+++ b/hostsidetests/compilation/app/Android.bp
@@ -16,7 +16,7 @@
name: "CtsCompilationApp",
defaults: ["cts_support_defaults"],
srcs: ["src/**/*.java"],
- sdk_version: "current",
+ sdk_version: "29",
// tag this module as a cts test artifact
test_suites: [
"cts",
diff --git a/hostsidetests/compilation/assets/CtsCompilationApp.apk b/hostsidetests/compilation/assets/CtsCompilationApp.apk
index 18c76d3..ba89b24 100644
--- a/hostsidetests/compilation/assets/CtsCompilationApp.apk
+++ b/hostsidetests/compilation/assets/CtsCompilationApp.apk
Binary files differ
diff --git a/hostsidetests/devicepolicy/OWNERS b/hostsidetests/devicepolicy/OWNERS
new file mode 100644
index 0000000..12341eb
--- /dev/null
+++ b/hostsidetests/devicepolicy/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 100560
+include /tests/admin/OWNERS
diff --git a/hostsidetests/devicepolicy/app/CertInstaller/Android.bp b/hostsidetests/devicepolicy/app/CertInstaller/Android.bp
index 9b99054..a3ae108 100644
--- a/hostsidetests/devicepolicy/app/CertInstaller/Android.bp
+++ b/hostsidetests/devicepolicy/app/CertInstaller/Android.bp
@@ -31,6 +31,7 @@
],
// tag this module as a cts test artifact
test_suites: [
+ "arcts",
"cts",
"vts",
"general-tests",
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp
index 1062d2e..513eda2 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.bp
@@ -61,6 +61,7 @@
min_sdk_version: "23",
// tag this module as a cts test artifact
test_suites: [
+ "arcts",
"cts",
"vts",
"general-tests",
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DeviceIdentifiersTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DeviceIdentifiersTest.java
index ea60582..3c53de9 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DeviceIdentifiersTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DeviceIdentifiersTest.java
@@ -16,6 +16,7 @@
package com.android.cts.deviceowner;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Build;
import android.telephony.TelephonyManager;
@@ -72,39 +73,66 @@
// SecurityException when querying for device identifiers.
TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(
Context.TELEPHONY_SERVICE);
+ // Allow the APIs to also return null if the telephony feature is not supported.
+ boolean hasTelephonyFeature =
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
try {
- telephonyManager.getDeviceId();
- fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getDeviceId"));
+ String deviceId = telephonyManager.getDeviceId();
+ if (hasTelephonyFeature) {
+ fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getDeviceId"));
+ } else {
+ assertEquals(null, deviceId);
+ }
} catch (SecurityException expected) {
}
try {
- telephonyManager.getImei();
- fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getImei"));
+ String imei = telephonyManager.getImei();
+ if (hasTelephonyFeature) {
+ fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getImei"));
+ } else {
+ assertEquals(null, imei);
+ }
} catch (SecurityException expected) {
}
try {
- telephonyManager.getMeid();
- fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getMeid"));
+ String meid = telephonyManager.getMeid();
+ if (hasTelephonyFeature) {
+ fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getMeid"));
+ } else {
+ assertEquals(null, meid);
+ }
} catch (SecurityException expected) {
}
try {
- telephonyManager.getSubscriberId();
- fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getSubscriberId"));
+ String subscriberId = telephonyManager.getSubscriberId();
+ if (hasTelephonyFeature) {
+ fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getSubscriberId"));
+ } else {
+ assertEquals(null, subscriberId);
+ }
} catch (SecurityException expected) {
}
try {
- telephonyManager.getSimSerialNumber();
- fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getSimSerialNumber"));
+ String simSerialNumber = telephonyManager.getSimSerialNumber();
+ if (hasTelephonyFeature) {
+ fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getSimSerialNumber"));
+ } else {
+ assertEquals(null, simSerialNumber);
+ }
} catch (SecurityException expected) {
}
try {
- Build.getSerial();
- fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "Build#getSerial"));
+ String serial = Build.getSerial();
+ if (hasTelephonyFeature) {
+ fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "Build#getSerial"));
+ } else {
+ assertEquals(null, serial);
+ }
} catch (SecurityException expected) {
}
}
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
index 3cfc542..fc424be 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
+++ b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
@@ -38,6 +38,6 @@
LOCAL_MIN_SDK_VERSION := 21
# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := arcts cts vts general-tests
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.bp b/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.bp
index f134b69..c690f9c 100644
--- a/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.bp
+++ b/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.bp
@@ -21,6 +21,7 @@
min_sdk_version: "21",
// tag this module as a cts test artifact
test_suites: [
+ "arcts",
"cts",
"vts",
"general-tests",
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/DeviceIdentifiersTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/DeviceIdentifiersTest.java
index 7c26fad..14e7b0c 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/DeviceIdentifiersTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/DeviceIdentifiersTest.java
@@ -16,6 +16,7 @@
package com.android.cts.managedprofile;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Build;
import android.telephony.TelephonyManager;
@@ -72,39 +73,66 @@
// SecurityException when querying for device identifiers.
TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(
Context.TELEPHONY_SERVICE);
+ // Allow the APIs to also return null if the telephony feature is not supported.
+ boolean hasTelephonyFeature =
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
try {
- telephonyManager.getDeviceId();
- fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getDeviceId"));
+ String deviceId = telephonyManager.getDeviceId();
+ if (hasTelephonyFeature) {
+ fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getDeviceId"));
+ } else {
+ assertEquals(null, deviceId);
+ }
} catch (SecurityException expected) {
}
try {
- telephonyManager.getImei();
- fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getImei"));
+ String imei = telephonyManager.getImei();
+ if (hasTelephonyFeature) {
+ fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getImei"));
+ } else {
+ assertEquals(null, imei);
+ }
} catch (SecurityException expected) {
}
try {
- telephonyManager.getMeid();
- fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getMeid"));
+ String meid = telephonyManager.getMeid();
+ if (hasTelephonyFeature) {
+ fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getMeid"));
+ } else {
+ assertEquals(null, meid);
+ }
} catch (SecurityException expected) {
}
try {
- telephonyManager.getSubscriberId();
- fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getSubscriberId"));
+ String subscriberId = telephonyManager.getSubscriberId();
+ if (hasTelephonyFeature) {
+ fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getSubscriberId"));
+ } else {
+ assertEquals(null, subscriberId);
+ }
} catch (SecurityException expected) {
}
try {
- telephonyManager.getSimSerialNumber();
- fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getSimSerialNumber"));
+ String simSerialNumber = telephonyManager.getSimSerialNumber();
+ if (hasTelephonyFeature) {
+ fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "getSimSerialNumber"));
+ } else {
+ assertEquals(null, simSerialNumber);
+ }
} catch (SecurityException expected) {
}
try {
- Build.getSerial();
- fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "Build#getSerial"));
+ String serial = Build.getSerial();
+ if (hasTelephonyFeature) {
+ fail(String.format(NO_SECURITY_EXCEPTION_ERROR_MESSAGE, "Build#getSerial"));
+ } else {
+ assertEquals(null, serial);
+ }
} catch (SecurityException expected) {
}
}
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/Android.bp b/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/Android.bp
index 2e8d9f4..f0f4716 100644
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/Android.bp
@@ -25,6 +25,7 @@
srcs: ["src/**/*.java"],
// tag this module as a cts test artifact
test_suites: [
+ "arcts",
"cts",
"vts",
"general-tests",
@@ -45,6 +46,7 @@
srcs: ["src/**/*.java"],
// tag this module as a cts test artifact
test_suites: [
+ "arcts",
"cts",
"vts",
"general-tests",
@@ -66,6 +68,7 @@
srcs: ["src/**/*.java"],
// tag this module as a cts test artifact
test_suites: [
+ "arcts",
"cts",
"vts",
"general-tests",
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 01d64ed..538a2a5 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -94,7 +94,8 @@
//The maximum time to wait for user to be unlocked.
private static final long USER_UNLOCK_TIMEOUT_NANO = 30_000_000_000L;
- private static final String USER_UNLOCKED_SHELL_OUTPUT = "RUNNING_UNLOCKED";
+ private static final String USER_STATE_UNLOCKED = "RUNNING_UNLOCKED";
+ private static final String USER_STATE_LOCKED = "RUNNING_LOCKED";
private int mParentUserId;
@@ -130,7 +131,7 @@
final String command = String.format("am get-started-user-state %d", mProfileUserId);
final long deadline = System.nanoTime() + USER_UNLOCK_TIMEOUT_NANO;
while (System.nanoTime() <= deadline) {
- if (getDevice().executeShellCommand(command).startsWith(USER_UNLOCKED_SHELL_OUTPUT)) {
+ if (getDevice().executeShellCommand(command).startsWith(USER_STATE_UNLOCKED)) {
return;
}
Thread.sleep(100);
@@ -265,15 +266,9 @@
}
private void waitUntilProfileLocked() throws Exception {
- final String cmd = "dumpsys activity | grep 'User #" + mProfileUserId + ": state='";
- final Pattern p = Pattern.compile("state=([\\p{Upper}_]+)$");
- SuccessCondition userLocked = () -> {
- final String activityDump = getDevice().executeShellCommand(cmd);
- final Matcher m = p.matcher(activityDump);
- return m.find() && m.group(1).equals("RUNNING_LOCKED");
- };
+ final String cmd = String.format("am get-started-user-state %d", mProfileUserId);
tryWaitForSuccess(
- userLocked,
+ () -> getDevice().executeShellCommand(cmd).startsWith(USER_STATE_LOCKED),
"The managed profile has not been locked after calling "
+ "lockNow(FLAG_SECURE_USER_DATA)",
TIMEOUT_USER_LOCKED_MILLIS);
diff --git a/hostsidetests/media/OWNERS b/hostsidetests/media/OWNERS
index 9884b18..8d6b291e 100644
--- a/hostsidetests/media/OWNERS
+++ b/hostsidetests/media/OWNERS
@@ -1,4 +1,4 @@
-rachad@google.com
+# Bug component: 1344
elaurent@google.com
lajos@google.com
marcone@google.com
diff --git a/hostsidetests/rollback/OWNERS b/hostsidetests/rollback/OWNERS
new file mode 100644
index 0000000..e84df8e
--- /dev/null
+++ b/hostsidetests/rollback/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 557916
+ruhler@google.com
+*
\ No newline at end of file
diff --git a/hostsidetests/sample/OWNERS b/hostsidetests/sample/OWNERS
new file mode 100644
index 0000000..84828b2
--- /dev/null
+++ b/hostsidetests/sample/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 346961
+include /tests/sample/OWNERS
diff --git a/hostsidetests/security/OWNERS b/hostsidetests/security/OWNERS
new file mode 100644
index 0000000..94522e3
--- /dev/null
+++ b/hostsidetests/security/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 36824
+include /tests/tests/security/OWNERS
diff --git a/hostsidetests/signedconfig/hostside/OWNERS b/hostsidetests/signedconfig/hostside/OWNERS
new file mode 100644
index 0000000..f968305
--- /dev/null
+++ b/hostsidetests/signedconfig/hostside/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 533114
+mathewi@google.com
+*
diff --git a/hostsidetests/stagedinstall/OWNERS b/hostsidetests/stagedinstall/OWNERS
new file mode 100644
index 0000000..2dd1076
--- /dev/null
+++ b/hostsidetests/stagedinstall/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 36137
+dariofreni@google.com
+toddke@google.com
+narayan@google.com
+patb@google.com
+ioffe@google.com
diff --git a/hostsidetests/theme/OWNERS b/hostsidetests/theme/OWNERS
index ae2c27b..b43358c 100644
--- a/hostsidetests/theme/OWNERS
+++ b/hostsidetests/theme/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 25700
-alanv@google.com
\ No newline at end of file
+alanv@google.com
+aurimas@google.com
\ No newline at end of file
diff --git a/hostsidetests/theme/assets/29/140dpi.zip b/hostsidetests/theme/assets/29/140dpi.zip
index cb385f1..48de32b 100644
--- a/hostsidetests/theme/assets/29/140dpi.zip
+++ b/hostsidetests/theme/assets/29/140dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/180dpi.zip b/hostsidetests/theme/assets/29/180dpi.zip
index b034a7f..4def986 100644
--- a/hostsidetests/theme/assets/29/180dpi.zip
+++ b/hostsidetests/theme/assets/29/180dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/200dpi.zip b/hostsidetests/theme/assets/29/200dpi.zip
index 9a0ca5e..fe2495e 100644
--- a/hostsidetests/theme/assets/29/200dpi.zip
+++ b/hostsidetests/theme/assets/29/200dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/220dpi.zip b/hostsidetests/theme/assets/29/220dpi.zip
index b65a035..a2c2ea2 100644
--- a/hostsidetests/theme/assets/29/220dpi.zip
+++ b/hostsidetests/theme/assets/29/220dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/260dpi.zip b/hostsidetests/theme/assets/29/260dpi.zip
index 9cdefe7..74890a2 100644
--- a/hostsidetests/theme/assets/29/260dpi.zip
+++ b/hostsidetests/theme/assets/29/260dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/280dpi.zip b/hostsidetests/theme/assets/29/280dpi.zip
index 2e39de5..83fd290 100644
--- a/hostsidetests/theme/assets/29/280dpi.zip
+++ b/hostsidetests/theme/assets/29/280dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/300dpi.zip b/hostsidetests/theme/assets/29/300dpi.zip
index fba9c6c..25334d8 100644
--- a/hostsidetests/theme/assets/29/300dpi.zip
+++ b/hostsidetests/theme/assets/29/300dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/340dpi.zip b/hostsidetests/theme/assets/29/340dpi.zip
index 72e6f8f..2092326 100644
--- a/hostsidetests/theme/assets/29/340dpi.zip
+++ b/hostsidetests/theme/assets/29/340dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/360dpi.zip b/hostsidetests/theme/assets/29/360dpi.zip
index 3970139..c13ad5c 100644
--- a/hostsidetests/theme/assets/29/360dpi.zip
+++ b/hostsidetests/theme/assets/29/360dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/400dpi.zip b/hostsidetests/theme/assets/29/400dpi.zip
index 510eb94d..1df1a95 100644
--- a/hostsidetests/theme/assets/29/400dpi.zip
+++ b/hostsidetests/theme/assets/29/400dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/420dpi.zip b/hostsidetests/theme/assets/29/420dpi.zip
index a457bda..d58d418 100644
--- a/hostsidetests/theme/assets/29/420dpi.zip
+++ b/hostsidetests/theme/assets/29/420dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/440dpi.zip b/hostsidetests/theme/assets/29/440dpi.zip
index 07355d1..535102f 100644
--- a/hostsidetests/theme/assets/29/440dpi.zip
+++ b/hostsidetests/theme/assets/29/440dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/560dpi.zip b/hostsidetests/theme/assets/29/560dpi.zip
index 6a85ad8..20f1c7b 100644
--- a/hostsidetests/theme/assets/29/560dpi.zip
+++ b/hostsidetests/theme/assets/29/560dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/hdpi.zip b/hostsidetests/theme/assets/29/hdpi.zip
index e1a534a..582989d 100644
--- a/hostsidetests/theme/assets/29/hdpi.zip
+++ b/hostsidetests/theme/assets/29/hdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/ldpi.zip b/hostsidetests/theme/assets/29/ldpi.zip
index 5475608..3035146 100644
--- a/hostsidetests/theme/assets/29/ldpi.zip
+++ b/hostsidetests/theme/assets/29/ldpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/mdpi.zip b/hostsidetests/theme/assets/29/mdpi.zip
index 67c5c03..a831e7b 100644
--- a/hostsidetests/theme/assets/29/mdpi.zip
+++ b/hostsidetests/theme/assets/29/mdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/tvdpi.zip b/hostsidetests/theme/assets/29/tvdpi.zip
index 60f5afe..bd4bf75 100644
--- a/hostsidetests/theme/assets/29/tvdpi.zip
+++ b/hostsidetests/theme/assets/29/tvdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/xhdpi.zip b/hostsidetests/theme/assets/29/xhdpi.zip
index d2895a1..0dd72e2 100644
--- a/hostsidetests/theme/assets/29/xhdpi.zip
+++ b/hostsidetests/theme/assets/29/xhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/xxhdpi.zip b/hostsidetests/theme/assets/29/xxhdpi.zip
index 637649a..64fc846 100644
--- a/hostsidetests/theme/assets/29/xxhdpi.zip
+++ b/hostsidetests/theme/assets/29/xxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/29/xxxhdpi.zip b/hostsidetests/theme/assets/29/xxxhdpi.zip
index 9ab19b1..87beb9a 100644
--- a/hostsidetests/theme/assets/29/xxxhdpi.zip
+++ b/hostsidetests/theme/assets/29/xxxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/140dpi.zip b/hostsidetests/theme/assets/R/140dpi.zip
new file mode 100644
index 0000000..48de32b
--- /dev/null
+++ b/hostsidetests/theme/assets/R/140dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/180dpi.zip b/hostsidetests/theme/assets/R/180dpi.zip
new file mode 100644
index 0000000..4def986
--- /dev/null
+++ b/hostsidetests/theme/assets/R/180dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/200dpi.zip b/hostsidetests/theme/assets/R/200dpi.zip
new file mode 100644
index 0000000..fe2495e
--- /dev/null
+++ b/hostsidetests/theme/assets/R/200dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/220dpi.zip b/hostsidetests/theme/assets/R/220dpi.zip
new file mode 100644
index 0000000..a2c2ea2
--- /dev/null
+++ b/hostsidetests/theme/assets/R/220dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/260dpi.zip b/hostsidetests/theme/assets/R/260dpi.zip
index ba5d363..74890a2 100644
--- a/hostsidetests/theme/assets/R/260dpi.zip
+++ b/hostsidetests/theme/assets/R/260dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/280dpi.zip b/hostsidetests/theme/assets/R/280dpi.zip
index 34ea14c..83fd290 100644
--- a/hostsidetests/theme/assets/R/280dpi.zip
+++ b/hostsidetests/theme/assets/R/280dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/300dpi.zip b/hostsidetests/theme/assets/R/300dpi.zip
index 7595d24..25334d8 100644
--- a/hostsidetests/theme/assets/R/300dpi.zip
+++ b/hostsidetests/theme/assets/R/300dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/340dpi.zip b/hostsidetests/theme/assets/R/340dpi.zip
index 8ce960c..2092326 100644
--- a/hostsidetests/theme/assets/R/340dpi.zip
+++ b/hostsidetests/theme/assets/R/340dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/360dpi.zip b/hostsidetests/theme/assets/R/360dpi.zip
index aae3adc..c13ad5c 100644
--- a/hostsidetests/theme/assets/R/360dpi.zip
+++ b/hostsidetests/theme/assets/R/360dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/400dpi.zip b/hostsidetests/theme/assets/R/400dpi.zip
index 363d602..1df1a95 100644
--- a/hostsidetests/theme/assets/R/400dpi.zip
+++ b/hostsidetests/theme/assets/R/400dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/420dpi.zip b/hostsidetests/theme/assets/R/420dpi.zip
index 0f2ce47..d58d418 100644
--- a/hostsidetests/theme/assets/R/420dpi.zip
+++ b/hostsidetests/theme/assets/R/420dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/440dpi.zip b/hostsidetests/theme/assets/R/440dpi.zip
index 2328c61..535102f 100644
--- a/hostsidetests/theme/assets/R/440dpi.zip
+++ b/hostsidetests/theme/assets/R/440dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/560dpi.zip b/hostsidetests/theme/assets/R/560dpi.zip
index 5f1bb0b..20f1c7b 100644
--- a/hostsidetests/theme/assets/R/560dpi.zip
+++ b/hostsidetests/theme/assets/R/560dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/hdpi.zip b/hostsidetests/theme/assets/R/hdpi.zip
index 6d82318..582989d 100644
--- a/hostsidetests/theme/assets/R/hdpi.zip
+++ b/hostsidetests/theme/assets/R/hdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/ldpi.zip b/hostsidetests/theme/assets/R/ldpi.zip
index cc60027..3035146 100644
--- a/hostsidetests/theme/assets/R/ldpi.zip
+++ b/hostsidetests/theme/assets/R/ldpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/mdpi.zip b/hostsidetests/theme/assets/R/mdpi.zip
index 66d41d4..a831e7b 100644
--- a/hostsidetests/theme/assets/R/mdpi.zip
+++ b/hostsidetests/theme/assets/R/mdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/tvdpi.zip b/hostsidetests/theme/assets/R/tvdpi.zip
index b43032f..bd4bf75 100644
--- a/hostsidetests/theme/assets/R/tvdpi.zip
+++ b/hostsidetests/theme/assets/R/tvdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/xhdpi.zip b/hostsidetests/theme/assets/R/xhdpi.zip
index 64905f3..0dd72e2 100644
--- a/hostsidetests/theme/assets/R/xhdpi.zip
+++ b/hostsidetests/theme/assets/R/xhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/xxhdpi.zip b/hostsidetests/theme/assets/R/xxhdpi.zip
index b2cb422..64fc846 100644
--- a/hostsidetests/theme/assets/R/xxhdpi.zip
+++ b/hostsidetests/theme/assets/R/xxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/R/xxxhdpi.zip b/hostsidetests/theme/assets/R/xxxhdpi.zip
index d00dbbd..87beb9a 100644
--- a/hostsidetests/theme/assets/R/xxxhdpi.zip
+++ b/hostsidetests/theme/assets/R/xxxhdpi.zip
Binary files differ
diff --git a/libs/deviceutillegacy/Android.bp b/libs/deviceutillegacy/Android.bp
index bbdd399..220b2ab 100644
--- a/libs/deviceutillegacy/Android.bp
+++ b/libs/deviceutillegacy/Android.bp
@@ -13,23 +13,6 @@
// limitations under the License.
java_library_static {
- name: "ctsdeviceutillegacy",
-
- static_libs: [
- "compatibility-device-util",
- "junit",
- ],
-
- libs: ["android.test.base.stubs"],
-
- srcs: ["src/**/*.java"],
-
- sdk_version: "test_current",
-
-}
-
-// A variant of ctsdeviceutillegacy that depends on androidx.test instead of android.support.test
-java_library_static {
name: "ctsdeviceutillegacy-axt",
static_libs: [
diff --git a/libs/runner/Android.bp b/libs/runner/Android.bp
index 425c593..40977ff 100644
--- a/libs/runner/Android.bp
+++ b/libs/runner/Android.bp
@@ -12,16 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// The legacy library that brings in android-support-test transitively
-java_library {
- name: "ctstestrunner",
-
- static_libs: ["cts-test-runner"],
-
- sdk_version: "current",
-
-}
-
// The library variant that brings in androidx-test transitively
java_library {
name: "ctstestrunner-axt",
diff --git a/tests/DropBoxManager/OWNERS b/tests/DropBoxManager/OWNERS
new file mode 100644
index 0000000..1a5b740
--- /dev/null
+++ b/tests/DropBoxManager/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 1344
+mwachens@google.com
diff --git a/tests/JobScheduler/OWNERS b/tests/JobScheduler/OWNERS
new file mode 100644
index 0000000..ef7929f
--- /dev/null
+++ b/tests/JobScheduler/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 330738
+ctate@google.com
\ No newline at end of file
diff --git a/tests/JobSchedulerSharedUid/OWNERS b/tests/JobSchedulerSharedUid/OWNERS
new file mode 100644
index 0000000..ef7929f
--- /dev/null
+++ b/tests/JobSchedulerSharedUid/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 330738
+ctate@google.com
\ No newline at end of file
diff --git a/tests/acceleration/OWNERS b/tests/acceleration/OWNERS
new file mode 100644
index 0000000..3d2576a
--- /dev/null
+++ b/tests/acceleration/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 32850
+include platform/frameworks/base:/libs/hwui/OWNERS
diff --git a/tests/accessibility/AndroidManifest.xml b/tests/accessibility/AndroidManifest.xml
index f07494f..d4cea0f 100644
--- a/tests/accessibility/AndroidManifest.xml
+++ b/tests/accessibility/AndroidManifest.xml
@@ -21,9 +21,11 @@
android:targetSandboxVersion="2">
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
- <application android:theme="@android:style/Theme.Holo.NoActionBar" >
+ <application android:theme="@android:style/Theme.Holo.NoActionBar"
+ android:requestLegacyExternalStorage="true">
<uses-library android:name="android.test.runner"/>
<service android:name=".SpeakingAccessibilityService"
android:label="@string/title_speaking_accessibility_service"
diff --git a/tests/accessibility/AndroidTest.xml b/tests/accessibility/AndroidTest.xml
index 7783a25..3057ae8 100644
--- a/tests/accessibility/AndroidTest.xml
+++ b/tests/accessibility/AndroidTest.xml
@@ -30,4 +30,8 @@
<option name="package" value="android.view.accessibility.cts" />
<option name="runtime-hint" value="8m"/>
</test>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/sdcard/android.view.accessibility.cts" />
+ <option name="collect-on-run-ended-only" value="true" />
+ </metrics_collector>
</configuration>
diff --git a/tests/accessibility/common/src/android/accessibility/cts/common/AccessibilityDumpOnFailureRule.java b/tests/accessibility/common/src/android/accessibility/cts/common/AccessibilityDumpOnFailureRule.java
new file mode 100644
index 0000000..a7a4282
--- /dev/null
+++ b/tests/accessibility/common/src/android/accessibility/cts/common/AccessibilityDumpOnFailureRule.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.accessibility.cts.common;
+
+import android.util.Log;
+
+import org.junit.AssumptionViolatedException;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Custom {@code TestRule} that dump UI data upon test failures.
+ *
+ * <p>Note: when using other {@code TestRule}s, make sure to use a {@code RuleChain} to ensure it
+ * is applied outside of other rules that can fail a test (otherwise this rule may not know that the
+ * test failed).
+ *
+ * <p>To capture the output of this rule, add the following to AndroidTest.xml:
+ * <pre>
+ * <!-- Collect output of AccessibilityDumpOnFailureRule. -->
+ * <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ * <option name="directory-keys" value="/sdcard/<test.package.name>" />
+ * <option name="collect-on-run-ended-only" value="true" />
+ * </metrics_collector>
+ * </pre>
+ * <p>And disable external storage isolation:
+ * <pre>
+ * <application ... android:requestLegacyExternalStorage="true" ... >
+ * </pre>
+ */
+public class AccessibilityDumpOnFailureRule implements TestRule {
+
+ private static final String LOG_TAG = AccessibilityDumpOnFailureRule.class.getSimpleName();
+
+ private AccessibilityDumper mDumper = new AccessibilityDumper();
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ base.evaluate();
+ } catch (Throwable t) {
+ // Ignore AssumptionViolatedException. It's not a test fail.
+ if (!(t instanceof AssumptionViolatedException)) {
+ onTestFailure(description, t);
+ throw t;
+ }
+ }
+ }
+ };
+ }
+
+ public void dump(int flag) {
+ mDumper.dump(flag);
+ }
+
+ protected void onTestFailure(Description description, Throwable t) {
+ try {
+ mDumper.setName(getTestNameFrom(description));
+ mDumper.dump();
+ } catch (Throwable throwable) {
+ Log.e(LOG_TAG, "Dump fail", throwable);
+ }
+ }
+
+ private String getTestNameFrom(Description description) {
+ return description.getTestClass().getSimpleName()
+ + "_" + description.getMethodName();
+ }
+}
diff --git a/tests/accessibility/common/src/android/accessibility/cts/common/AccessibilityDumper.java b/tests/accessibility/common/src/android/accessibility/cts/common/AccessibilityDumper.java
new file mode 100644
index 0000000..3d37d3c
--- /dev/null
+++ b/tests/accessibility/common/src/android/accessibility/cts/common/AccessibilityDumper.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.accessibility.cts.common;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+
+import android.app.UiAutomation;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.os.Environment;
+import android.support.test.uiautomator.UiDevice;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityWindowInfo;
+
+import com.android.compatibility.common.util.BitmapUtils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.time.LocalTime;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Helper class to dump data for accessibility test cases.
+ *
+ * It can dump {@code dumpsys accessibility}, accessibility node tree to logcat and/or
+ * screenshot for inspect later.
+ */
+public class AccessibilityDumper {
+ private static final String TAG = "AccessibilityDumper";
+
+ /** Dump flag to write the output of {@code dumpsys accessibility} to logcat. */
+ public static final int FLAG_DUMPSYS = 0x1;
+
+ /** Dump flag to write the output of {@code uiautomator dump} to logcat. */
+ public static final int FLAG_HIERARCHY = 0x2;
+
+ /** Dump flag to save the screenshot to external storage. */
+ public static final int FLAG_SCREENSHOT = 0x4;
+
+ /** Dump flag to write the tree of accessility node info to logcat. */
+ public static final int FLAG_NODETREE = 0x8;
+
+ /** Default dump flag */
+ public static final int FLAG_DUMP_ALL = FLAG_DUMPSYS | FLAG_HIERARCHY | FLAG_SCREENSHOT;
+
+ private int mFlag;
+
+ /** Screenshot filename */
+ private String mName;
+
+ /** Root directory matching the directory-key of collector in AndroidTest.xml */
+ private File mRoot;
+
+ /**
+ * Define the directory to dump/clean and initial dump options
+ *
+ * @param flag control what to dump
+ */
+ public AccessibilityDumper(int flag) {
+ mRoot = getDumpRoot(getContext().getPackageName());
+ mFlag = flag;
+ }
+
+ public AccessibilityDumper() {
+ this(FLAG_DUMP_ALL);
+ }
+
+ public void dump(int flag) {
+ if ((flag & FLAG_DUMPSYS) != 0) {
+ dumpsysOnLogcat();
+ }
+ if ((flag & FLAG_HIERARCHY) != 0) {
+ dumpHierarchyOnLogcat();
+ }
+ if ((flag & FLAG_SCREENSHOT) != 0) {
+ dumpScreen();
+ }
+ if ((flag & FLAG_NODETREE) != 0) {
+ dumpAccessibilityNodeTreeOnLogcat();
+ }
+ }
+
+ void dump() {
+ dump(mFlag);
+ }
+
+ void setName(String name) {
+ assertNotEmpty(name);
+ mName = name;
+ }
+
+ private File getDumpRoot(String directory) {
+ return new File(Environment.getExternalStorageDirectory(), directory);
+ }
+
+ private void dumpsysOnLogcat() {
+ ShellCommandBuilder.create(getInstrumentation())
+ .addCommandPrintOnLogCat("dumpsys accessibility")
+ .run();
+ }
+
+ private void dumpHierarchyOnLogcat() {
+ try(ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+ UiDevice.getInstance(getInstrumentation()).dumpWindowHierarchy(os);
+ Log.w(TAG, "Window hierarchy:");
+ for (String line : os.toString("UTF-8").split("\\n")) {
+ Log.w(TAG, line);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "ERROR: unable to dumping hierarchy on logcat", e);
+ }
+ }
+
+ private void dumpScreen() {
+ assertNotEmpty(mName);
+ final Bitmap screenshot = getInstrumentation().getUiAutomation().takeScreenshot();
+ final String filename = String.format("%s_%s__screenshot.png", mName, LocalTime.now());
+ BitmapUtils.saveBitmap(screenshot, mRoot.toString(), filename);
+ }
+
+ /** Dump hierarchy compactly and include nodes not visible to user */
+ private void dumpAccessibilityNodeTreeOnLogcat() {
+ final Set<AccessibilityNodeInfo> roots = new HashSet<>();
+ final UiAutomation automation = getInstrumentation().getUiAutomation();
+ for (AccessibilityWindowInfo window : automation.getWindows()) {
+ AccessibilityNodeInfo root = window.getRoot();
+ if (root == null) {
+ Log.w(TAG, String.format("Skipping null root node for window: %s",
+ window.toString()));
+ } else {
+ roots.add(root);
+ }
+ }
+ if (roots.isEmpty()) {
+ Log.w(TAG, "No node of windows to dump");
+ } else {
+ Log.w(TAG, "Accessibility nodes hierarchy:");
+ for (AccessibilityNodeInfo root : roots) {
+ dumpTreeWithPrefix(root, "");
+ }
+ }
+ }
+
+ private static void dumpTreeWithPrefix(AccessibilityNodeInfo node, String prefix) {
+ final StringBuilder nodeText = new StringBuilder(prefix);
+ appendNodeText(nodeText, node);
+ Log.v(TAG, nodeText.toString());
+ final int count = node.getChildCount();
+ for (int i = 0; i < count; i++) {
+ AccessibilityNodeInfo child = node.getChild(i);
+ if (child != null) {
+ dumpTreeWithPrefix(child, "-" + prefix);
+ } else {
+ Log.i(TAG, String.format("%sNull child %d/%d", prefix, i, count));
+ }
+ }
+ }
+
+ private static void appendNodeText(StringBuilder out, AccessibilityNodeInfo node) {
+ final CharSequence txt = node.getText();
+ final CharSequence description = node.getContentDescription();
+ final String viewId = node.getViewIdResourceName();
+
+ if (!TextUtils.isEmpty(description)) {
+ out.append(escape(description));
+ } else if (!TextUtils.isEmpty(txt)) {
+ out.append('"').append(escape(txt)).append('"');
+ }
+ if (!TextUtils.isEmpty(viewId)) {
+ out.append("(").append(viewId).append(")");
+ }
+ out.append("+").append(node.getClassName());
+ out.append("+ \t<");
+ out.append(node.isCheckable() ? "C" : ".");
+ out.append(node.isChecked() ? "c" : ".");
+ out.append(node.isClickable() ? "K" : ".");
+ out.append(node.isEnabled() ? "E" : ".");
+ out.append(node.isFocusable() ? "F" : ".");
+ out.append(node.isFocused() ? "f" : ".");
+ out.append(node.isScrollable() ? "S" : ".");
+ out.append(node.isLongClickable() ? "L" : ".");
+ out.append(node.isPassword() ? "P" : ".");
+ out.append(node.isSelected() ? "s" : ".");
+ out.append(node.isVisibleToUser() ? "V" : ".");
+ out.append("> ");
+ final Rect bounds = new Rect();
+ node.getBoundsInScreen(bounds);
+ out.append(bounds.toShortString());
+ }
+
+ /**
+ * Produce a displayable string from a CharSequence
+ */
+ private static String escape(CharSequence s) {
+ final StringBuilder out = new StringBuilder();
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if ((c < 127) || (c == 0xa0) || ((c >= 0x2000) && (c < 0x2070))) {
+ out.append(c);
+ } else {
+ out.append("\\u").append(Integer.toHexString(c));
+ }
+ }
+ return out.toString();
+ }
+
+ private void assertNotEmpty(String name) {
+ assertFalse("Expected non empty name.", TextUtils.isEmpty(name));
+ }
+}
diff --git a/tests/accessibility/common/src/android/accessibility/cts/common/InstrumentedAccessibilityService.java b/tests/accessibility/common/src/android/accessibility/cts/common/InstrumentedAccessibilityService.java
index 3f9a344..cbfb570 100644
--- a/tests/accessibility/common/src/android/accessibility/cts/common/InstrumentedAccessibilityService.java
+++ b/tests/accessibility/common/src/android/accessibility/cts/common/InstrumentedAccessibilityService.java
@@ -52,7 +52,7 @@
// Match com.android.server.accessibility.AccessibilityManagerService#COMPONENT_NAME_SEPARATOR
private static final String COMPONENT_NAME_SEPARATOR = ":";
- private static final int TIMEOUT_SERVICE_PERFORM_SYNC = DEBUG ? Integer.MAX_VALUE : 5000;
+ private static final int TIMEOUT_SERVICE_PERFORM_SYNC = DEBUG ? Integer.MAX_VALUE : 10000;
private static final HashMap<Class, WeakReference<InstrumentedAccessibilityService>>
sInstances = new HashMap<>();
@@ -119,13 +119,14 @@
public <T extends Object> T getOnService(Callable<T> callable) {
AtomicReference<T> returnValue = new AtomicReference<>(null);
AtomicReference<Throwable> throwable = new AtomicReference<>(null);
- runOnServiceSync(() -> {
- try {
- returnValue.set(callable.call());
- } catch (Throwable e) {
- throwable.set(e);
- }
- });
+ runOnServiceSync(
+ () -> {
+ try {
+ returnValue.set(callable.call());
+ } catch (Throwable e) {
+ throwable.set(e);
+ }
+ });
if (throwable.get() != null) {
throw new RuntimeException(throwable.get());
}
@@ -170,21 +171,23 @@
Instrumentation instrumentation, Class<T> clazz) {
final String serviceName = clazz.getSimpleName();
final Context context = instrumentation.getContext();
- final String enabledServices = Settings.Secure.getString(
- context.getContentResolver(),
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+ final String enabledServices =
+ Settings.Secure.getString(
+ context.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
if (enabledServices != null) {
assertFalse("Service is already enabled", enabledServices.contains(serviceName));
}
- final AccessibilityManager manager = (AccessibilityManager) context.getSystemService(
- Context.ACCESSIBILITY_SERVICE);
+ final AccessibilityManager manager =
+ (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
final List<AccessibilityServiceInfo> serviceInfos =
manager.getInstalledAccessibilityServiceList();
for (AccessibilityServiceInfo serviceInfo : serviceInfos) {
final String serviceId = serviceInfo.getId();
if (serviceId.endsWith(serviceName)) {
ShellCommandBuilder.create(instrumentation)
- .putSecureSetting(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ .putSecureSetting(
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
enabledServices + COMPONENT_NAME_SEPARATOR + serviceId)
.putSecureSetting(Settings.Secure.ACCESSIBILITY_ENABLED, "1")
.run();
@@ -192,11 +195,15 @@
final T instance = getInstanceForClass(clazz, TIMEOUT_SERVICE_ENABLE);
if (instance == null) {
ShellCommandBuilder.create(instrumentation)
- .putSecureSetting(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- enabledServices)
+ .putSecureSetting(
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServices)
.run();
- throw new RuntimeException("Starting accessibility service " + serviceName
- + " took longer than " + TIMEOUT_SERVICE_ENABLE + "ms");
+ throw new RuntimeException(
+ "Starting accessibility service "
+ + serviceName
+ + " took longer than "
+ + TIMEOUT_SERVICE_ENABLE
+ + "ms");
}
return instance;
}
@@ -204,8 +211,8 @@
throw new RuntimeException("Accessibility service " + serviceName + " not found");
}
- public static <T extends InstrumentedAccessibilityService> T getInstanceForClass(Class clazz,
- long timeoutMillis) {
+ public static <T extends InstrumentedAccessibilityService> T getInstanceForClass(
+ Class clazz, long timeoutMillis) {
final long timeoutTimeMillis = SystemClock.uptimeMillis() + timeoutMillis;
while (SystemClock.uptimeMillis() < timeoutTimeMillis) {
synchronized (sInstances) {
@@ -235,12 +242,13 @@
(AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
// Updates to manager.isEnabled() aren't synchronized
final AtomicBoolean accessibilityEnabled = new AtomicBoolean(manager.isEnabled());
- manager.addAccessibilityStateChangeListener(b -> {
- synchronized (waitLockForA11yOff) {
- waitLockForA11yOff.notifyAll();
- accessibilityEnabled.set(b);
- }
- });
+ manager.addAccessibilityStateChangeListener(
+ b -> {
+ synchronized (waitLockForA11yOff) {
+ waitLockForA11yOff.notifyAll();
+ accessibilityEnabled.set(b);
+ }
+ });
final UiAutomation uiAutomation = instrumentation.getUiAutomation(
UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
ShellCommandBuilder.create(uiAutomation)
diff --git a/tests/accessibility/common/src/android/accessibility/cts/common/ShellCommandBuilder.java b/tests/accessibility/common/src/android/accessibility/cts/common/ShellCommandBuilder.java
index c305ceb..cfeb1fd 100644
--- a/tests/accessibility/common/src/android/accessibility/cts/common/ShellCommandBuilder.java
+++ b/tests/accessibility/common/src/android/accessibility/cts/common/ShellCommandBuilder.java
@@ -21,6 +21,8 @@
import android.os.ParcelFileDescriptor;
import android.util.Log;
+import com.android.compatibility.common.util.SystemUtil;
+
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
@@ -88,6 +90,25 @@
return this;
}
+ public ShellCommandBuilder addCommandPrintOnLogCat(String command) {
+ mCommands.add(() -> {
+ execShellCommandAndPrintOnLogcat(mUiAutomation, command);
+ });
+ return this;
+ }
+
+ public static void execShellCommandAndPrintOnLogcat(UiAutomation automation, String command) {
+ Log.i(LOG_TAG, "command [" + command + "]");
+ try {
+ final String output = SystemUtil.runShellCommand(automation, command);
+ for (String line : output.split("\\n", -1)) {
+ Log.i(LOG_TAG, line);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to exec shell command [" + command + "]", e);
+ }
+ }
+
public static void execShellCommand(UiAutomation automation, String command) {
Log.i(LOG_TAG, "command [" + command + "]");
try (ParcelFileDescriptor fd = automation.executeShellCommand(command)) {
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityDelegateTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityDelegateTest.java
index fcc4f6e..d3b6162 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityDelegateTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityDelegateTest.java
@@ -22,6 +22,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
@@ -36,6 +37,7 @@
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
/**
@@ -47,10 +49,17 @@
private LinearLayout mParentView;
private View mChildView;
- @Rule
- public ActivityTestRule<DummyActivity> mActivityRule =
+ private ActivityTestRule<DummyActivity> mActivityRule =
new ActivityTestRule<>(DummyActivity.class, false, false);
+ private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
+ @Rule
+ public final RuleChain mRuleChain = RuleChain
+ .outerRule(mDumpOnFailureRule)
+ .around(mActivityRule);
+
@Before
public void setUp() throws Exception {
Activity activity = mActivityRule.launchActivity(null);
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
index 509092f..b140f37 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
@@ -16,27 +16,45 @@
package android.view.accessibility.cts;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.os.Message;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
import android.text.TextUtils;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityRecord;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import junit.framework.TestCase;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
/**
* Class for testing {@link AccessibilityEvent}.
*/
@Presubmit
-public class AccessibilityEventTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityEventTest {
+
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
/**
* Tests whether accessibility events are correctly written and
* read from a parcel (version 1).
*/
@SmallTest
+ @Test
public void testMarshaling() throws Exception {
// fully populate the event to marshal
AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
@@ -58,6 +76,7 @@
* Tests if {@link AccessibilityEvent} are properly reused.
*/
@SmallTest
+ @Test
public void testReuse() {
AccessibilityEvent firstEvent = AccessibilityEvent.obtain();
firstEvent.recycle();
@@ -69,6 +88,7 @@
* Tests if {@link AccessibilityEvent} are properly recycled.
*/
@SmallTest
+ @Test
public void testRecycle() {
// obtain and populate an event
AccessibilityEvent populatedEvent = AccessibilityEvent.obtain();
@@ -86,6 +106,7 @@
* Tests whether the event types are correctly converted to strings.
*/
@SmallTest
+ @Test
public void testEventTypeToString() {
assertEquals("TYPE_NOTIFICATION_STATE_CHANGED", AccessibilityEvent.eventTypeToString(
AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED));
@@ -123,6 +144,7 @@
* Tests whether the event describes its contents consistently.
*/
@SmallTest
+ @Test
public void testDescribeContents() {
AccessibilityEvent event = AccessibilityEvent.obtain();
assertSame("Accessibility events always return 0 for this method.", 0,
@@ -137,6 +159,7 @@
* read from a parcel (version 2).
*/
@SmallTest
+ @Test
public void testMarshaling2() {
AccessibilityEvent marshaledEvent = AccessibilityEvent.obtain();
fullyPopulateAccessibilityEvent(marshaledEvent);
@@ -155,6 +178,7 @@
* can't change the object by changing the objects backing CharSequence
*/
@SmallTest
+ @Test
public void testChangeTextAfterSetting_shouldNotAffectEvent() {
final String originalText = "Cassowary";
final String newText = "Hornbill";
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index a681baf..ee0d4de 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -28,6 +28,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibility.cts.common.InstrumentedAccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Instrumentation;
@@ -52,6 +53,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -65,6 +67,10 @@
@RunWith(AndroidJUnit4.class)
public class AccessibilityManagerTest {
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
private static final Instrumentation sInstrumentation =
InstrumentationRegistry.getInstrumentation();
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
index 0923a92..c7c9b0d 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
@@ -16,13 +16,20 @@
package android.view.accessibility.cts;
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
import android.text.InputType;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -35,6 +42,13 @@
import android.view.accessibility.AccessibilityNodeInfo.RangeInfo;
import android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -43,9 +57,15 @@
* Class for testing {@link AccessibilityNodeInfo}.
*/
@Presubmit
-public class AccessibilityNodeInfoTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityNodeInfoTest {
+
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
@SmallTest
+ @Test
public void testMarshaling() throws Exception {
// fully populate the node info to marshal
AccessibilityNodeInfo sentInfo = AccessibilityNodeInfo.obtain(new View(getContext()));
@@ -67,6 +87,7 @@
* Tests if {@link AccessibilityNodeInfo}s are properly reused.
*/
@SmallTest
+ @Test
public void testReuse() {
AccessibilityEvent firstInfo = AccessibilityEvent.obtain();
firstInfo.recycle();
@@ -78,6 +99,7 @@
* Tests if {@link AccessibilityNodeInfo} are properly recycled.
*/
@SmallTest
+ @Test
public void testRecycle() {
// obtain and populate an node info
AccessibilityNodeInfo populatedInfo = AccessibilityNodeInfo.obtain();
@@ -95,6 +117,7 @@
* Tests whether the event describes its contents consistently.
*/
@SmallTest
+ @Test
public void testDescribeContents() {
AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
assertSame("Accessibility node infos always return 0 for this method.", 0,
@@ -108,6 +131,7 @@
* Tests whether accessibility actions are properly added.
*/
@SmallTest
+ @Test
public void testAddActions() {
List<AccessibilityAction> customActions = new ArrayList<AccessibilityAction>();
customActions.add(new AccessibilityAction(AccessibilityNodeInfo.ACTION_FOCUS, "Foo"));
@@ -133,6 +157,7 @@
* Tests whether we catch addition of an action with invalid id.
*/
@SmallTest
+ @Test
public void testCreateInvalidActionId() {
try {
new AccessibilityAction(3, null);
@@ -145,6 +170,7 @@
* Tests whether accessibility actions are properly removed.
*/
@SmallTest
+ @Test
public void testRemoveActions() {
AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
@@ -173,6 +199,7 @@
* can't change the object by changing the objects backing CharSequence
*/
@SmallTest
+ @Test
public void testChangeTextAfterSetting_shouldNotAffectInfo() {
final String originalText = "Cassowaries";
final String newText = "Hornbill";
@@ -191,6 +218,7 @@
}
@SmallTest
+ @Test
public void testIsHeadingTakesOldApiIntoAccount() {
final AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
assertFalse(info.isHeading());
@@ -399,11 +427,11 @@
(receivedRange != null));
if (expectedRange != null) {
assertEquals("RangeInfo#getCurrent has incorrect value", expectedRange.getCurrent(),
- receivedRange.getCurrent());
+ receivedRange.getCurrent(), 0.0);
assertEquals("RangeInfo#getMin has incorrect value", expectedRange.getMin(),
- receivedRange.getMin());
+ receivedRange.getMin(), 0.0);
assertEquals("RangeInfo#getMax has incorrect value", expectedRange.getMax(),
- receivedRange.getMax());
+ receivedRange.getMax(), 0.0);
assertEquals("RangeInfo#getType has incorrect value", expectedRange.getType(),
receivedRange.getType());
}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_CollectionInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_CollectionInfoTest.java
index 98b87fc..cabfd98 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_CollectionInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_CollectionInfoTest.java
@@ -16,18 +16,34 @@
package android.view.accessibility.cts;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.platform.test.annotations.Presubmit;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
/**
* Class for testing {@link CollectionInfo}.
*/
@Presubmit
-public class AccessibilityNodeInfo_CollectionInfoTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityNodeInfo_CollectionInfoTest {
+
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
@SmallTest
+ @Test
public void testObtain() {
CollectionInfo c;
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_RangeInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_RangeInfoTest.java
index 4b01129..e7761f4 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_RangeInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_RangeInfoTest.java
@@ -16,22 +16,36 @@
package android.view.accessibility.cts;
+import static org.junit.Assert.assertEquals;
+
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.platform.test.annotations.Presubmit;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.RangeInfo;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
/**
* Class for testing {@link AccessibilityNodeInfo.RangeInfo}.
*/
@Presubmit
-public class AccessibilityNodeInfo_RangeInfoTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityNodeInfo_RangeInfoTest {
/** Allowed tolerance for floating point equality comparisons. */
public static final float FLOAT_TOLERANCE = 0.001f;
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
@SmallTest
+ @Test
public void testObtain() {
RangeInfo r;
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeProviderTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeProviderTest.java
index 0c2a2dd..60bc1a3 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeProviderTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeProviderTest.java
@@ -16,17 +16,33 @@
package android.view.accessibility.cts;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.platform.test.annotations.Presubmit;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
import android.view.accessibility.AccessibilityNodeProvider;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
/**
* Class for testing {@link AccessibilityNodeProvider}.
*/
@Presubmit
-public class AccessibilityNodeProviderTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityNodeProviderTest {
+
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
@SmallTest
+ @Test
public void testDefaultBehavior() {
AccessibilityNodeProvider p = new AccessibilityNodeProvider() {
// Class is abstract, but has no abstract methods.
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
index 72bb4e0..7ae8070 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
@@ -16,17 +16,23 @@
package android.view.accessibility.cts;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.os.Message;
import android.platform.test.annotations.Presubmit;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityRecord;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import junit.framework.TestCase;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.Iterator;
import java.util.List;
@@ -34,11 +40,18 @@
* Class for testing {@link AccessibilityRecord}.
*/
@Presubmit
-public class AccessibilityRecordTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityRecordTest {
+
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
/**
* Tests the cloning obtain method.
*/
@SmallTest
+ @Test
public void testObtain() {
AccessibilityRecord originalRecord = AccessibilityRecord.obtain();
fullyPopulateAccessibilityRecord(originalRecord);
@@ -50,6 +63,7 @@
* Tests if {@link AccessibilityRecord}s are properly recycled.
*/
@SmallTest
+ @Test
public void testRecycle() {
// obtain and populate an event
AccessibilityRecord populatedRecord = AccessibilityRecord.obtain();
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
index 0029b53..d80ba5c 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
@@ -16,14 +16,29 @@
package android.view.accessibility.cts;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibility.cts.common.InstrumentedAccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Service;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.List;
/**
@@ -33,15 +48,20 @@
* accessibility service and the fake service used for implementing the UI
* automation is not reported through the APIs.
*/
-public class AccessibilityServiceInfoTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityServiceInfoTest {
- @Override
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
+ @Before
public void setUp() throws Exception {
SpeakingAccessibilityService.enableSelf(getInstrumentation());
VibratingAccessibilityService.enableSelf(getInstrumentation());
}
- @Override
+ @After
public void tearDown() {
InstrumentedAccessibilityService.disableAllServices(getInstrumentation());
}
@@ -52,6 +72,7 @@
*/
@MediumTest
@SuppressWarnings("deprecation")
+ @Test
public void testAccessibilityServiceInfoForEnabledService() {
AccessibilityManager accessibilityManager = (AccessibilityManager)
getInstrumentation().getContext().getSystemService(Service.ACCESSIBILITY_SERVICE);
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java
index e959544..f391263 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java
@@ -16,21 +16,41 @@
package android.view.accessibility.cts;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.graphics.Rect;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
import android.text.TextUtils;
import android.view.accessibility.AccessibilityWindowInfo;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
/**
* Class for testing {@link AccessibilityWindowInfo}.
*/
@Presubmit
-public class AccessibilityWindowInfoTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityWindowInfoTest {
+
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
@SmallTest
+ @Test
public void testObtain() {
AccessibilityWindowInfo w1 = AccessibilityWindowInfo.obtain();
assertNotNull(w1);
@@ -41,6 +61,7 @@
}
@SmallTest
+ @Test
public void testParceling() {
Parcel parcel = Parcel.obtain();
AccessibilityWindowInfo w1 = AccessibilityWindowInfo.obtain();
@@ -53,6 +74,7 @@
}
@SmallTest
+ @Test
public void testDefaultValues() {
AccessibilityWindowInfo w = AccessibilityWindowInfo.obtain();
assertEquals(0, w.getChildCount());
@@ -80,6 +102,7 @@
}
@SmallTest
+ @Test
public void testRecycle() {
AccessibilityWindowInfo w = AccessibilityWindowInfo.obtain();
w.recycle();
diff --git a/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
index d0db868..c3054ef 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
@@ -16,6 +16,12 @@
package android.view.accessibility.cts;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.anyFloat;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.mock;
@@ -23,13 +29,19 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.app.UiAutomation;
import android.os.ParcelFileDescriptor;
-import android.test.InstrumentationTestCase;
import android.view.accessibility.CaptioningManager;
import android.view.accessibility.CaptioningManager.CaptionStyle;
import android.view.accessibility.CaptioningManager.CaptioningChangeListener;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mockito;
import java.io.FileInputStream;
@@ -40,15 +52,19 @@
/**
* Tests whether the CaptioningManager APIs are functional.
*/
-public class CaptioningManagerTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class CaptioningManagerTest {
+
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
private static final int LISTENER_TIMEOUT = 3000;
private CaptioningManager mManager;
private UiAutomation mUiAutomation;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
+ @Before
+ public void setUp() throws Exception {
mManager = getInstrumentation().getTargetContext().getSystemService(
CaptioningManager.class);
@@ -60,6 +76,7 @@
/**
* Tests whether a client can observe changes in caption properties.
*/
+ @Test
public void testChangeListener() {
putSecureSetting("accessibility_captioning_enabled","0");
putSecureSetting("accessibility_captioning_preset", "1");
@@ -97,16 +114,18 @@
}
}
+ @Test
public void testProperties() {
putSecureSetting("accessibility_captioning_font_scale", "2.0");
putSecureSetting("accessibility_captioning_locale", "ja_JP");
putSecureSetting("accessibility_captioning_enabled", "1");
- assertEquals("Test runner set font scale to 2.0", 2.0f, mManager.getFontScale());
+ assertEquals("Test runner set font scale to 2.0", 2.0f, mManager.getFontScale(), 0f);
assertEquals("Test runner set locale to Japanese", Locale.JAPAN, mManager.getLocale());
assertEquals("Test runner set enabled to true", true, mManager.isEnabled());
}
+ @Test
public void testUserStyle() {
putSecureSetting("accessibility_captioning_preset", "-1");
putSecureSetting("accessibility_captioning_foreground_color", "511");
diff --git a/tests/accessibilityservice/Android.bp b/tests/accessibilityservice/Android.bp
index 527ce29..40b928c 100644
--- a/tests/accessibilityservice/Android.bp
+++ b/tests/accessibilityservice/Android.bp
@@ -19,6 +19,7 @@
"ctstestrunner-axt",
"hamcrest-library",
"mockito-target-minus-junit4",
+ "compatibility-device-util-axt",
"platform-test-annotations",
"CtsAccessibilityCommon",
],
diff --git a/tests/accessibilityservice/AndroidManifest.xml b/tests/accessibilityservice/AndroidManifest.xml
index fc0b2e6..f4227c1 100644
--- a/tests/accessibilityservice/AndroidManifest.xml
+++ b/tests/accessibilityservice/AndroidManifest.xml
@@ -20,10 +20,12 @@
android:targetSandboxVersion="2">
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
- <application android:theme="@android:style/Theme.Holo.NoActionBar">
+ <application android:theme="@android:style/Theme.Holo.NoActionBar"
+ android:requestLegacyExternalStorage="true">
<uses-library android:name="android.test.runner" />
@@ -67,6 +69,15 @@
android:label="@string/accessibility_soft_keyboard_modes_activity"
android:name=".AccessibilitySoftKeyboardModesTest$SoftKeyboardModesActivity" />
+ <activity
+ android:label="@string/accessibility_embedded_display_test_parent_activity"
+ android:name=".AccessibilityEmbeddedDisplayTest$EmbeddedDisplayParentActivity"
+ android:theme="@android:style/Theme.Dialog" />
+
+ <activity
+ android:label="@string/accessibility_embedded_display_test_activity"
+ android:name=".AccessibilityEmbeddedDisplayTest$EmbeddedDisplayActivity" />
+
<service
android:name=".StubGestureAccessibilityService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
@@ -93,6 +104,17 @@
</service>
<service
+ android:name=".TouchExplorationStubAccessibilityService"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService" />
+ <category android:name="android.accessibilityservice.category.FEEDBACK_GENERIC" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accessibilityservice"
+ android:resource="@xml/stub_touch_exploration_a11y_service" />
+ </service>
+ <service
android:name="android.accessibility.cts.common.InstrumentedAccessibilityService"
android:label="@string/title_soft_keyboard_modes_accessibility_service"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
diff --git a/tests/accessibilityservice/AndroidTest.xml b/tests/accessibilityservice/AndroidTest.xml
index eb75538..b0e873c 100644
--- a/tests/accessibilityservice/AndroidTest.xml
+++ b/tests/accessibilityservice/AndroidTest.xml
@@ -34,4 +34,8 @@
<option name="package" value="android.accessibilityservice.cts" />
<option name="runtime-hint" value="2m12s" />
</test>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/sdcard/android.accessibilityservice.cts" />
+ <option name="collect-on-run-ended-only" value="true" />
+ </metrics_collector>
</configuration>
diff --git a/tests/accessibilityservice/res/layout/accessibility_embedded_display_test.xml b/tests/accessibilityservice/res/layout/accessibility_embedded_display_test.xml
new file mode 100644
index 0000000..666bfbe
--- /dev/null
+++ b/tests/accessibilityservice/res/layout/accessibility_embedded_display_test.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <Button
+ android:id="@+id/button"
+ android:text="@string/button_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+</LinearLayout>
diff --git a/tests/accessibilityservice/res/layout/accessibility_view_tree_reporting_test.xml b/tests/accessibilityservice/res/layout/accessibility_view_tree_reporting_test.xml
index 0dbd62a..e05c259 100644
--- a/tests/accessibilityservice/res/layout/accessibility_view_tree_reporting_test.xml
+++ b/tests/accessibilityservice/res/layout/accessibility_view_tree_reporting_test.xml
@@ -88,6 +88,14 @@
android:text="@string/secondButton"
android:textSize="10dip" />
+ <Button
+ android:id="@+id/hiddenButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/secondButton"
+ android:textSize="10dip"
+ android:visibility="gone" />
+
</LinearLayout>
</FrameLayout>
diff --git a/tests/accessibilityservice/res/values/strings.xml b/tests/accessibilityservice/res/values/strings.xml
index ad5d3fd..3fd45bd 100644
--- a/tests/accessibilityservice/res/values/strings.xml
+++ b/tests/accessibilityservice/res/values/strings.xml
@@ -147,7 +147,9 @@
<string name="stub_gesture_dispatch_a11y_service_description">com.android.accessibilityservice.cts.StubGestureAccessibilityService</string>
- <string name="stub_gesture_detector_a11y_service_description">com.android.accessibilityservice.cts.StubService</string>
+ <string name="stub_gesture_detector_a11y_service_description">com.android.accessibilityservice.cts.GestureDetectionStubAccessibilityService</string>
+
+ <string name="stub_touch_exploration_a11y_service_description">com.android.accessibilityservice.cts.TouchExplorationStubAccessibilityService</string>
<string name="stub_fprint_a11y_service_description">com.android.accessibilityservice.cts.StubFingerprintGestureAccessibilityService</string>
@@ -170,4 +172,12 @@
<!-- Description of the accessibility service -->
<string name="soft_keyboard_modes_accessibility_service_description">This Accessibility Service was installed for testing purposes. It can be uninstalled by going to Settings > Apps > android.view.accessibilityservice.services and selecting \"Uninstall\".</string>
+ <!-- AccessibilityEmbeddedDisplayTest -->
+
+ <!-- String title of accessibility embedded display test parent window activity -->
+ <string name="accessibility_embedded_display_test_parent_activity">Embedded display test parent</string>
+
+ <!-- String title of accessibility embedded display test activity -->
+ <string name="accessibility_embedded_display_test_activity">Embedded display test</string>
+
</resources>
diff --git a/tests/accessibilityservice/res/xml/stub_touch_exploration_a11y_service.xml b/tests/accessibilityservice/res/xml/stub_touch_exploration_a11y_service.xml
new file mode 100644
index 0000000..33c5ec8
--- /dev/null
+++ b/tests/accessibilityservice/res/xml/stub_touch_exploration_a11y_service.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<accessibility-service
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:description="@string/stub_touch_exploration_a11y_service_description"
+ android:accessibilityEventTypes="typeAllMask"
+ android:accessibilityFeedbackType="feedbackGeneric"
+ android:accessibilityFlags="flagDefault|flagRequestTouchExplorationMode|flagReportViewIds"
+ android:canRequestTouchExplorationMode="true"
+ android:canRetrieveWindowContent="true"
+ android:canPerformGestures="true" />
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityButtonTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityButtonTest.java
index 84fb0ef..6b758c0 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityButtonTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityButtonTest.java
@@ -16,6 +16,7 @@
import static android.accessibilityservice.cts.utils.CtsTestUtils.runIfNotNull;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibilityservice.AccessibilityButtonController;
import android.app.Instrumentation;
import android.platform.test.annotations.AppModeFull;
@@ -25,6 +26,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -37,6 +39,10 @@
@RunWith(AndroidJUnit4.class)
public class AccessibilityButtonTest {
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
private StubAccessibilityButtonService mService;
private AccessibilityButtonController mButtonController;
private AccessibilityButtonController.AccessibilityButtonCallback mStubCallback =
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedDisplayTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedDisplayTest.java
new file mode 100644
index 0000000..c3c1efc
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedDisplayTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.accessibilityservice.cts;
+
+import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.findWindowByTitle;
+import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen;
+import static android.accessibilityservice.cts.utils.AsyncUtils.DEFAULT_TIMEOUT_MS;
+import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
+import android.accessibilityservice.cts.activities.AccessibilityTestActivity;
+import android.app.Activity;
+import android.app.ActivityView;
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.platform.test.annotations.Presubmit;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityWindowInfo;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests that AccessibilityWindowInfos and AccessibilityNodeInfos from a window on an embedded
+ * display that is re-parented to another window are properly populated.
+ */
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityEmbeddedDisplayTest {
+ private static Instrumentation sInstrumentation;
+ private static UiAutomation sUiAutomation;
+
+ private EmbeddedDisplayParentActivity mActivity;
+ private ActivityView mActivityView;
+ private Context mContext;
+
+ private String mParentActivityTitle;
+ private String mActivityTitle;
+
+ private final ActivityTestRule<EmbeddedDisplayParentActivity> mActivityRule =
+ new ActivityTestRule<>(EmbeddedDisplayParentActivity.class, false, false);
+
+ private final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
+ @Rule
+ public final RuleChain mRuleChain = RuleChain
+ .outerRule(mDumpOnFailureRule)
+ .around(mActivityRule);
+
+ @BeforeClass
+ public static void oneTimeSetup() throws Exception {
+ sInstrumentation = InstrumentationRegistry.getInstrumentation();
+ sUiAutomation = sInstrumentation.getUiAutomation();
+ }
+
+ @AfterClass
+ public static void postTestTearDown() {
+ sUiAutomation.destroy();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = sInstrumentation.getContext();
+ assumeTrue(supportsMultiDisplay());
+
+ mParentActivityTitle = mContext.getString(
+ R.string.accessibility_embedded_display_test_parent_activity);
+ mActivityTitle = mContext.getString(R.string.accessibility_embedded_display_test_activity);
+
+ SystemUtil.runWithShellPermissionIdentity(() -> {
+ mActivity = launchActivityAndWaitForItToBeOnscreen(
+ sInstrumentation, sUiAutomation, mActivityRule);
+ mActivityView = mActivity.getActivityView();
+ });
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mActivityView != null) {
+ SystemUtil.runWithShellPermissionIdentity(() -> mActivityView.release());
+ }
+ }
+
+ @Presubmit
+ @Test
+ public void testA11yWindowInfoHasCorrectLayer() throws Exception {
+ launchActivityInActivityView();
+
+ assertTrue(findWindowByTitle(sUiAutomation, mActivityTitle).getLayer()
+ > findWindowByTitle(sUiAutomation, mParentActivityTitle).getLayer());
+ }
+
+ @Presubmit
+ @Test
+ public void testA11yWindowInfoAndA11yNodeInfoHasCorrectBoundsInScreen() throws Exception {
+ launchActivityInActivityView();
+
+ final AccessibilityNodeInfo button = findWindowByTitle(sUiAutomation,
+ mActivityTitle).getRoot().findAccessibilityNodeInfosByViewId(
+ "android.accessibilityservice.cts:id/button").get(0);
+ final Rect parentActivityBound = getWindowBoundByTitle(mParentActivityTitle);
+ final Rect activityBound = getWindowBoundByTitle(mActivityTitle);
+ final Rect buttonBound = new Rect();
+ button.getBoundsInScreen(buttonBound);
+
+ assertTrue(parentActivityBound.contains(activityBound));
+ assertTrue(parentActivityBound.contains(buttonBound));
+ }
+
+ private void launchActivityInActivityView() throws Exception {
+ final Rect bounds = new Rect();
+ sUiAutomation.executeAndWaitForEvent(
+ () -> sInstrumentation.runOnMainSync(() -> {
+ Intent intent = new Intent(mContext, EmbeddedDisplayActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> mActivityView.startActivity(intent));
+ }),
+ (event) -> {
+ // Ensure the target activity is shown
+ final AccessibilityWindowInfo window =
+ findWindowByTitle(sUiAutomation, mContext.getString(
+ R.string.accessibility_embedded_display_test_activity));
+ if (window == null) {
+ return false;
+ }
+ window.getBoundsInScreen(bounds);
+ return !bounds.isEmpty();
+ }, DEFAULT_TIMEOUT_MS);
+ }
+
+ private Rect getWindowBoundByTitle(String title) {
+ final AccessibilityWindowInfo window = findWindowByTitle(sUiAutomation, title);
+ final Rect bound = new Rect();
+ window.getBoundsInScreen(bound);
+ return bound;
+ }
+
+ private boolean supportsMultiDisplay() {
+ return mContext.getPackageManager().hasSystemFeature(
+ FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS);
+ }
+
+ public static class EmbeddedDisplayParentActivity extends Activity {
+ private ActivityView mActivityView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mActivityView = new ActivityView(this);
+ setContentView(mActivityView);
+ }
+
+ ActivityView getActivityView() {
+ return mActivityView;
+ }
+ }
+
+ public static class EmbeddedDisplayActivity extends AccessibilityTestActivity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.accessibility_embedded_display_test);
+ }
+ }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
index 60ef850..142b1cf 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -45,6 +45,7 @@
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibility.cts.common.InstrumentedAccessibilityService;
import android.accessibility.cts.common.ShellCommandBuilder;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -101,6 +102,7 @@
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import java.util.Iterator;
@@ -131,10 +133,17 @@
private AccessibilityEndToEndActivity mActivity;
- @Rule
- public ActivityTestRule<AccessibilityEndToEndActivity> mActivityRule =
+ private ActivityTestRule<AccessibilityEndToEndActivity> mActivityRule =
new ActivityTestRule<>(AccessibilityEndToEndActivity.class, false, false);
+ private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
+ @Rule
+ public final RuleChain mRuleChain = RuleChain
+ .outerRule(mDumpOnFailureRule)
+ .around(mActivityRule);
+
@BeforeClass
public static void oneTimeSetup() throws Exception {
sInstrumentation = InstrumentationRegistry.getInstrumentation();
@@ -504,6 +513,7 @@
.getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
InstrumentedAccessibilityService service = InstrumentedAccessibilityService.enableService(
sInstrumentation, InstrumentedAccessibilityService.class);
+
try {
assertFalse(service.wasOnInterruptCalled());
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFingerprintGestureTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFingerprintGestureTest.java
index 1db66a2..0dc118c 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFingerprintGestureTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFingerprintGestureTest.java
@@ -23,6 +23,7 @@
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibilityservice.FingerprintGestureController;
import android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback;
import android.accessibilityservice.cts.activities.AccessibilityEndToEndActivity;
@@ -39,6 +40,7 @@
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -57,10 +59,16 @@
FingerprintGestureController mFingerprintGestureController;
CancellationSignal mCancellationSignal = new CancellationSignal();
- @Rule
- public ActivityTestRule<AccessibilityEndToEndActivity> mActivityRule =
+ private ActivityTestRule<AccessibilityEndToEndActivity> mActivityRule =
new ActivityTestRule<>(AccessibilityEndToEndActivity.class, false, false);
+ private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
+ @Rule
+ public final RuleChain mRuleChain = RuleChain
+ .outerRule(mDumpOnFailureRule)
+ .around(mActivityRule);
@Mock FingerprintManager.AuthenticationCallback mMockAuthenticationCallback;
@Mock FingerprintGestureCallback mMockFingerprintGestureCallback;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java
index 43c12e9..7d5146a 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java
@@ -26,8 +26,8 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibilityservice.AccessibilityServiceInfo;
-import android.accessibilityservice.cts.R;
import android.accessibilityservice.cts.activities.AccessibilityFocusAndInputFocusSyncActivity;
import android.app.Instrumentation;
import android.app.UiAutomation;
@@ -46,6 +46,7 @@
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import java.util.LinkedList;
@@ -65,10 +66,17 @@
private AccessibilityFocusAndInputFocusSyncActivity mActivity;
- @Rule
- public ActivityTestRule<AccessibilityFocusAndInputFocusSyncActivity> mActivityRule =
+ private ActivityTestRule<AccessibilityFocusAndInputFocusSyncActivity> mActivityRule =
new ActivityTestRule<>(AccessibilityFocusAndInputFocusSyncActivity.class, false, false);
+ private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
+ @Rule
+ public final RuleChain mRuleChain = RuleChain
+ .outerRule(mDumpOnFailureRule)
+ .around(mActivityRule);
+
@BeforeClass
public static void oneTimeSetup() throws Exception {
sInstrumentation = InstrumentationRegistry.getInstrumentation();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
index 24c00ff..a1307ba 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
@@ -25,6 +25,7 @@
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.GestureDescription;
import android.accessibilityservice.GestureDescription.StrokeDescription;
@@ -44,6 +45,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -59,6 +61,10 @@
private static final long GESTURE_DISPATCH_TIMEOUT_MS = 3000;
private static final long EVENT_DISPATCH_TIMEOUT_MS = 3000;
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
// Test AccessibilityService that collects gestures.
GestureDetectionStubAccessibilityService mService;
boolean mHasTouchScreen;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
index 757be1b..096878d 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
@@ -14,6 +14,7 @@
package android.accessibilityservice.cts;
+import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen;
import static android.accessibilityservice.cts.utils.AsyncUtils.await;
import static android.accessibilityservice.cts.utils.AsyncUtils.awaitCancellation;
import static android.accessibilityservice.cts.utils.CtsTestUtils.runIfNotNull;
@@ -26,19 +27,25 @@
import static android.accessibilityservice.cts.utils.GestureUtils.path;
import static android.accessibilityservice.cts.utils.GestureUtils.times;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.any;
import static org.hamcrest.CoreMatchers.both;
import static org.hamcrest.CoreMatchers.everyItem;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.GestureDescription;
import android.accessibilityservice.GestureDescription.StrokeDescription;
import android.accessibilityservice.cts.activities.AccessibilityTestActivity;
+import android.app.Instrumentation;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Matrix;
@@ -47,7 +54,6 @@
import android.os.Bundle;
import android.os.SystemClock;
import android.platform.test.annotations.AppModeFull;
-import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
@@ -56,9 +62,18 @@
import android.view.WindowManager;
import android.widget.TextView;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
@@ -68,8 +83,8 @@
* Verify that gestures dispatched from an accessibility service show up in the current UI
*/
@AppModeFull
-public class AccessibilityGestureDispatchTest extends
- ActivityInstrumentationTestCase2<AccessibilityGestureDispatchTest.GestureDispatchActivity> {
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityGestureDispatchTest {
private static final String TAG = AccessibilityGestureDispatchTest.class.getSimpleName();
private static final int GESTURE_COMPLETION_TIMEOUT = 5000; // millis
@@ -88,6 +103,16 @@
private static final Matcher<MotionEvent> IS_ACTION_MOVE =
new MotionEventActionMatcher(MotionEvent.ACTION_MOVE);
+ private ActivityTestRule<GestureDispatchActivity> mActivityRule =
+ new ActivityTestRule<>(GestureDispatchActivity.class, false, false);
+
+ private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
+ @Rule
+ public final RuleChain mRuleChain = RuleChain
+ .outerRule(mDumpOnFailureRule)
+ .around(mActivityRule);
final List<MotionEvent> mMotionEvents = new ArrayList<>();
StubGestureAccessibilityService mService;
@@ -99,48 +124,46 @@
boolean mHasTouchScreen;
boolean mHasMultiTouch;
- public AccessibilityGestureDispatchTest() {
- super(GestureDispatchActivity.class);
- }
+ private GestureDispatchActivity mActivity;
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
- PackageManager pm = getInstrumentation().getContext().getPackageManager();
+ Instrumentation instrumentation = getInstrumentation();
+ PackageManager pm = instrumentation.getContext().getPackageManager();
mHasTouchScreen = pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
|| pm.hasSystemFeature(PackageManager.FEATURE_FAKETOUCH);
if (!mHasTouchScreen) {
return;
}
- getActivity().waitForEnterAnimationComplete();
+ mActivity = launchActivityAndWaitForItToBeOnscreen(instrumentation,
+ instrumentation.getUiAutomation(), mActivityRule);
mHasMultiTouch = pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)
|| pm.hasSystemFeature(PackageManager.FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT);
- mFullScreenTextView =
- (TextView) getActivity().findViewById(R.id.full_screen_text_view);
+ mFullScreenTextView = mActivity.findViewById(R.id.full_screen_text_view);
getInstrumentation().runOnMainSync(() -> {
mFullScreenTextView.getLocationOnScreen(mViewLocation);
mFullScreenTextView.setOnTouchListener(mMyTouchListener);
});
- mService = StubGestureAccessibilityService.enableSelf(getInstrumentation());
+ mService = StubGestureAccessibilityService.enableSelf(instrumentation);
mMotionEvents.clear();
mGotUpEvent = false;
}
- @Override
+ @After
public void tearDown() throws Exception {
if (!mHasTouchScreen) {
return;
}
runIfNotNull(mService, service -> service.runOnServiceSync(service::disableSelf));
- super.tearDown();
}
+ @Test
public void testClickAt_producesDownThenUp() throws InterruptedException {
if (!mHasTouchScreen) {
return;
@@ -160,10 +183,10 @@
assertEquals(0, clickDown.getActionIndex());
assertEquals(0, clickDown.getDeviceId());
assertEquals(0, clickDown.getEdgeFlags());
- assertEquals(1F, clickDown.getXPrecision());
- assertEquals(1F, clickDown.getYPrecision());
+ assertEquals(1F, clickDown.getXPrecision(), 0F);
+ assertEquals(1F, clickDown.getYPrecision(), 0F);
assertEquals(1, clickDown.getPointerCount());
- assertEquals(1F, clickDown.getPressure());
+ assertEquals(1F, clickDown.getPressure(), 0F);
// Verify timing matches click
assertEquals(clickDown.getDownTime(), clickDown.getEventTime());
@@ -174,6 +197,7 @@
> clickUp.getEventTime());
}
+ @Test
public void testLongClickAt_producesEventsWithLongClickTiming() throws InterruptedException {
if (!mHasTouchScreen) {
return;
@@ -194,6 +218,7 @@
assertEquals(clickDown.getDownTime(), clickUp.getDownTime());
}
+ @Test
public void testSwipe_shouldContainPointsInALine() throws InterruptedException {
if (!mHasTouchScreen) {
return;
@@ -232,6 +257,7 @@
await(dispatchGesture(mService, gesture), timeoutMs, MILLISECONDS);
}
+ @Test
public void testSlowSwipe_shouldNotContainMovesForTinyMovement() throws InterruptedException {
if (!mHasTouchScreen) {
return;
@@ -256,6 +282,7 @@
assertThat(mMotionEvents.get(4), both(IS_ACTION_UP).and(isAtPoint(endPoint)));
}
+ @Test
public void testAngledPinch_looksReasonable() throws InterruptedException {
if (!(mHasTouchScreen && mHasMultiTouch)) {
return;
@@ -305,6 +332,7 @@
// This test assumes device's screen contains its center (W/2, H/2) with some surroundings
// and should work for rectangular, round and round with chin screens.
+ @Test
public void testClickWhenMagnified_matchesActualTouch() throws InterruptedException {
final float POINT_TOL = 2.0f;
final float CLICK_OFFSET_X = 10;
@@ -314,7 +342,7 @@
return;
}
- int displayId = getActivity().getWindow().getDecorView().getDisplay().getDisplayId();
+ int displayId = mActivity.getWindow().getDecorView().getDisplay().getDisplayId();
if (displayId != Display.DEFAULT_DISPLAY) {
Log.i(TAG, "Magnification is not supported on virtual displays.");
return;
@@ -388,6 +416,7 @@
both(IS_ACTION_UP).and(isAtPoint(magRegionOffsetPoint, POINT_TOL)));
}
+ @Test
public void testContinuedGestures_motionEventsContinue() throws Exception {
if (!mHasTouchScreen) {
return;
@@ -422,6 +451,7 @@
allOf(IS_ACTION_UP, isAtPoint(end)));
}
+ @Test
public void testContinuedGesture_withLineDisconnect_isCancelled() throws Exception {
if (!mHasTouchScreen) {
return;
@@ -450,6 +480,7 @@
assertEquals(1, mMotionEvents.size());
}
+ @Test
public void testContinuedGesture_nextGestureDoesntContinue_isCancelled() throws Exception {
if (!mHasTouchScreen) {
return;
@@ -482,6 +513,7 @@
both(IS_ACTION_UP).and(isAtPoint(endPoint)));
}
+ @Test
public void testContinuingGesture_withNothingToContinue_isCancelled() {
if (!mHasTouchScreen) {
return;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
index 5c45080..9379fc5 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
@@ -16,12 +16,22 @@
package android.accessibilityservice.cts;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertTrue;
+
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibilityservice.AccessibilityService;
import android.os.SystemClock;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.Presubmit;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.concurrent.TimeoutException;
@@ -30,7 +40,8 @@
*/
@Presubmit
@AppModeFull
-public class AccessibilityGlobalActionsTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityGlobalActionsTest {
/**
* Timeout required for pending Binder calls or event processing to
* complete.
@@ -42,7 +53,12 @@
*/
private static final long TIMEOUT_ACCESSIBILITY_STATE_IDLE = 500;
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
@MediumTest
+ @Test
public void testPerformGlobalActionBack() throws Exception {
assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
AccessibilityService.GLOBAL_ACTION_BACK));
@@ -52,6 +68,7 @@
}
@MediumTest
+ @Test
public void testPerformGlobalActionHome() throws Exception {
assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
AccessibilityService.GLOBAL_ACTION_HOME));
@@ -61,6 +78,7 @@
}
@MediumTest
+ @Test
public void testPerformGlobalActionRecents() throws Exception {
// Perform the action.
boolean actionWasPerformed =
@@ -85,6 +103,7 @@
}
@MediumTest
+ @Test
public void testPerformGlobalActionNotifications() throws Exception {
// Perform the action under test
assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
@@ -102,6 +121,7 @@
}
@MediumTest
+ @Test
public void testPerformGlobalActionQuickSettings() throws Exception {
// Check whether the action succeeded.
assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
@@ -122,6 +142,7 @@
}
@MediumTest
+ @Test
public void testPerformGlobalActionPowerDialog() throws Exception {
// Check whether the action succeeded.
assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
@@ -139,6 +160,7 @@
}
@MediumTest
+ @Test
public void testPerformActionScreenshot() throws Exception {
// Action should succeed
assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityLoggingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityLoggingTest.java
index 9654352..66baa04 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityLoggingTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityLoggingTest.java
@@ -17,6 +17,7 @@
import static junit.framework.Assert.assertTrue;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.content.Context;
import android.platform.test.annotations.Presubmit;
@@ -25,6 +26,7 @@
import com.android.compatibility.common.util.AppOpsUtils;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -32,6 +34,10 @@
@Presubmit
public class AccessibilityLoggingTest {
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
/**
* Tests that new accessibility services are logged by the system.
*/
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityMagnificationTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityMagnificationTest.java
index 2774457..f0a4209 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityMagnificationTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityMagnificationTest.java
@@ -18,6 +18,11 @@
import static android.accessibilityservice.cts.utils.CtsTestUtils.runIfNotNull;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyFloat;
import static org.mockito.Mockito.eq;
@@ -25,6 +30,7 @@
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibility.cts.common.InstrumentedAccessibilityService;
import android.accessibility.cts.common.ShellCommandBuilder;
import android.accessibilityservice.AccessibilityService.MagnificationController;
@@ -34,7 +40,14 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.platform.test.annotations.AppModeFull;
-import android.test.InstrumentationTestCase;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -42,7 +55,8 @@
* Class for testing {@link AccessibilityServiceInfo}.
*/
@AppModeFull
-public class AccessibilityMagnificationTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityMagnificationTest {
/** Maximum timeout when waiting for a magnification callback. */
public static final int LISTENER_TIMEOUT_MILLIS = 500;
@@ -51,10 +65,13 @@
private StubMagnificationAccessibilityService mService;
private Instrumentation mInstrumentation;
- @Override
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
+ @Before
public void setUp() throws Exception {
- super.setUp();
- ShellCommandBuilder.create(this.getInstrumentation())
+ ShellCommandBuilder.create(getInstrumentation())
.deleteSecureSetting(ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED)
.run();
mInstrumentation = getInstrumentation();
@@ -63,13 +80,12 @@
mService = StubMagnificationAccessibilityService.enableSelf(mInstrumentation);
}
- @Override
- protected void tearDown() throws Exception {
+ @After
+ public void tearDown() throws Exception {
runIfNotNull(mService, service -> service.runOnServiceSync(service::disableSelfAndRemove));
-
- super.tearDown();
}
+ @Test
public void testSetScale() {
final MagnificationController controller = mService.getMagnificationController();
final float scale = 2.0f;
@@ -78,14 +94,15 @@
mService.runOnServiceSync(() -> result.set(controller.setScale(scale, false)));
assertTrue("Failed to set scale", result.get());
- assertEquals("Failed to apply scale", scale, controller.getScale());
+ assertEquals("Failed to apply scale", scale, controller.getScale(), 0f);
mService.runOnServiceSync(() -> result.set(controller.reset(false)));
assertTrue("Failed to reset", result.get());
- assertEquals("Failed to apply reset", 1.0f, controller.getScale());
+ assertEquals("Failed to apply reset", 1.0f, controller.getScale(), 0f);
}
+ @Test
public void testSetScaleAndCenter() {
final MagnificationController controller = mService.getMagnificationController();
final Region region = controller.getMagnificationRegion();
@@ -103,7 +120,7 @@
});
assertTrue("Failed to set scale", setScale.get());
- assertEquals("Failed to apply scale", scale, controller.getScale());
+ assertEquals("Failed to apply scale", scale, controller.getScale(), 0f);
assertTrue("Failed to set center", setCenter.get());
assertEquals("Failed to apply center X", x, controller.getCenterX(), 5.0f);
@@ -112,9 +129,10 @@
mService.runOnServiceSync(() -> result.set(controller.reset(false)));
assertTrue("Failed to reset", result.get());
- assertEquals("Failed to apply reset", 1.0f, controller.getScale());
+ assertEquals("Failed to apply reset", 1.0f, controller.getScale(), 0f);
}
+ @Test
public void testListener() {
final MagnificationController controller = mService.getMagnificationController();
final OnMagnificationChangedListener listener = mock(OnMagnificationChangedListener.class);
@@ -140,6 +158,7 @@
}
}
+ @Test
public void testMagnificationServiceShutsDownWhileMagnifying_shouldReturnTo1x() {
final MagnificationController controller = mService.getMagnificationController();
mService.runOnServiceSync(() -> controller.setScale(2.0f, false));
@@ -151,12 +170,13 @@
final MagnificationController controller2 = service.getMagnificationController();
try {
assertEquals("Magnification must reset when a service dies",
- 1.0f, controller2.getScale());
+ 1.0f, controller2.getScale(), 0f);
} finally {
service.runOnServiceSync(() -> service.disableSelf());
}
}
+ @Test
public void testGetMagnificationRegion_whenCanControlMagnification_shouldNotBeEmpty() {
final MagnificationController controller = mService.getMagnificationController();
Region magnificationRegion = controller.getMagnificationRegion();
@@ -164,6 +184,7 @@
+ "magnification is being actively controlled", magnificationRegion.isEmpty());
}
+ @Test
public void testGetMagnificationRegion_whenCantControlMagnification_shouldBeEmpty() {
mService.runOnServiceSync(() -> mService.disableSelf());
mService = null;
@@ -179,6 +200,7 @@
}
}
+ @Test
public void testGetMagnificationRegion_whenMagnificationGesturesEnabled_shouldNotBeEmpty() {
ShellCommandBuilder.create(mInstrumentation)
.putSecureSetting(ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, "1")
@@ -200,6 +222,7 @@
}
}
+ @Test
public void testAnimatingMagnification() throws InterruptedException {
final MagnificationController controller = mService.getMagnificationController();
final int timeBetweenAnimationChanges = 100;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityOverlayTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityOverlayTest.java
index e461bdf..37128fd 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityOverlayTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityOverlayTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertTrue;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibility.cts.common.InstrumentedAccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.cts.utils.AsyncUtils;
@@ -36,6 +37,7 @@
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,6 +51,10 @@
private static UiAutomation sUiAutomation;
InstrumentedAccessibilityService mService;
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
@BeforeClass
public static void oneTimeSetUp() {
sInstrumentation = InstrumentationRegistry.getInstrumentation();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityPaneTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityPaneTest.java
index 959f315..b4a8b09 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityPaneTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityPaneTest.java
@@ -28,6 +28,7 @@
import static org.hamcrest.Matchers.both;
import static org.junit.Assert.assertEquals;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibilityservice.cts.activities.AccessibilityEndToEndActivity;
import android.app.Activity;
import android.app.Instrumentation;
@@ -45,6 +46,7 @@
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
/**
@@ -58,10 +60,17 @@
private Activity mActivity;
private View mPaneView;
- @Rule
- public ActivityTestRule<AccessibilityEndToEndActivity> mActivityRule =
+ private ActivityTestRule<AccessibilityEndToEndActivity> mActivityRule =
new ActivityTestRule<>(AccessibilityEndToEndActivity.class, false, false);
+ private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
+ @Rule
+ public final RuleChain mRuleChain = RuleChain
+ .outerRule(mDumpOnFailureRule)
+ .around(mActivityRule);
+
@BeforeClass
public static void oneTimeSetup() throws Exception {
sInstrumentation = InstrumentationRegistry.getInstrumentation();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java
index 67626fe..01d1659 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java
@@ -16,20 +16,35 @@
package android.accessibilityservice.cts;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.accessibility.AccessibilityEvent;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
/**
* Class for testing {@link AccessibilityServiceInfo}.
*/
@Presubmit
-public class AccessibilityServiceInfoTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityServiceInfoTest {
+
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
@MediumTest
+ @Test
public void testMarshalling() throws Exception {
// fully populate the service info to marshal
@@ -51,6 +66,7 @@
* Tests whether the service info describes its contents consistently.
*/
@MediumTest
+ @Test
public void testDescribeContents() {
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
assertSame("Accessibility service info always return 0 for this method.", 0,
@@ -64,6 +80,7 @@
* Tests whether a feedback type is correctly transformed to a string.
*/
@MediumTest
+ @Test
public void testFeedbackTypeToString() {
assertEquals("[FEEDBACK_AUDIBLE]", AccessibilityServiceInfo.feedbackTypeToString(
AccessibilityServiceInfo.FEEDBACK_AUDIBLE));
@@ -87,6 +104,7 @@
* Tests whether a flag is correctly transformed to a string.
*/
@MediumTest
+ @Test
public void testFlagToString() {
assertEquals("DEFAULT", AccessibilityServiceInfo.flagToString(
AccessibilityServiceInfo.DEFAULT));
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySettingsTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySettingsTest.java
index f01251a..3199dc6 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySettingsTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySettingsTest.java
@@ -16,15 +16,25 @@
package android.accessibilityservice.cts;
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static org.junit.Assert.assertTrue;
+
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
-import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.List;
/**
@@ -32,12 +42,18 @@
* accessibility settings has an activity that handles it.
*/
@Presubmit
-public class AccessibilitySettingsTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AccessibilitySettingsTest {
+
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
@MediumTest
@AppModeFull
+ @Test
public void testAccessibilitySettingsIntentHandled() throws Throwable {
- PackageManager packageManager = mContext.getPackageManager();
+ PackageManager packageManager = getContext().getPackageManager();
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
List<ResolveInfo> resolvedActivities = packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
index 8bb1bfb..7575167 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
@@ -13,6 +13,7 @@
*/
package android.accessibilityservice.cts;
+
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_AUTO;
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN;
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD;
@@ -21,6 +22,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibility.cts.common.InstrumentedAccessibilityService;
import android.accessibilityservice.AccessibilityService.SoftKeyboardController;
import android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener;
@@ -36,6 +38,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -57,7 +60,9 @@
}
};
-
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
@Before
public void setUp() throws Exception {
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
index e89b4dd..58fbfd8 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
@@ -30,7 +30,7 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import android.accessibilityservice.cts.R;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibilityservice.cts.activities.AccessibilityTextTraversalActivity;
import android.app.Instrumentation;
import android.app.UiAutomation;
@@ -60,6 +60,7 @@
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import java.util.Arrays;
@@ -80,10 +81,17 @@
private AccessibilityTextTraversalActivity mActivity;
- @Rule
- public ActivityTestRule<AccessibilityTextTraversalActivity> mActivityRule =
+ private ActivityTestRule<AccessibilityTextTraversalActivity> mActivityRule =
new ActivityTestRule<>(AccessibilityTextTraversalActivity.class, false, false);
+ private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
+ @Rule
+ public final RuleChain mRuleChain = RuleChain
+ .outerRule(mDumpOnFailureRule)
+ .around(mActivityRule);
+
@BeforeClass
public static void oneTimeSetup() throws Exception {
sInstrumentation = InstrumentationRegistry.getInstrumentation();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
index 75eda1d..1729269 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
@@ -23,7 +23,7 @@
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
-import android.accessibilityservice.cts.R;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibilityservice.cts.activities.AccessibilityTextTraversalActivity;
import android.app.Instrumentation;
import android.app.UiAutomation;
@@ -47,6 +47,7 @@
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
/**
@@ -64,10 +65,17 @@
private AccessibilityTextTraversalActivity mActivity;
- @Rule
- public ActivityTestRule<AccessibilityTextTraversalActivity> mActivityRule =
+ private ActivityTestRule<AccessibilityTextTraversalActivity> mActivityRule =
new ActivityTestRule<>(AccessibilityTextTraversalActivity.class, false, false);
+ private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
+ @Rule
+ public final RuleChain mRuleChain = RuleChain
+ .outerRule(mDumpOnFailureRule)
+ .around(mActivityRule);
+
@BeforeClass
public static void oneTimeSetup() throws Exception {
sInstrumentation = InstrumentationRegistry.getInstrumentation();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
index 28a3acd..a1b993b 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
@@ -14,8 +14,7 @@
package android.accessibilityservice.cts;
-import static android.accessibilityservice.cts.utils.ActivityLaunchUtils
- .launchActivityAndWaitForItToBeOnscreen;
+import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -23,15 +22,12 @@
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibilityservice.AccessibilityServiceInfo;
-import android.accessibilityservice.cts.R;
import android.accessibilityservice.cts.activities.AccessibilityViewTreeReportingActivity;
import android.app.Instrumentation;
import android.app.UiAutomation;
import android.content.Context;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.rule.ActivityTestRule;
-import androidx.test.runner.AndroidJUnit4;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
@@ -40,11 +36,16 @@
import android.widget.Button;
import android.widget.LinearLayout;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
/**
@@ -61,10 +62,17 @@
private AccessibilityViewTreeReportingActivity mActivity;
- @Rule
- public ActivityTestRule<AccessibilityViewTreeReportingActivity> mActivityRule =
+ private ActivityTestRule<AccessibilityViewTreeReportingActivity> mActivityRule =
new ActivityTestRule<>(AccessibilityViewTreeReportingActivity.class, false, false);
+ private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
+ @Rule
+ public final RuleChain mRuleChain = RuleChain
+ .outerRule(mDumpOnFailureRule)
+ .around(mActivityRule);
+
@BeforeClass
public static void oneTimeSetup() throws Exception {
sInstrumentation = InstrumentationRegistry.getInstrumentation();
@@ -309,6 +317,44 @@
assertTrue(awaitedEvent.getSource().isImportantForAccessibility());
}
+
+ @Test
+ public void testHideView_receiveSubtreeEvent() throws Throwable {
+ final View view = mActivity.findViewById(R.id.secondButton);
+ AccessibilityEvent awaitedEvent =
+ sUiAutomation.executeAndWaitForEvent(
+ () -> mActivity.runOnUiThread(() -> view.setVisibility(View.GONE)),
+ (event) -> {
+ boolean isContentChanged = event.getEventType()
+ == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
+ int isSubTree = (event.getContentChangeTypes()
+ & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
+ boolean isFromThisPackage = TextUtils.equals(event.getPackageName(),
+ mActivity.getPackageName());
+ return isContentChanged && (isSubTree != 0) && isFromThisPackage;
+ }, TIMEOUT_ASYNC_PROCESSING);
+ awaitedEvent.recycle();
+ }
+
+ @Test
+ public void testUnhideView_receiveSubtreeEvent() throws Throwable {
+ final View view = mActivity.findViewById(R.id.hiddenButton);
+ AccessibilityEvent awaitedEvent =
+ sUiAutomation.executeAndWaitForEvent(
+ () -> mActivity.runOnUiThread(() -> view.setVisibility(View.VISIBLE)),
+ (event) -> {
+ boolean isContentChanged = event.getEventType()
+ == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
+ int isSubTree = (event.getContentChangeTypes()
+ & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
+ boolean isFromThisPackage = TextUtils.equals(event.getPackageName(),
+ mActivity.getPackageName());
+ return isContentChanged && (isSubTree != 0) && isFromThisPackage;
+ }, TIMEOUT_ASYNC_PROCESSING);
+ awaitedEvent.recycle();
+ }
+
+
private void setGetNonImportantViews(boolean getNonImportantViews) {
AccessibilityServiceInfo serviceInfo = sUiAutomation.getServiceInfo();
serviceInfo.flags &= ~AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java
index 16e0b68..4eb140d 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java
@@ -17,6 +17,7 @@
import static org.junit.Assert.assertEquals;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibility.cts.common.InstrumentedAccessibilityService;
import android.app.Instrumentation;
import android.content.pm.PackageManager;
@@ -28,6 +29,7 @@
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -43,6 +45,10 @@
// If a11y volume is stuck at a single value, don't run the tests
boolean mFixedA11yVolume;
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
@Before
public void setUp() {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
index e757a66..fe8b70d 100755
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
@@ -48,9 +48,9 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
-import android.accessibilityservice.cts.activities.AccessibilityEndToEndActivity;
import android.accessibilityservice.cts.activities.AccessibilityWindowQueryActivity;
import android.app.Instrumentation;
import android.app.UiAutomation;
@@ -80,6 +80,7 @@
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import java.util.ArrayList;
@@ -108,13 +109,16 @@
private AccessibilityWindowQueryActivity mActivity;
- @Rule
- public ActivityTestRule<AccessibilityWindowQueryActivity> mActivityRule =
+ private ActivityTestRule<AccessibilityWindowQueryActivity> mActivityRule =
new ActivityTestRule<>(AccessibilityWindowQueryActivity.class, false, false);
+ private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
@Rule
- public ActivityTestRule<AccessibilityEndToEndActivity> mEndToEndActivityRule =
- new ActivityTestRule<>(AccessibilityEndToEndActivity.class, false, false);
+ public final RuleChain mRuleChain = RuleChain
+ .outerRule(mDumpOnFailureRule)
+ .around(mActivityRule);
@BeforeClass
public static void oneTimeSetup() throws Exception {
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
index 71c34c2..83c8154 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
@@ -39,6 +39,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.cts.activities.AccessibilityWindowReportingActivity;
import android.app.Activity;
@@ -62,6 +63,7 @@
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import java.util.List;
@@ -82,10 +84,17 @@
private Activity mActivity;
private CharSequence mActivityTitle;
- @Rule
- public ActivityTestRule<AccessibilityWindowReportingActivity> mActivityRule =
+ private ActivityTestRule<AccessibilityWindowReportingActivity> mActivityRule =
new ActivityTestRule<>(AccessibilityWindowReportingActivity.class, false, false);
+ private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
+ @Rule
+ public final RuleChain mRuleChain = RuleChain
+ .outerRule(mDumpOnFailureRule)
+ .around(mActivityRule);
+
@BeforeClass
public static void oneTimeSetup() throws Exception {
sInstrumentation = InstrumentationRegistry.getInstrumentation();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
index 92821b8..4f19ef7 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
@@ -14,30 +14,48 @@
package android.accessibilityservice.cts;
+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 android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibilityservice.GestureDescription;
import android.accessibilityservice.GestureDescription.StrokeDescription;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.Presubmit;
-import android.test.InstrumentationTestCase;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
/**
* Tests for creating gesture descriptions.
*/
@Presubmit
@AppModeFull
-public class GestureDescriptionTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class GestureDescriptionTest {
static final int NOMINAL_PATH_DURATION = 100;
private Path mNominalPath;
- @Override
+ @Rule
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
+ @Before
public void setUp() {
mNominalPath = new Path();
mNominalPath.moveTo(0, 0);
mNominalPath.lineTo(10, 10);
}
+ @Test
public void testCreateStroke_noDuration_shouldThrow() {
try {
new StrokeDescription(mNominalPath, 0, 0);
@@ -46,6 +64,7 @@
}
}
+ @Test
public void testCreateStroke_negativeStartTime_shouldThrow() {
try {
new StrokeDescription(mNominalPath, -1, NOMINAL_PATH_DURATION);
@@ -54,6 +73,7 @@
}
}
+ @Test
public void testCreateStroke_negativeStartX_shouldThrow() {
Path negativeStartXPath = new Path();
negativeStartXPath.moveTo(-1, 0);
@@ -65,6 +85,7 @@
}
}
+ @Test
public void testCreateStroke_negativeStartY_shouldThrow() {
Path negativeStartYPath = new Path();
negativeStartYPath.moveTo(0, -1);
@@ -76,6 +97,7 @@
}
}
+ @Test
public void testCreateStroke_negativeEndX_shouldThrow() {
Path negativeEndXPath = new Path();
negativeEndXPath.moveTo(0, 0);
@@ -87,6 +109,7 @@
}
}
+ @Test
public void testCreateStroke_negativeEndY_shouldThrow() {
Path negativeEndYPath = new Path();
negativeEndYPath.moveTo(0, 0);
@@ -98,6 +121,7 @@
}
}
+ @Test
public void testCreateStroke_withEmptyPath_shouldThrow() {
Path emptyPath = new Path();
try {
@@ -107,6 +131,7 @@
}
}
+ @Test
public void testCreateStroke_pathWithMultipleContours_shouldThrow() {
Path multiContourPath = new Path();
multiContourPath.moveTo(0, 0);
@@ -120,6 +145,7 @@
}
}
+ @Test
public void testStrokeDescriptionWillContinue() {
StrokeDescription strokeDescription = new StrokeDescription(mNominalPath, 0, 100);
assertFalse(strokeDescription.willContinue());
@@ -138,6 +164,7 @@
assertTrue(continuation.willContinue());
}
+ @Test
public void testAddStroke_allowUpToMaxPaths() {
GestureDescription.Builder gestureBuilder = new GestureDescription.Builder();
for (int i = 0; i < GestureDescription.getMaxStrokeCount(); i++) {
@@ -156,6 +183,7 @@
}
}
+ @Test
public void testAddStroke_withDurationTooLong_shouldThrow() {
Path path = new Path();
path.moveTo(10, 10);
@@ -169,6 +197,7 @@
}
}
+ @Test
public void testEmptyDescription_shouldThrow() {
GestureDescription.Builder gestureBuilder = new GestureDescription.Builder();
try {
@@ -178,6 +207,7 @@
}
}
+ @Test
public void testStrokeDescriptionGetters_workAsExpected() {
int x = 100;
int startY = 100;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDetectionStubAccessibilityService.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDetectionStubAccessibilityService.java
index 042904b..a2a3472 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDetectionStubAccessibilityService.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDetectionStubAccessibilityService.java
@@ -14,20 +14,24 @@
package android.accessibilityservice.cts;
+import static org.junit.Assert.fail;
+
import android.accessibility.cts.common.InstrumentedAccessibilityService;
import android.app.Instrumentation;
import android.view.accessibility.AccessibilityEvent;
+
import java.util.ArrayList;
+import java.util.List;
/** Accessibility service stub, which will collect recognized gestures. */
public class GestureDetectionStubAccessibilityService extends InstrumentedAccessibilityService {
private static final long GESTURE_RECOGNIZE_TIMEOUT_MS = 3000;
- private static final long EVENT_RECOGNIZE_TIMEOUT_MS = 3000;
+ private static final long EVENT_RECOGNIZE_TIMEOUT_MS = 5000;
// Member variables
- private final Object mLock = new Object();
+ protected final Object mLock = new Object();
private ArrayList<Integer> mCollectedGestures = new ArrayList();
- private ArrayList<Integer> mCollectedEvents = new ArrayList();
+ protected ArrayList<Integer> mCollectedEvents = new ArrayList();
public static GestureDetectionStubAccessibilityService enableSelf(
Instrumentation instrumentation) {
@@ -124,4 +128,37 @@
}
}
}
+
+ /** Insure that the specified accessibility events have been received. */
+ public void assertPropagated(int... events) {
+ waitUntilEvent(events.length);
+ // Set up readable error reporting.
+ List<String> received = new ArrayList<>();
+ List<String> expected = new ArrayList<>();
+ for (int event : events) {
+ expected.add(AccessibilityEvent.eventTypeToString(event));
+ }
+ for (int i = 0; i < getEventsSize(); ++i) {
+ received.add(AccessibilityEvent.eventTypeToString(getEvent(i)));
+ }
+
+ if (events.length != getEventsSize()) {
+ String message =
+ String.format(
+ "Received %d events when expecting %d. Received %s, expected %s",
+ received.size(),
+ expected.size(),
+ received.toString(),
+ expected.toString());
+ fail(message);
+ }
+ else if (!expected.equals(received)) {
+ String message =
+ String.format(
+ "Received %s, expected %s",
+ received.toString(),
+ expected.toString());
+ fail(message);
+ }
+ }
}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/MagnificationGestureHandlerTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/MagnificationGestureHandlerTest.java
index 72bbd97..95740cd 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/MagnificationGestureHandlerTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/MagnificationGestureHandlerTest.java
@@ -24,6 +24,7 @@
import static android.accessibilityservice.cts.utils.GestureUtils.dispatchGesture;
import static android.accessibilityservice.cts.utils.GestureUtils.distance;
import static android.accessibilityservice.cts.utils.GestureUtils.drag;
+import static android.accessibilityservice.cts.utils.GestureUtils.doubleTap;
import static android.accessibilityservice.cts.utils.GestureUtils.endTimeOf;
import static android.accessibilityservice.cts.utils.GestureUtils.lastPointOf;
import static android.accessibilityservice.cts.utils.GestureUtils.longClick;
@@ -31,6 +32,7 @@
import static android.accessibilityservice.cts.utils.GestureUtils.pointerUp;
import static android.accessibilityservice.cts.utils.GestureUtils.startingAt;
import static android.accessibilityservice.cts.utils.GestureUtils.swipe;
+import static android.accessibilityservice.cts.utils.GestureUtils.tripleTap;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
@@ -45,6 +47,7 @@
import static java.util.concurrent.TimeUnit.SECONDS;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibility.cts.common.InstrumentedAccessibilityService;
import android.accessibilityservice.GestureDescription;
import android.accessibilityservice.GestureDescription.StrokeDescription;
@@ -67,6 +70,7 @@
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import java.util.ArrayList;
@@ -95,10 +99,17 @@
private final Object mZoomLock = new Object();
- @Rule
- public ActivityTestRule<GestureDispatchActivity> mActivityRule =
+ private ActivityTestRule<GestureDispatchActivity> mActivityRule =
new ActivityTestRule<>(GestureDispatchActivity.class);
+ private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
+
+ @Rule
+ public final RuleChain mRuleChain = RuleChain
+ .outerRule(mDumpOnFailureRule)
+ .around(mActivityRule);
+
@Before
public void setUp() throws Exception {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
@@ -196,9 +207,9 @@
private void setZoomByTripleTapping(boolean desiredZoomState) {
if (isZoomed() == desiredZoomState) return;
- dispatch(tripleTap());
+ dispatch(tripleTap(mTapLocation));
waitOn(mZoomLock, () -> isZoomed() == desiredZoomState);
- assertNoTouchInputPropagated();
+ mTouchListener.assertNonePropagated();
}
private void tripleTapAndDragViewport() {
@@ -210,10 +221,10 @@
dispatch(drag);
waitOn(mZoomLock, () -> distance(mCurrentZoomCenter, oldCenter) >= mPan / 5);
assertTrue(isZoomed());
- assertNoTouchInputPropagated();
+ mTouchListener.assertNonePropagated();
dispatch(pointerUp(drag));
- assertNoTouchInputPropagated();
+ mTouchListener.assertNonePropagated();
}
private StrokeDescription tripleTapAndHold() {
@@ -227,22 +238,18 @@
private void assertGesturesPropagateToView() {
dispatch(click(mTapLocation));
- assertPropagated(ACTION_DOWN, ACTION_UP);
+ mTouchListener.assertPropagated(ACTION_DOWN, ACTION_UP);
dispatch(longClick(mTapLocation));
- assertPropagated(ACTION_DOWN, ACTION_UP);
+ mTouchListener.assertPropagated(ACTION_DOWN, ACTION_UP);
- dispatch(doubleTap());
- assertPropagated(ACTION_DOWN, ACTION_UP, ACTION_DOWN, ACTION_UP);
+ dispatch(doubleTap(mTapLocation));
+ mTouchListener.assertPropagated(ACTION_DOWN, ACTION_UP, ACTION_DOWN, ACTION_UP);
dispatch(swipe(
mTapLocation,
add(mTapLocation, 0, 29)));
- assertPropagated(ACTION_DOWN, ACTION_MOVE, ACTION_UP);
- }
-
- private void assertNoTouchInputPropagated() {
- assertThat(prettyPrintable(mTouchListener.events), is(empty()));
+ mTouchListener.assertPropagated(ACTION_DOWN, ACTION_MOVE, ACTION_UP);
}
private void setMagnificationEnabled(boolean enabled) {
@@ -254,50 +261,6 @@
return mCurrentScale >= MIN_SCALE;
}
- private void assertPropagated(int... eventTypes) {
- MotionEvent ev;
- try {
- while (true) {
- if (eventTypes.length == 0) return;
- int expectedEventType = eventTypes[0];
- long startedPollingAt = SystemClock.uptimeMillis();
- ev = mTouchListener.events.poll(5, SECONDS);
- assertNotNull("Expected "
- + MotionEvent.actionToString(expectedEventType)
- + " but none present after "
- + (SystemClock.uptimeMillis() - startedPollingAt) + "ms",
- ev);
- int action = ev.getActionMasked();
- if (action == expectedEventType) {
- eventTypes = Arrays.copyOfRange(eventTypes, 1, eventTypes.length);
- } else {
- if (action != ACTION_MOVE) fail("Unexpected event: " + ev);
- }
- }
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
-
- private GestureDescription doubleTap() {
- return multiTap(2);
- }
-
- private GestureDescription tripleTap() {
- return multiTap(3);
- }
-
- private GestureDescription multiTap(int taps) {
- GestureDescription.Builder builder = new GestureDescription.Builder();
- long time = 0;
- for (int i = 0; i < taps; i++) {
- StrokeDescription stroke = click(mTapLocation);
- builder.addStroke(startingAt(time, stroke));
- time += stroke.getDuration() + 20;
- }
- return builder.build();
- }
-
public void dispatch(StrokeDescription firstStroke, StrokeDescription... rest) {
GestureDescription.Builder builder =
new GestureDescription.Builder().addStroke(firstStroke);
@@ -310,17 +273,4 @@
public void dispatch(GestureDescription gesture) {
await(dispatchGesture(mService, gesture));
}
-
- private static <T> Collection<T> prettyPrintable(Collection<T> c) {
- return new ArrayList<T>(c) {
-
- @Override
- public String toString() {
- return stream()
- .map(t -> "\n" + t)
- .reduce(String::concat)
- .orElse("");
- }
- };
- }
}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorationStubAccessibilityService.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorationStubAccessibilityService.java
new file mode 100644
index 0000000..07f8ea8
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorationStubAccessibilityService.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * <p>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
+ *
+ * <p>http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * <p>Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.accessibilityservice.cts;
+
+import static android.view.accessibility.AccessibilityEvent.TYPE_GESTURE_DETECTION_END;
+import static android.view.accessibility.AccessibilityEvent.TYPE_GESTURE_DETECTION_START;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_CLICKED;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_HOVER_ENTER;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_HOVER_EXIT;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_LONG_CLICKED;
+
+import android.accessibility.cts.common.InstrumentedAccessibilityService;
+import android.app.Instrumentation;
+import android.view.accessibility.AccessibilityEvent;
+
+/**
+ * This accessibility service stub collects all events relating to touch exploration rather than
+ * just the few collected by GestureDetectionStubAccessibilityService
+ */
+public class TouchExplorationStubAccessibilityService
+ extends GestureDetectionStubAccessibilityService {
+ @Override
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ synchronized (mLock) {
+ switch (event.getEventType()) {
+ case TYPE_GESTURE_DETECTION_START:
+ case TYPE_GESTURE_DETECTION_END:
+ case TYPE_VIEW_HOVER_ENTER:
+ case TYPE_VIEW_HOVER_EXIT:
+ case TYPE_VIEW_FOCUSED:
+ case TYPE_VIEW_ACCESSIBILITY_FOCUSED:
+ case TYPE_VIEW_CLICKED:
+ case TYPE_VIEW_LONG_CLICKED:
+ mCollectedEvents.add(event.getEventType());
+ }
+ }
+ super.onAccessibilityEvent(event);
+ }
+
+ public static TouchExplorationStubAccessibilityService enableSelf(
+ Instrumentation instrumentation) {
+ return InstrumentedAccessibilityService.enableService(
+ instrumentation, TouchExplorationStubAccessibilityService.class);
+ }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java
new file mode 100644
index 0000000..87d7166
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice.cts;
+
+import static android.accessibilityservice.cts.utils.AsyncUtils.await;
+import static android.accessibilityservice.cts.utils.GestureUtils.add;
+import static android.accessibilityservice.cts.utils.GestureUtils.click;
+import static android.accessibilityservice.cts.utils.GestureUtils.dispatchGesture;
+import static android.accessibilityservice.cts.utils.GestureUtils.doubleTap;
+import static android.accessibilityservice.cts.utils.GestureUtils.doubleTapAndHold;
+import static android.accessibilityservice.cts.utils.GestureUtils.swipe;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_HOVER_ENTER;
+import static android.view.MotionEvent.ACTION_HOVER_EXIT;
+import static android.view.MotionEvent.ACTION_HOVER_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
+import static android.view.accessibility.AccessibilityEvent.TYPE_GESTURE_DETECTION_END;
+import static android.view.accessibility.AccessibilityEvent.TYPE_GESTURE_DETECTION_START;
+import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END;
+import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START;
+import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_INTERACTION_END;
+import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_INTERACTION_START;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_CLICKED;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_HOVER_ENTER;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_HOVER_EXIT;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_LONG_CLICKED;
+
+import android.accessibilityservice.GestureDescription;
+import android.accessibilityservice.GestureDescription.StrokeDescription;
+import android.accessibilityservice.cts.AccessibilityGestureDispatchTest.GestureDispatchActivity;
+import android.accessibilityservice.cts.utils.EventCapturingClickListener;
+import android.accessibilityservice.cts.utils.EventCapturingHoverListener;
+import android.accessibilityservice.cts.utils.EventCapturingLongClickListener;
+import android.accessibilityservice.cts.utils.EventCapturingTouchListener;
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.platform.test.annotations.AppModeFull;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * A set of tests for testing touch exploration. Each test dispatches a gesture and checks for the
+ * appropriate hover and/or touch events followed by the appropriate accessibility events. Some
+ * tests will then check for events from the view.
+ */
+@RunWith(AndroidJUnit4.class)
+@AppModeFull
+public class TouchExplorerTest {
+ // Constants
+ private static final float GESTURE_LENGTH_INCHES = 1.0f;
+ private TouchExplorationStubAccessibilityService mService;
+ private Instrumentation mInstrumentation;
+ private UiAutomation mUiAutomation;
+ private boolean mHasTouchscreen;
+ private boolean mScreenBigEnough;
+ private EventCapturingHoverListener mHoverListener = new EventCapturingHoverListener(false);
+ private EventCapturingTouchListener mTouchListener = new EventCapturingTouchListener(false);
+ private EventCapturingClickListener mClickListener = new EventCapturingClickListener();
+ private EventCapturingLongClickListener mLongClickListener =
+ new EventCapturingLongClickListener();
+
+ @Rule
+ public ActivityTestRule<GestureDispatchActivity> mActivityRule =
+ new ActivityTestRule<>(GestureDispatchActivity.class, false);
+
+ Point mCenter; // Center of screen. Gestures all start from this point.
+ PointF mTapLocation;
+ float mSwipeDistance;
+ View mView;
+
+ @Before
+ public void setUp() throws Exception {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mUiAutomation = mInstrumentation.getUiAutomation();
+ PackageManager pm = mInstrumentation.getContext().getPackageManager();
+ mHasTouchscreen = pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
+ || pm.hasSystemFeature(PackageManager.FEATURE_FAKETOUCH);
+ // Find screen size, check that it is big enough for gestures.
+ // Gestures will start in the center of the screen, so we need enough horiz/vert space.
+ WindowManager windowManager =
+ (WindowManager)
+ mInstrumentation.getContext().getSystemService(Context.WINDOW_SERVICE);
+ final DisplayMetrics metrics = new DisplayMetrics();
+ windowManager.getDefaultDisplay().getRealMetrics(metrics);
+ mCenter = new Point((int) metrics.widthPixels / 2, (int) metrics.heightPixels / 2);
+ mTapLocation = new PointF(mCenter);
+ mScreenBigEnough = (metrics.widthPixels / (2 * metrics.xdpi) > GESTURE_LENGTH_INCHES);
+ if (!mHasTouchscreen || !mScreenBigEnough) return;
+ mService = TouchExplorationStubAccessibilityService.enableSelf(mInstrumentation);
+ mView = mActivityRule.getActivity().findViewById(R.id.full_screen_text_view);
+ mView.setOnHoverListener(mHoverListener);
+ mView.setOnTouchListener(mTouchListener);
+ mInstrumentation.runOnMainSync(
+ () -> {
+ mSwipeDistance = mView.getWidth() / 4;
+ mView.setOnClickListener(mClickListener);
+ mView.setOnLongClickListener(mLongClickListener);
+ });
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (!mHasTouchscreen || !mScreenBigEnough) return;
+ if (mService != null) {
+ mService.runOnServiceSync(() -> mService.disableSelfAndRemove());
+ mService = null;
+ }
+ }
+
+ /** Test a slow swipe which should initiate touch exploration. */
+ @Test
+ @AppModeFull
+ public void testSlowSwipe() {
+ if (!mHasTouchscreen || !mScreenBigEnough) return;
+ dispatch(swipe(mTapLocation, add(mTapLocation, mSwipeDistance, 0), 400));
+ mHoverListener.assertPropagated(ACTION_HOVER_ENTER, ACTION_HOVER_MOVE, ACTION_HOVER_EXIT);
+ mTouchListener.assertNonePropagated();
+ mService.assertPropagated(
+ TYPE_VIEW_FOCUSED,
+ TYPE_TOUCH_INTERACTION_START,
+ TYPE_TOUCH_EXPLORATION_GESTURE_START,
+ TYPE_VIEW_HOVER_ENTER,
+ TYPE_VIEW_HOVER_EXIT,
+ TYPE_TOUCH_EXPLORATION_GESTURE_END,
+ TYPE_TOUCH_INTERACTION_END);
+ }
+
+ /** Test a fast swipe which should not initiate touch exploration. */
+ @Test
+ @AppModeFull
+ public void testFastSwipe() {
+ if (!mHasTouchscreen || !mScreenBigEnough) return;
+ dispatch(swipe(mTapLocation, add(mTapLocation, mSwipeDistance, 0)));
+ mHoverListener.assertNonePropagated();
+ mTouchListener.assertNonePropagated();
+ mService.assertPropagated(
+ TYPE_VIEW_FOCUSED,
+ TYPE_TOUCH_INTERACTION_START,
+ TYPE_GESTURE_DETECTION_START,
+ TYPE_GESTURE_DETECTION_END,
+ TYPE_TOUCH_INTERACTION_END);
+ }
+
+ /** Test a basic single tap which should initiate touch exploration. */
+ @Test
+ @AppModeFull
+ public void testSingleTap() {
+ if (!mHasTouchscreen || !mScreenBigEnough) return;
+ dispatch(click(mTapLocation));
+ mHoverListener.assertPropagated(ACTION_HOVER_ENTER, ACTION_HOVER_EXIT);
+ mTouchListener.assertNonePropagated();
+ mService.assertPropagated(
+ TYPE_VIEW_FOCUSED,
+ TYPE_TOUCH_INTERACTION_START,
+ TYPE_TOUCH_EXPLORATION_GESTURE_START,
+ TYPE_VIEW_HOVER_ENTER,
+ TYPE_VIEW_HOVER_EXIT,
+ TYPE_TOUCH_EXPLORATION_GESTURE_END,
+ TYPE_TOUCH_INTERACTION_END);
+ }
+
+ /**
+ * Test the case where we want to click on the item that has accessibility focus by using
+ * AccessibilityNodeInfo.performAction.
+ */
+ @Test
+ @AppModeFull
+ public void testDoubleTapAccessibilityFocus() {
+ if (!mHasTouchscreen || !mScreenBigEnough) return;
+ syncAccessibilityFocusToInputFocus();
+ dispatch(doubleTap(mTapLocation));
+ mHoverListener.assertNonePropagated();
+ // The click should not be delivered via touch events in this case.
+ mTouchListener.assertNonePropagated();
+ mService.assertPropagated(
+ TYPE_VIEW_FOCUSED,
+ TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+ TYPE_TOUCH_INTERACTION_START,
+ TYPE_TOUCH_INTERACTION_END,
+ TYPE_VIEW_CLICKED);
+ mClickListener.assertClicked(mView);
+ }
+
+ /**
+ * Test the case where we double tap but there is no accessibility focus. Nothing should happen.
+ */
+ @Test
+ @AppModeFull
+ public void testDoubleTapNoAccessibilityFocus() {
+ if (!mHasTouchscreen || !mScreenBigEnough) return;
+ dispatch(doubleTap(mTapLocation));
+ mHoverListener.assertNonePropagated();
+ mTouchListener.assertNonePropagated();
+ mService.assertPropagated(
+ TYPE_VIEW_FOCUSED, TYPE_TOUCH_INTERACTION_START, TYPE_TOUCH_INTERACTION_END);
+ mService.clearEvents();
+ mClickListener.assertNoneClicked();
+ }
+
+ /** Test the case where we want to long click on the item that has accessibility focus. */
+ @Test
+ @AppModeFull
+ public void testDoubleTapAndHoldAccessibilityFocus() {
+ if (!mHasTouchscreen || !mScreenBigEnough) return;
+ syncAccessibilityFocusToInputFocus();
+ dispatch(doubleTapAndHold(mTapLocation));
+ mHoverListener.assertNonePropagated();
+ // The click should not be delivered via touch events in this case.
+ mTouchListener.assertNonePropagated();
+ mService.assertPropagated(
+ TYPE_VIEW_FOCUSED,
+ TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+ TYPE_TOUCH_INTERACTION_START,
+ TYPE_VIEW_LONG_CLICKED,
+ TYPE_TOUCH_INTERACTION_END);
+ mLongClickListener.assertLongClicked(mView);
+ }
+
+ /**
+ * Test the case where we double tap and hold but there is no accessibility focus.
+ * Nothing should happen.
+ */
+ @Test
+ @AppModeFull
+ public void testDoubleTapAndHoldNoAccessibilityFocus() {
+ if (!mHasTouchscreen || !mScreenBigEnough) return;
+ dispatch(doubleTap(mTapLocation));
+ mHoverListener.assertNonePropagated();
+ mTouchListener.assertNonePropagated();
+ mService.assertPropagated(
+ TYPE_VIEW_FOCUSED, TYPE_TOUCH_INTERACTION_START, TYPE_TOUCH_INTERACTION_END);
+ mService.clearEvents();
+ mLongClickListener.assertNoneLongClicked();
+ }
+
+ public void dispatch(StrokeDescription firstStroke, StrokeDescription... rest) {
+ GestureDescription.Builder builder =
+ new GestureDescription.Builder().addStroke(firstStroke);
+ for (StrokeDescription stroke : rest) {
+ builder.addStroke(stroke);
+ }
+ dispatch(builder.build());
+ }
+
+ public void dispatch(GestureDescription gesture) {
+ await(dispatchGesture(mService, gesture));
+ }
+
+ /** Set the accessibility focus to the element that has input focus. */
+ private void syncAccessibilityFocusToInputFocus() {
+ mService.runOnServiceSync(
+ () -> {
+ mUiAutomation
+ .getRootInActiveWindow()
+ .findFocus(AccessibilityNodeInfo.FOCUS_INPUT)
+ .performAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
+ });
+ }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/EventCapturingClickListener.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/EventCapturingClickListener.java
new file mode 100644
index 0000000..116bccf
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/EventCapturingClickListener.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice.cts.utils;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.view.View;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/** A click event listener that keeps an ordered record of events. */
+public class EventCapturingClickListener implements View.OnClickListener {
+
+ private final BlockingQueue<View> mViews = new LinkedBlockingQueue<>();
+
+ @Override
+ public void onClick(View view) {
+ mViews.offer(view);
+ }
+
+ /** Insure that the specified views have received click events. */
+ public void assertClicked(View... views) {
+ View view;
+ try {
+ for (View v : views) {
+ long waitTime = 5; // seconds
+ view = mViews.poll(waitTime, SECONDS);
+ assertNotNull(
+ "Expected click event for "
+ + v.toString()
+ + " but none present after "
+ + waitTime
+ + " seconds",
+ view);
+ if (v != view) {
+ fail("Unexpected click event for view" + view.toString());
+ }
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Insure that no click events have been received. */
+ public void assertNoneClicked() {
+ try {
+ long waitTime = 1; // seconds
+ View view = mViews.poll(waitTime, SECONDS);
+ if (view != null) {
+ fail("Unexpected click event for view" + view.toString());
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/EventCapturingHoverListener.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/EventCapturingHoverListener.java
new file mode 100644
index 0000000..87d46ba
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/EventCapturingHoverListener.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice.cts.utils;
+
+import static android.view.MotionEvent.ACTION_HOVER_MOVE;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.view.MotionEvent;
+import android.view.View;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/** This Listener listens for and logs hover events so they can be checked later by tests. */
+public class EventCapturingHoverListener implements View.OnHoverListener {
+
+ private boolean shouldConsumeEvents; // whether or not to keep events from propagating to other
+ // listeners
+ private final BlockingQueue<MotionEvent> mEvents = new LinkedBlockingQueue<>();
+
+ public EventCapturingHoverListener(boolean shouldConsumeEvents) {
+ this.shouldConsumeEvents = shouldConsumeEvents;
+ }
+
+ public EventCapturingHoverListener() {
+ this.shouldConsumeEvents = true;
+ }
+
+ @Override
+ public boolean onHover(View view, MotionEvent MotionEvent) {
+ assertTrue(mEvents.offer(MotionEvent.obtain(MotionEvent)));
+ return shouldConsumeEvents;
+ }
+
+ /** Insure that no hover events have been detected. */
+ public void assertNonePropagated() {
+ try {
+ long waitTime = 1; // seconds
+ MotionEvent event = mEvents.poll(waitTime, SECONDS);
+ if (event != null) {
+ fail("Unexpected touch event " + event.toString());
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Check for the specified hover events. Note that specifying ACTION_HOVER_MOVE will match one
+ * or more consecutive ACTION_HOVER_MOVE events.
+ */
+ public void assertPropagated(int... eventTypes) {
+ MotionEvent ev;
+ long waitTime = 5; // seconds
+ try {
+ List<String> expected = new ArrayList<>();
+ List<String> received = new ArrayList<>();
+ for (int e : eventTypes) {
+ expected.add(MotionEvent.actionToString(e));
+ }
+ ev = mEvents.poll(waitTime, SECONDS);
+ assertNotNull(
+ "Expected " + expected + " but none present after " + waitTime + " seconds",
+ ev);
+ // By this point there is at least one received event.
+ received.add(MotionEvent.actionToString(ev.getActionMasked()));
+ ev = mEvents.poll(waitTime, SECONDS);
+ while (ev != null) {
+ int action = ev.getActionMasked();
+ if (action != ACTION_HOVER_MOVE) {
+ received.add(MotionEvent.actionToString(action));
+ } else {
+ // Add the current event if the previous received event was not ACTION_MOVE
+ String prev = received.get(received.size() - 1);
+ if (!prev.equals(MotionEvent.actionToString(ACTION_HOVER_MOVE))) {
+ received.add(MotionEvent.actionToString(action));
+ }
+ }
+ ev = mEvents.poll(waitTime, SECONDS);
+ }
+ assertEquals(expected, received);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/EventCapturingLongClickListener.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/EventCapturingLongClickListener.java
new file mode 100644
index 0000000..5daf89e
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/EventCapturingLongClickListener.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice.cts.utils;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.view.View;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/** A click event listener that keeps an ordered record of events. */
+public class EventCapturingLongClickListener implements View.OnLongClickListener {
+
+ // whether or not to keep events from propagating to other listeners.
+ // Note that setting this to false means that the accessibility service will see both a long
+ // click and a click event when you perform a double tap and hold gesture
+ private boolean shouldConsumeEvents;
+ private final BlockingQueue<View> mViews = new LinkedBlockingQueue<>();
+
+ public EventCapturingLongClickListener(boolean shouldConsumeEvents) {
+ this.shouldConsumeEvents = shouldConsumeEvents;
+ }
+
+ public EventCapturingLongClickListener() {
+ this.shouldConsumeEvents = true;
+ }
+
+ @Override
+ public boolean onLongClick(View view) {
+ mViews.offer(view);
+ return true;
+ }
+
+ /** Insure that the specified views have received long click events. */
+ public void assertLongClicked(View... views) {
+ View view;
+ try {
+ for (View v : views) {
+ long waitTime = 5; // seconds
+ view = mViews.poll(waitTime, SECONDS);
+ assertNotNull(
+ "Expected long click event for "
+ + v.toString()
+ + " but none present after "
+ + waitTime
+ + " seconds",
+ view);
+ if (v != view) {
+ fail("Unexpected long click event for view" + view.toString());
+ }
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Insure that no click events have been received. */
+ public void assertNoneLongClicked() {
+ try {
+ long waitTime = 1; // seconds
+ View view = mViews.poll(waitTime, SECONDS);
+ if (view != null) {
+ fail("Unexpected long click event for view" + view.toString());
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/EventCapturingTouchListener.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/EventCapturingTouchListener.java
index d7ae4592..e0adce2 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/EventCapturingTouchListener.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/EventCapturingTouchListener.java
@@ -16,22 +16,91 @@
package android.accessibilityservice.cts.utils;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.view.MotionEvent;
import android.view.View;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class EventCapturingTouchListener implements View.OnTouchListener {
+ // whether or not to keep events from propagating to other listeners
+ private boolean shouldConsumeEvents;
+ private final BlockingQueue<MotionEvent> events = new LinkedBlockingQueue<>();
- public final BlockingQueue<MotionEvent> events = new LinkedBlockingQueue<>();
+ public EventCapturingTouchListener(boolean shouldConsumeEvents) {
+ this.shouldConsumeEvents = shouldConsumeEvents;
+ }
+
+ public EventCapturingTouchListener() {
+ this.shouldConsumeEvents = true;
+ }
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
assertTrue(events.offer(MotionEvent.obtain(motionEvent)));
- return true;
+ return shouldConsumeEvents;
+ }
+
+ /** Insure that no touch events have been detected. */
+ public void assertNonePropagated() {
+ try {
+ long waitTime = 1; // seconds
+ MotionEvent event = events.poll(waitTime, SECONDS);
+ if (event != null) {
+ fail("Unexpected touch event " + event.toString());
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Check for the specified touch events. Note that specifying ACTION_MOVE will match one or more
+ * consecutive ACTION_MOVE events.
+ */
+ public void assertPropagated(int... eventTypes) {
+ MotionEvent ev;
+ long waitTime = 5; // seconds
+ try {
+ List<String> expected = new ArrayList<>();
+ List<String> received = new ArrayList<>();
+ for (int e : eventTypes) {
+ expected.add(MotionEvent.actionToString(e));
+ }
+ ev = events.poll(waitTime, SECONDS);
+ assertNotNull(
+ "Expected " + expected + " but none present after " + waitTime + " seconds",
+ ev);
+ // By this point there is at least one received event.
+ received.add(MotionEvent.actionToString(ev.getActionMasked()));
+ ev = events.poll(waitTime, SECONDS);
+ while (ev != null) {
+ int action = ev.getActionMasked();
+ if (action != ACTION_MOVE) {
+ received.add(MotionEvent.actionToString(action));
+ } else {
+ // Add the current event if the previous received event was not ACTION_MOVE
+ String prev = received.get(received.size() - 1);
+ if (!prev.equals(MotionEvent.actionToString(ACTION_MOVE))) {
+ received.add(MotionEvent.actionToString(action));
+ }
+ }
+ ev = events.poll(waitTime, SECONDS);
+ }
+ assertEquals(expected, received);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
}
}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/GestureUtils.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/GestureUtils.java
index 99fa727..6a29f60 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/GestureUtils.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/GestureUtils.java
@@ -73,7 +73,7 @@
public static StrokeDescription longClick(PointF point) {
return new StrokeDescription(path(point), 0,
- ViewConfiguration.getLongPressTimeout() * 3 / 2);
+ ViewConfiguration.getLongPressTimeout() * 3);
}
public static StrokeDescription swipe(PointF from, PointF to) {
@@ -141,4 +141,33 @@
public static PointF ceil(PointF p) {
return new PointF((float) Math.ceil(p.x), (float) Math.ceil(p.y));
}
-}
+
+ public static GestureDescription doubleTap(PointF point) {
+ return multiTap(point, 2);
+ }
+
+ public static GestureDescription tripleTap(PointF point) {
+ return multiTap(point, 3);
+ }
+
+ public static GestureDescription multiTap(PointF point, int taps) {
+ GestureDescription.Builder builder = new GestureDescription.Builder();
+ long time = 0;
+ for (int i = 0; i < taps; i++) {
+ StrokeDescription stroke = click(point);
+ builder.addStroke(startingAt(time, stroke));
+ time += stroke.getDuration() + 40;
+ }
+ return builder.build();
+ }
+
+ public static GestureDescription doubleTapAndHold(PointF point) {
+ GestureDescription.Builder builder = new GestureDescription.Builder();
+ StrokeDescription tap1 = click(point);
+ StrokeDescription tap2 = startingAt(endTimeOf(tap1) + 40, longClick(point));
+ builder.addStroke(tap1);
+ builder.addStroke(tap2);
+ return builder.build();
+ }
+
+}
\ No newline at end of file
diff --git a/tests/admin/OWNERS b/tests/admin/OWNERS
new file mode 100644
index 0000000..46669be
--- /dev/null
+++ b/tests/admin/OWNERS
@@ -0,0 +1,9 @@
+# Bug component: 100560
+sandness@google.com
+rubinxu@google.com
+eranm@google.com
+irinaid@google.com
+pgrafov@google.com
+alexkershaw@google.com
+arangelov@google.com
+scottjonathan@google.com
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index 3513f21..84b8adc 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -1571,6 +1571,7 @@
}
}
+ @FlakyTest(bugId = 133501804)
public void testAutogrouping() throws Exception {
sendNotification(1, R.drawable.black);
sendNotification(2, R.drawable.blue);
@@ -1581,6 +1582,7 @@
assertAllPostedNotificationsAutogrouped();
}
+ @FlakyTest(bugId = 133501804)
public void testAutogrouping_autogroupStaysUntilAllNotificationsCanceled() throws Exception {
sendNotification(1, R.drawable.black);
sendNotification(2, R.drawable.blue);
@@ -1600,6 +1602,7 @@
assertNotificationCount(0);
}
+ @FlakyTest(bugId = 133501804)
public void testAutogrouping_autogroupStaysUntilAllNotificationsAddedToGroup()
throws Exception {
String newGroup = "new!";
@@ -1630,7 +1633,8 @@
assertOnlySomeNotificationsAutogrouped(postedIds);
}
- public void testNewNotificationsAddedToAutogroup_ifOriginalNotificationsCanceled()
+ // b/133502627.
+ public void disabledTestNewNotificationsAddedToAutogroup_ifOriginalNotificationsCanceled()
throws Exception {
String newGroup = "new!";
sendNotification(10, R.drawable.black);
@@ -2176,7 +2180,8 @@
listener.onListenerDisconnected();
}
- public void testNotificationListener_setNotificationsShown() throws Exception {
+ // b/133502627
+ public void disabledTestNotificationListener_setNotificationsShown() throws Exception {
if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
return;
}
@@ -2272,7 +2277,8 @@
}
}
- public void testNotificationListener_getActiveNotifications() throws Exception {
+ // b/133502627
+ public void disabledTestNotificationListener_getActiveNotifications() throws Exception {
if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
return;
}
@@ -2322,7 +2328,8 @@
assertEquals(mListener.mRankingMap, mListener.getCurrentRanking());
}
- public void testNotificationListener_cancelNotifications() throws Exception {
+ // b/133502627
+ public void disabledTestNotificationListener_cancelNotifications() throws Exception {
if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
return;
}
@@ -2586,7 +2593,8 @@
}
}
- public void testNotificationManagerBubblePolicy_flagForAppForeground() throws Exception {
+ // b/133502627
+ public void disabledTestNotificationManagerBubblePolicy_flagForAppForeground() throws Exception {
try {
// turn on bubbles globally
toggleBubbleSetting(true);
diff --git a/tests/aslr/OWNERS b/tests/aslr/OWNERS
new file mode 100644
index 0000000..94522e3
--- /dev/null
+++ b/tests/aslr/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 36824
+include /tests/tests/security/OWNERS
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
index 2e56a02..9f87565 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
@@ -813,7 +813,12 @@
private String getString(String id) {
final Resources resources = mContext.getResources();
final int stringId = resources.getIdentifier(id, "string", "android");
- return resources.getString(stringId);
+ try {
+ return resources.getString(stringId);
+ } catch (Resources.NotFoundException e) {
+ throw new IllegalStateException("no internal string for '" + id + "' / res=" + stringId
+ + ": ", e);
+ }
}
/**
@@ -822,7 +827,12 @@
private String getString(String id, Object... formatArgs) {
final Resources resources = mContext.getResources();
final int stringId = resources.getIdentifier(id, "string", "android");
- return resources.getString(stringId, formatArgs);
+ try {
+ return resources.getString(stringId, formatArgs);
+ } catch (Resources.NotFoundException e) {
+ throw new IllegalStateException("no internal string for '" + id + "' / res=" + stringId
+ + ": ", e);
+ }
}
/**
diff --git a/tests/backup/OWNERS b/tests/backup/OWNERS
index 3637e32..c28c4d8 100644
--- a/tests/backup/OWNERS
+++ b/tests/backup/OWNERS
@@ -1,3 +1,4 @@
+# Bug component: 41666
# Use this reviewer by default.
br-framework-team+reviews@google.com
diff --git a/tests/backup/app/src/android/backup/app/FullBackupBackupAgent.java b/tests/backup/app/src/android/backup/app/FullBackupBackupAgent.java
index 8535344..0f4a123 100644
--- a/tests/backup/app/src/android/backup/app/FullBackupBackupAgent.java
+++ b/tests/backup/app/src/android/backup/app/FullBackupBackupAgent.java
@@ -53,23 +53,25 @@
@Override
public void onRestoreFile(ParcelFileDescriptor data, long size,
File destination, int type, long mode, long mtime) throws IOException {
- Log.d(MainActivity.TAG, "onRestoreFile " + destination);
super.onRestoreFile(data, size, destination, type, mode, mtime);
+ Log.d(MainActivity.TAG, "onRestoreFile " + destination);
}
@Override
public void onFullBackup(FullBackupDataOutput data) throws IOException {
- Log.d(MainActivity.TAG, "Full backup requested, quota is " + data.getQuota());
super.onFullBackup(data);
+ Log.d(MainActivity.TAG, "Full backup requested, quota is " + data.getQuota());
}
@Override
public void onQuotaExceeded(long backupDataBytes, long quotaBytes) {
+ super.onQuotaExceeded(backupDataBytes, quotaBytes);
Log.d(MainActivity.TAG, "Quota exceeded!");
}
@Override
public void onRestoreFinished() {
+ super.onRestoreFinished();
Log.d(MainActivity.TAG, "onRestoreFinished");
}
diff --git a/tests/backup/app/src/android/backup/app/KeyValueBackupAgent.java b/tests/backup/app/src/android/backup/app/KeyValueBackupAgent.java
index 155d8f9..c73731e 100644
--- a/tests/backup/app/src/android/backup/app/KeyValueBackupAgent.java
+++ b/tests/backup/app/src/android/backup/app/KeyValueBackupAgent.java
@@ -77,11 +77,13 @@
@Override
public void onQuotaExceeded(long backupDataBytes, long quotaBytes) {
+ super.onQuotaExceeded(backupDataBytes, quotaBytes);
Log.d(MainActivity.TAG, "Quota exceeded!");
}
@Override
public void onRestoreFinished() {
+ super.onRestoreFinished();
Log.d(MainActivity.TAG, "onRestoreFinished");
}
diff --git a/tests/core/runner/Android.bp b/tests/core/runner/Android.bp
deleted file mode 100644
index de3d724..0000000
--- a/tests/core/runner/Android.bp
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (C) 2009 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.
-
-//==========================================================
-// Build the core runner.
-//==========================================================
-
-// Build library
-java_library {
- name: "cts-core-test-runner",
-
- srcs: ["src/**/*.java"],
- static_libs: [
- "compatibility-device-util",
- "android-support-test",
- "vogarexpect",
- "testng",
- ],
-
- libs: ["android.test.runner.stubs"],
- sdk_version: "test_current",
-
-}
-
-//==========================================================
-// Build the run listener
-//==========================================================
-
-// Build library
-java_library {
- name: "cts-test-runner",
-
- srcs: ["src/com/android/cts/runner/**/*.java"],
- static_libs: ["android-support-test"],
- sdk_version: "current",
-
-}
diff --git a/tests/core/runner/AndroidManifest.xml b/tests/core/runner/AndroidManifest.xml
deleted file mode 100644
index 001e6f2..0000000
--- a/tests/core/runner/AndroidManifest.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.core.tests.runner">
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.core.tests.runner"
- android:label="cts framework tests"/>
-
-</manifest>
diff --git a/tests/core/runner/src/com/android/cts/core/runner/ExpectationBasedFilter.java b/tests/core/runner/src/com/android/cts/core/runner/ExpectationBasedFilter.java
deleted file mode 100644
index f409dbd..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/ExpectationBasedFilter.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2016 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.cts.core.runner;
-
-import android.os.Bundle;
-import android.util.Log;
-import com.google.common.base.Splitter;
-import java.io.IOException;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-import javax.annotation.Nullable;
-import org.junit.runner.Description;
-import org.junit.runner.manipulation.Filter;
-import org.junit.runners.ParentRunner;
-import org.junit.runners.Suite;
-import vogar.Expectation;
-import vogar.ExpectationStore;
-import vogar.ModeId;
-import vogar.Result;
-
-/**
- * Filter out tests/classes that are not requested or which are expected to fail.
- *
- * <p>This filter has to handle both a hierarchy of {@code Description descriptions} that looks
- * something like this:
- * <pre>
- * Suite
- * Suite
- * Suite
- * ParentRunner
- * Test
- * ...
- * ...
- * ParentRunner
- * Test
- * ...
- * ...
- * Suite
- * ParentRunner
- * Test
- * ...
- * ...
- * ...
- * </pre>
- *
- * <p>It cannot filter out the non-leaf nodes in the hierarchy, i.e. {@link Suite} and
- * {@link ParentRunner}, as that would prevent it from traversing the hierarchy and finding
- * the leaf nodes.
- */
-class ExpectationBasedFilter extends Filter {
-
- static final String TAG = "ExpectationBasedFilter";
-
- private static final String ARGUMENT_EXPECTATIONS = "core-expectations";
-
- private static final Splitter CLASS_LIST_SPLITTER = Splitter.on(',').trimResults();
-
- private final ExpectationStore expectationStore;
-
- private static List<String> getExpectationResourcePaths(Bundle args) {
- return CLASS_LIST_SPLITTER.splitToList(args.getString(ARGUMENT_EXPECTATIONS));
- }
-
- public ExpectationBasedFilter(Bundle args) {
- ExpectationStore expectationStore = null;
- try {
- // Get the set of resource names containing the expectations.
- Set<String> expectationResources = new LinkedHashSet<>(
- getExpectationResourcePaths(args));
- Log.i(TAG, "Loading expectations from: " + expectationResources);
- expectationStore = ExpectationStore.parseResources(
- getClass(), expectationResources, ModeId.DEVICE);
- } catch (IOException e) {
- Log.e(TAG, "Could not initialize ExpectationStore: ", e);
- }
-
- this.expectationStore = expectationStore;
- }
-
- @Override
- public boolean shouldRun(Description description) {
- // Only filter leaf nodes. The description is for a test if and only if it is a leaf node.
- // Non-leaf nodes must not be filtered out as that would prevent leaf nodes from being
- // visited in the case when we are traversing the hierarchy of classes.
- Description testDescription = getTestDescription(description);
- if (testDescription != null) {
- String className = testDescription.getClassName();
- String methodName = testDescription.getMethodName();
- String testName = className + "#" + methodName;
-
- if (expectationStore != null) {
- Expectation expectation = expectationStore.get(testName);
- if (expectation.getResult() != Result.SUCCESS) {
- Log.d(TAG, "Excluding test " + testDescription
- + " as it matches expectation: " + expectation);
- return false;
- }
- }
- }
-
- return true;
- }
-
- private Description getTestDescription(Description description) {
- List<Description> children = description.getChildren();
- // An empty description is by definition a test.
- if (children.isEmpty()) {
- return description;
- }
-
- // Handle initialization errors that were wrapped in an ErrorReportingRunner as a special
- // case. This is needed because ErrorReportingRunner is treated as a suite of Throwables,
- // (where each Throwable corresponds to a test called initializationError) and so its
- // description contains children, one for each Throwable, and so is not treated as a test
- // to filter. Unfortunately, it does not support Filterable so this filter is never applied
- // to its children.
- // See https://github.com/junit-team/junit/issues/1253
- Description child = children.get(0);
- String methodName = child.getMethodName();
- if ("initializationError".equals(methodName)) {
- return child;
- }
-
- return null;
- }
-
- @Override
- public String describe() {
- return "TestFilter";
- }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/SingleTestNGTestRunListener.java b/tests/core/runner/src/com/android/cts/core/runner/support/SingleTestNGTestRunListener.java
deleted file mode 100644
index 7a68a8b..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/support/SingleTestNGTestRunListener.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2016 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.cts.core.runner.support;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-/**
- * Listener for TestNG runs that provides gtest-like console output.
- *
- * Prints a message like [RUN], [OK], [ERROR], [SKIP] to stdout
- * as tests are being executed with their status.
- *
- * This output is also saved as the device logs (logcat) when the test is run through
- * cts-tradefed.
- */
-public class SingleTestNGTestRunListener implements org.testng.ITestListener {
- private int mTestStarted = 0;
-
- private Map<String, Throwable> failures = new LinkedHashMap<>();
-
- private static class Prefixes {
- @SuppressWarnings("unused")
- private static final String INFORMATIONAL_MARKER = "[----------]";
- private static final String START_TEST_MARKER = "[ RUN ]";
- private static final String OK_TEST_MARKER = "[ OK ]";
- private static final String ERROR_TEST_RUN_MARKER = "[ ERROR ]";
- private static final String SKIPPED_TEST_MARKER = "[ SKIP ]";
- private static final String TEST_RUN_MARKER = "[==========]";
- }
-
- // How many tests did TestNG *actually* try to run?
- public int getNumTestStarted() {
- return mTestStarted;
- }
-
- public Map<String, Throwable> getFailures() {
- return Collections.unmodifiableMap(failures);
- }
-
- @Override
- public void onFinish(org.testng.ITestContext context) {
- System.out.println(String.format("%s", Prefixes.TEST_RUN_MARKER));
- }
-
- @Override
- public void onStart(org.testng.ITestContext context) {
- System.out.println(String.format("%s", Prefixes.INFORMATIONAL_MARKER));
- }
-
- @Override
- public void onTestFailedButWithinSuccessPercentage(org.testng.ITestResult result) {
- onTestFailure(result);
- }
-
- @Override
- public void onTestFailure(org.testng.ITestResult result) {
- // All failures are coalesced into one '[ FAILED ]' message at the end
- // This is because a single test method can run multiple times with different parameters.
- // Since we only test a single method, it's safe to combine all failures into one
- // failure at the end.
- //
- // The big pass/fail is printed from SingleTestNGTestRunner, not from the listener.
- String id = getId(result);
- Throwable throwable = result.getThrowable();
- System.out.println(String.format("%s %s ::: %s", Prefixes.ERROR_TEST_RUN_MARKER,
- id, stringify(throwable)));
- failures.put(id, throwable);
- }
-
- @Override
- public void onTestSkipped(org.testng.ITestResult result) {
- System.out.println(String.format("%s %s", Prefixes.SKIPPED_TEST_MARKER,
- getId(result)));
- }
-
- @Override
- public void onTestStart(org.testng.ITestResult result) {
- mTestStarted++;
- System.out.println(String.format("%s %s", Prefixes.START_TEST_MARKER,
- getId(result)));
- }
-
- @Override
- public void onTestSuccess(org.testng.ITestResult result) {
- System.out.println(String.format("%s", Prefixes.OK_TEST_MARKER));
- }
-
- private String getId(org.testng.ITestResult test) {
- // TestNG is quite complicated since tests can have arbitrary parameters.
- // Use its code to stringify a result name instead of doing it ourselves.
-
- org.testng.remote.strprotocol.TestResultMessage msg =
- new org.testng.remote.strprotocol.TestResultMessage(
- null, /*suite name*/
- null, /*test name -- display the test method name instead */
- test);
-
- String className = test.getTestClass().getName();
- //String name = test.getMethod().getMethodName();
- return String.format("%s#%s", className, msg.toDisplayString());
-
- }
-
- private String stringify(Throwable error) {
- return Arrays.toString(error.getStackTrace()).replaceAll("\n", " ");
- }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/SingleTestNgTestExecutor.java b/tests/core/runner/src/com/android/cts/core/runner/support/SingleTestNgTestExecutor.java
deleted file mode 100644
index deb18df..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/support/SingleTestNgTestExecutor.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2016 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.cts.core.runner.support;
-
-import android.util.Log;
-
-import org.testng.TestNG;
-import org.testng.xml.XmlClass;
-import org.testng.xml.XmlInclude;
-import org.testng.xml.XmlSuite;
-import org.testng.xml.XmlTest;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Test executor to run a single TestNG test method.
- */
-public class SingleTestNgTestExecutor {
- // Execute any method which is in the class klass.
- // The klass is passed in separately to handle inherited methods only.
- // Returns true if all tests pass, false otherwise.
- public static Result execute(Class<?> klass, String methodName) {
- if (klass == null) {
- throw new NullPointerException("klass must not be null");
- }
-
- if (methodName == null) {
- throw new NullPointerException("methodName must not be null");
- }
-
- //if (!method.getDeclaringClass().isAssignableFrom(klass)) {
- // throw new IllegalArgumentException("klass must match method's declaring class");
- //}
-
- SingleTestNGTestRunListener listener = new SingleTestNGTestRunListener();
-
- // Although creating a new testng "core" every time might seem heavyweight, in practice
- // it seems to take a mere few milliseconds at most.
- // Since we're running all the parameteric combinations of a test,
- // this ends up being neglible relative to that.
- TestNG testng = createTestNG(klass.getName(), methodName, listener);
- testng.run();
-
- if (listener.getNumTestStarted() <= 0) {
- // It's possible to be invoked here with an arbitrary method name
- // so print out a warning incase TestNG actually had a no-op.
- Log.w("TestNgExec", "execute class " + klass.getName() + ", method " + methodName +
- " had 0 tests executed. Not a test method?");
- }
-
- return new Result(testng.hasFailure(), listener.getFailures());
- }
-
- private static org.testng.TestNG createTestNG(String klass, String method,
- SingleTestNGTestRunListener listener) {
- org.testng.TestNG testng = new org.testng.TestNG();
- testng.setUseDefaultListeners(false); // Don't create the testng-specific HTML/XML reports.
- // It still prints the X/Y tests succeeded/failed summary to stdout.
-
- // We don't strictly need this listener for CTS, but having it print SUCCESS/FAIL
- // makes it easier to diagnose which particular combination of a test method had failed
- // from looking at device logcat.
- testng.addListener(listener);
-
- /* Construct the following equivalent XML configuration:
- *
- * <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
- * <suite>
- * <test>
- * <classes>
- * <class name="$klass">
- * <include name="$method" />
- * </class>
- * </classes>
- * </test>
- * </suite>
- *
- * This will ensure that only a single klass/method is being run by testng.
- * (It can still be run multiple times due to @DataProvider, with different parameters
- * each time)
- */
- List<XmlSuite> suites = new ArrayList<>();
- XmlSuite the_suite = new XmlSuite();
- XmlTest the_test = new XmlTest(the_suite);
- XmlClass the_class = new XmlClass(klass);
- XmlInclude the_include = new XmlInclude(method);
-
- the_class.getIncludedMethods().add(the_include);
- the_test.getXmlClasses().add(the_class);
- suites.add(the_suite);
- testng.setXmlSuites(suites);
-
- return testng;
- }
-
- public static class Result {
- private final boolean hasFailure;
- private final Map<String,Throwable> failures;
-
-
- Result(boolean hasFailure, Map<String, Throwable> failures) {
- this.hasFailure = hasFailure;
- this.failures = Collections.unmodifiableMap(new LinkedHashMap<>(failures));
- }
-
- public boolean hasFailure() {
- return hasFailure;
- }
-
- public Map<String, Throwable> getFailures() {
- return failures;
- }
- }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/TestNgRunner.java b/tests/core/runner/src/com/android/cts/core/runner/support/TestNgRunner.java
deleted file mode 100644
index d9bf037..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/support/TestNgRunner.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2016 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.cts.core.runner.support;
-
-import android.util.Log;
-
-import org.junit.runner.Description;
-import org.junit.runner.Runner;
-import org.junit.runner.manipulation.Filter;
-import org.junit.runner.manipulation.Filterable;
-import org.junit.runner.manipulation.NoTestsRemainException;
-import org.junit.runner.notification.Failure;
-import org.junit.runner.notification.RunNotifier;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.HashSet;
-import java.util.Map;
-
-/**
- * A {@link Runner} that can TestNG tests.
- *
- * <p>Implementation note: Avoid extending ParentRunner since that also has
- * logic to handle BeforeClass/AfterClass and other junit-specific functionality
- * that would be invalid for TestNG.</p>
- */
-class TestNgRunner extends Runner implements Filterable {
-
- private static final boolean DEBUG = false;
-
- private Description mDescription;
- /** Class name for debugging. */
- private String mClassName;
- /** Don't include the same method names twice. */
- private HashSet<String> mMethodSet = new HashSet<>();
-
- /**
- * @param testClass the test class to run
- */
- TestNgRunner(Class<?> testClass) {
- mDescription = generateTestNgDescription(testClass);
- mClassName = testClass.getName();
- }
-
- // Runner implementation
- @Override
- public Description getDescription() {
- return mDescription;
- }
-
- // Runner implementation
- @Override
- public int testCount() {
- if (!descriptionHasChildren(getDescription())) { // Avoid NPE when description is null.
- return 0;
- }
-
- // We always follow a flat Parent->Leaf hierarchy, so no recursion necessary.
- return getDescription().testCount();
- }
-
- // Filterable implementation
- @Override
- public void filter(Filter filter) throws NoTestsRemainException {
- mDescription = filterDescription(mDescription, filter);
-
- if (!descriptionHasChildren(getDescription())) { // Avoid NPE when description is null.
- if (DEBUG) {
- Log.d("TestNgRunner",
- "Filtering has removed all tests :( for class " + mClassName);
- }
- throw new NoTestsRemainException();
- }
-
- if (DEBUG) {
- Log.d("TestNgRunner",
- "Filtering has retained " + testCount() + " tests for class " + mClassName);
- }
- }
-
- // Filterable implementation
- @Override
- public void run(RunNotifier notifier) {
- if (!descriptionHasChildren(getDescription())) { // Avoid NPE when description is null.
- // Nothing to do.
- return;
- }
-
- for (Description child : getDescription().getChildren()) {
- String className = child.getClassName();
- String methodName = child.getMethodName();
-
- Class<?> klass;
- try {
- klass = Class.forName(className, false, Thread.currentThread().getContextClassLoader());
- } catch (ClassNotFoundException e) {
- throw new AssertionError(e);
- }
-
- notifier.fireTestStarted(child);
-
- // Avoid looking at all the methods by just using the string method name.
- SingleTestNgTestExecutor.Result result = SingleTestNgTestExecutor.execute(klass, methodName);
- if (result.hasFailure()) {
- // TODO: get the error messages from testng somehow.
- notifier.fireTestFailure(new Failure(child, extractException(result.getFailures())));
- }
-
- notifier.fireTestFinished(child);
- // TODO: Check @Test(enabled=false) and invoke #fireTestIgnored instead.
- }
- }
-
- private Throwable extractException(Map<String, Throwable> failures) {
- if (failures.isEmpty()) {
- return new AssertionError();
- }
- if (failures.size() == 1) {
- return failures.values().iterator().next();
- }
-
- StringBuilder errorMessage = new StringBuilder("========== Multiple Failures ==========");
- for (Map.Entry<String, Throwable> failureEntry : failures.entrySet()) {
- errorMessage.append("\n\n=== "). append(failureEntry.getKey()).append(" ===\n");
- Throwable throwable = failureEntry.getValue();
- errorMessage
- .append(throwable.getClass()).append(": ")
- .append(throwable.getMessage());
- for (StackTraceElement e : throwable.getStackTrace()) {
- if (e.getClassName().equals(getClass().getName())) {
- break;
- }
- errorMessage.append("\n at ").append(e);
- }
- }
- errorMessage.append("\n=======================================\n\n");
- return new AssertionError(errorMessage.toString());
- }
-
-
- /**
- * Recursively (preorder traversal) apply the filter to all the descriptions.
- *
- * @return null if the filter rejects the whole tree.
- */
- private static Description filterDescription(Description desc, Filter filter) {
- if (!filter.shouldRun(desc)) { // XX: Does the filter itself do the recursion?
- return null;
- }
-
- Description newDesc = desc.childlessCopy();
-
- // Return leafs.
- if (!descriptionHasChildren(desc)) {
- return newDesc;
- }
-
- // Filter all subtrees, only copying them if the filter accepts them.
- for (Description child : desc.getChildren()) {
- Description filteredChild = filterDescription(child, filter);
-
- if (filteredChild != null) {
- newDesc.addChild(filteredChild);
- }
- }
-
- return newDesc;
- }
-
- private Description generateTestNgDescription(Class<?> cls) {
- // Add the overall class description as the parent.
- Description parent = Description.createSuiteDescription(cls);
-
- if (DEBUG) {
- Log.d("TestNgRunner", "Generating TestNg Description for class " + cls.getName());
- }
-
- // Add each test method as a child.
- for (Method m : cls.getDeclaredMethods()) {
-
- // Filter to only 'public void' signatures.
- if ((m.getModifiers() & Modifier.PUBLIC) == 0) {
- continue;
- }
-
- if (!m.getReturnType().equals(Void.TYPE)) {
- continue;
- }
-
- // Note that TestNG methods may actually have parameters
- // (e.g. with @DataProvider) which TestNG will populate itself.
-
- // Add [Class, MethodName] as a Description leaf node.
- String name = m.getName();
-
- if (!mMethodSet.add(name)) {
- // Overloaded methods have the same name, don't add them twice.
- if (DEBUG) {
- Log.d("TestNgRunner", "Already added child " + cls.getName() + "#" + name);
- }
- continue;
- }
-
- Description child = Description.createTestDescription(cls, name);
-
- parent.addChild(child);
-
- if (DEBUG) {
- Log.d("TestNgRunner", "Add child " + cls.getName() + "#" + name);
- }
- }
-
- return parent;
- }
-
- private static boolean descriptionHasChildren(Description desc) {
- // Note: Although "desc.isTest()" is equivalent to "!desc.getChildren().isEmpty()"
- // we add the pre-requisite 2 extra null checks to avoid throwing NPEs.
- return desc != null && desc.getChildren() != null && !desc.getChildren().isEmpty();
- }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/TestNgRunnerBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/TestNgRunnerBuilder.java
deleted file mode 100644
index 2f084b3..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/support/TestNgRunnerBuilder.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2016 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.cts.core.runner.support;
-
-import java.lang.reflect.Method;
-
-import org.junit.runner.Runner;
-import org.junit.runners.model.RunnerBuilder;
-
-import org.testng.annotations.Test;
-
-/**
- * A {@link RunnerBuilder} that can handle TestNG tests.
- */
-public class TestNgRunnerBuilder extends RunnerBuilder {
- // Returns a TestNG runner for this class, only if it is a class
- // annotated with testng's @Test or has any methods with @Test in it.
- @Override
- public Runner runnerForClass(Class<?> testClass) {
- if (isTestNgTestClass(testClass)) {
- return new TestNgRunner(testClass);
- }
-
- return null;
- }
-
- private static boolean isTestNgTestClass(Class<?> cls) {
- // TestNG test is either marked @Test at the class
- if (cls.getAnnotation(Test.class) != null) {
- return true;
- }
-
- // Or It's marked @Test at the method level
- for (Method m : cls.getDeclaredMethods()) {
- if (m.getAnnotation(Test.class) != null) {
- return true;
- }
- }
-
- return false;
- }
-}
diff --git a/tests/core/runner/src/com/android/cts/runner/CrashParserRunListener.java b/tests/core/runner/src/com/android/cts/runner/CrashParserRunListener.java
deleted file mode 100644
index fbbb684..0000000
--- a/tests/core/runner/src/com/android/cts/runner/CrashParserRunListener.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.runner;
-
-import android.support.test.internal.runner.listener.InstrumentationRunListener;
-import android.util.Log;
-import org.junit.runner.Description;
-
-/**
- * A {@link RunListener} for CrashParser. Dumps the test name to logs when
- * tests start.
- */
-public class CrashParserRunListener extends InstrumentationRunListener {
-
- private static final String TAG = "CrashParserRunListener";
-
- // Constant must be kept in sync with CrashUtils.java
- public static final String NEW_TEST_ALERT = "New test starting with name: ";
-
- @Override
- public void testStarted(Description description) throws Exception {
- Log.i(TAG, NEW_TEST_ALERT + description.toString());
- }
-
-}
diff --git a/tests/core/runner/src/com/android/cts/runner/CtsTestRunListener.java b/tests/core/runner/src/com/android/cts/runner/CtsTestRunListener.java
deleted file mode 100644
index 1f9a939..0000000
--- a/tests/core/runner/src/com/android/cts/runner/CtsTestRunListener.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (C) 2014 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.cts.runner;
-
-import android.app.ActivityManager;
-import android.app.Instrumentation;
-import android.app.KeyguardManager;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.support.test.internal.runner.listener.InstrumentationRunListener;
-import android.text.TextUtils;
-import android.util.Log;
-
-import junit.framework.TestCase;
-
-import org.junit.runner.Description;
-import org.junit.runner.notification.RunListener;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.lang.Class;
-import java.lang.ReflectiveOperationException;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.net.Authenticator;
-import java.net.CookieHandler;
-import java.net.ResponseCache;
-import java.text.DateFormat;
-import java.util.Locale;
-import java.util.Properties;
-import java.util.TimeZone;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLSocketFactory;
-
-/**
- * A {@link RunListener} for CTS. Sets the system properties necessary for many
- * core tests to run. This is needed because there are some core tests that need
- * writing access to the file system.
- * Finally, we add a means to free memory allocated by a TestCase after its
- * execution.
- */
-public class CtsTestRunListener extends InstrumentationRunListener {
-
- private static final String TAG = "CtsTestRunListener";
-
- private TestEnvironment mEnvironment;
- private Class<?> lastClass;
-
- @Override
- public void testRunStarted(Description description) throws Exception {
- mEnvironment = new TestEnvironment(getInstrumentation().getTargetContext());
-
- // We might want to move this to /sdcard, if is is mounted/writable.
- File cacheDir = getInstrumentation().getTargetContext().getCacheDir();
- System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
-
- // attempt to disable keyguard, if current test has permission to do so
- // TODO: move this to a better place, such as InstrumentationTestRunner
- // ?
- if (getInstrumentation().getContext().checkCallingOrSelfPermission(
- android.Manifest.permission.DISABLE_KEYGUARD)
- == PackageManager.PERMISSION_GRANTED) {
- Log.i(TAG, "Disabling keyguard");
- KeyguardManager keyguardManager =
- (KeyguardManager) getInstrumentation().getContext().getSystemService(
- Context.KEYGUARD_SERVICE);
- keyguardManager.newKeyguardLock("cts").disableKeyguard();
- } else {
- Log.i(TAG, "Test lacks permission to disable keyguard. " +
- "UI based tests may fail if keyguard is up");
- }
- }
-
- @Override
- public void testStarted(Description description) throws Exception {
- if (description.getTestClass() != lastClass) {
- lastClass = description.getTestClass();
- printMemory(description.getTestClass());
- }
-
- mEnvironment.reset();
- }
-
- @Override
- public void testFinished(Description description) {
- // no way to implement this in JUnit4...
- // offending test cases that need this logic should probably be cleaned
- // up individually
- // if (test instanceof TestCase) {
- // cleanup((TestCase) test);
- // }
- }
-
- /**
- * Dumps some memory info.
- */
- private void printMemory(Class<?> testClass) {
- Runtime runtime = Runtime.getRuntime();
-
- long total = runtime.totalMemory();
- long free = runtime.freeMemory();
- long used = total - free;
-
- Log.d(TAG, "Total memory : " + total);
- Log.d(TAG, "Used memory : " + used);
- Log.d(TAG, "Free memory : " + free);
-
- String tempdir = System.getProperty("java.io.tmpdir", "");
- // TODO: Remove these extra Logs added to debug a specific timeout problem.
- Log.d(TAG, "java.io.tmpdir is:" + tempdir);
-
- if (!TextUtils.isEmpty(tempdir)) {
- String[] commands = {"df", tempdir};
- BufferedReader in = null;
- try {
- Log.d(TAG, "About to .exec df");
- Process proc = runtime.exec(commands);
- Log.d(TAG, ".exec returned");
- in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
- Log.d(TAG, "Stream reader created");
- String line;
- while ((line = in.readLine()) != null) {
- Log.d(TAG, line);
- }
- } catch (IOException e) {
- Log.d(TAG, "Exception: " + e.toString());
- // Well, we tried
- } finally {
- Log.d(TAG, "In finally");
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {
- // Meh
- }
- }
- }
- }
-
- Log.d(TAG, "Now executing : " + testClass.getName());
- }
-
- /**
- * Nulls all non-static reference fields in the given test class. This
- * method helps us with those test classes that don't have an explicit
- * tearDown() method. Normally the garbage collector should take care of
- * everything, but since JUnit keeps references to all test cases, a little
- * help might be a good idea.
- */
- private void cleanup(TestCase test) {
- Class<?> clazz = test.getClass();
-
- while (clazz != TestCase.class) {
- Field[] fields = clazz.getDeclaredFields();
- for (int i = 0; i < fields.length; i++) {
- Field f = fields[i];
- if (!f.getType().isPrimitive() &&
- !Modifier.isStatic(f.getModifiers())) {
- try {
- f.setAccessible(true);
- f.set(test, null);
- } catch (Exception ignored) {
- // Nothing we can do about it.
- }
- }
- }
-
- clazz = clazz.getSuperclass();
- }
- }
-
- // http://code.google.com/p/vogar/source/browse/trunk/src/vogar/target/TestEnvironment.java
- static class TestEnvironment {
- private static final Field sDateFormatIs24HourField;
- static {
- try {
- Class<?> dateFormatClass = Class.forName("java.text.DateFormat");
- sDateFormatIs24HourField = dateFormatClass.getDeclaredField("is24Hour");
- } catch (ReflectiveOperationException e) {
- throw new AssertionError("Missing DateFormat.is24Hour", e);
- }
- }
-
- private final Locale mDefaultLocale;
- private final TimeZone mDefaultTimeZone;
- private final HostnameVerifier mHostnameVerifier;
- private final SSLSocketFactory mSslSocketFactory;
- private final Properties mProperties = new Properties();
- private final Boolean mDefaultIs24Hour;
-
- TestEnvironment(Context context) {
- mDefaultLocale = Locale.getDefault();
- mDefaultTimeZone = TimeZone.getDefault();
- mHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
- mSslSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
-
- mProperties.setProperty("user.home", "");
- mProperties.setProperty("java.io.tmpdir", context.getCacheDir().getAbsolutePath());
- // The CDD mandates that devices that support WiFi are the only ones that will have
- // multicast.
- PackageManager pm = context.getPackageManager();
- mProperties.setProperty("android.cts.device.multicast",
- Boolean.toString(pm.hasSystemFeature(PackageManager.FEATURE_WIFI)));
- mDefaultIs24Hour = getDateFormatIs24Hour();
-
- // There are tests in libcore that should be disabled for low ram devices. They can't
- // access ActivityManager to call isLowRamDevice, but can read system properties.
- ActivityManager activityManager =
- (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
- mProperties.setProperty("android.cts.device.lowram",
- Boolean.toString(activityManager.isLowRamDevice()));
- }
-
- void reset() {
- System.setProperties(null);
- System.setProperties(mProperties);
- Locale.setDefault(mDefaultLocale);
- TimeZone.setDefault(mDefaultTimeZone);
- Authenticator.setDefault(null);
- CookieHandler.setDefault(null);
- ResponseCache.setDefault(null);
- HttpsURLConnection.setDefaultHostnameVerifier(mHostnameVerifier);
- HttpsURLConnection.setDefaultSSLSocketFactory(mSslSocketFactory);
- setDateFormatIs24Hour(mDefaultIs24Hour);
- }
-
- private static Boolean getDateFormatIs24Hour() {
- try {
- return (Boolean) sDateFormatIs24HourField.get(null);
- } catch (ReflectiveOperationException e) {
- throw new AssertionError("Unable to get java.text.DateFormat.is24Hour", e);
- }
- }
-
- private static void setDateFormatIs24Hour(Boolean value) {
- try {
- sDateFormatIs24HourField.set(null, value);
- } catch (ReflectiveOperationException e) {
- throw new AssertionError("Unable to set java.text.DateFormat.is24Hour", e);
- }
- }
- }
-
-}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java
index c83cb2e..87039b3 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java
@@ -29,9 +29,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.fail;
import android.content.ComponentName;
import android.platform.test.annotations.Presubmit;
@@ -40,9 +38,6 @@
import org.junit.Test;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
/**
* Build/Install/Run:
* atest CtsWindowManagerDeviceTestCases:AmStartOptionsTests
@@ -92,9 +87,10 @@
// Start LaunchingActivity again and finish TestActivity
final int flags =
FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP;
- final String result = executeShellCommand(
- "am start -W -f " + flags + " -n " + getActivityName(LAUNCHING_ACTIVITY));
- verifyShellOutput(result, LAUNCHING_ACTIVITY, false);
+ executeShellCommand("am start -W -f " + flags + " -n " + getActivityName(LAUNCHING_ACTIVITY)
+ + " --display " + DEFAULT_DISPLAY);
+ waitAndAssertTopResumedActivity(LAUNCHING_ACTIVITY, DEFAULT_DISPLAY,
+ "Activity must be launched.");
}
private void testDashW(final ComponentName entryActivity, final ComponentName actualActivity)
@@ -112,73 +108,14 @@
private void startActivityAndVerifyResult(final ComponentName entryActivity,
final ComponentName actualActivity, boolean shouldStart) {
- // See TODO below
- // final LogSeparator logSeparator = separateLogs();
-
// Pass in different data only when cold starting. This is to make the intent
// different in subsequent warm/hot launches, so that the entrypoint alias
// activity is always started, but the actual activity is not started again
// because of the NEW_TASK and singleTask flags.
- final String result = executeShellCommand(
- "am start -n " + getActivityName(entryActivity) + " -W"
- + (shouldStart ? " -d about:blank" : ""));
+ executeShellCommand("am start -n " + getActivityName(entryActivity) + " -W --display "
+ + DEFAULT_DISPLAY + (shouldStart ? " -d about:blank" : ""));
- // Verify shell command return value
- verifyShellOutput(result, actualActivity, shouldStart);
-
- // TODO: Disable logcat check for now.
- // Logcat of WM or AM tag could be lost (eg. chatty if earlier events generated
- // too many lines), and make the test look flaky. We need to either use event
- // log or swith to other mechanisms. Only verify shell output for now, it should
- // still catch most failures.
-
- // Verify adb logcat log
- //verifyLogcat(actualActivity, shouldStart, logSeparator);
- }
-
- private static final Pattern sNotStartedWarningPattern = Pattern.compile(
- "Warning: Activity not started(.*)");
- private static final Pattern sStatusPattern = Pattern.compile(
- "Status: (.*)");
- private static final Pattern sActivityPattern = Pattern.compile(
- "Activity: (.*)");
- private static final String sStatusOk = "ok";
-
- private void verifyShellOutput(
- final String result, final ComponentName activity, boolean shouldStart) {
- boolean warningFound = false;
- String status = null;
- String reportedActivity = null;
-
- final String[] lines = result.split("\\n");
- // Going from the end of logs to beginning in case if some other activity is started first.
- for (int i = lines.length - 1; i >= 0; i--) {
- final String line = lines[i].trim();
- Matcher matcher = sNotStartedWarningPattern.matcher(line);
- if (matcher.matches()) {
- warningFound = true;
- continue;
- }
- matcher = sStatusPattern.matcher(line);
- if (matcher.matches()) {
- status = matcher.group(1);
- continue;
- }
- matcher = sActivityPattern.matcher(line);
- if (matcher.matches()) {
- reportedActivity = matcher.group(1);
- continue;
- }
- }
-
- assertEquals("Status is ok", sStatusOk, status);
- assertEquals("Reported activity is " + getActivityName(activity),
- getActivityName(activity), reportedActivity);
-
- if (shouldStart && warningFound) {
- fail("Should start new activity but brought something to front.");
- } else if (!shouldStart && !warningFound){
- fail("Should bring existing activity to front but started new activity.");
- }
+ waitAndAssertTopResumedActivity(actualActivity, DEFAULT_DISPLAY,
+ "Activity must be launched");
}
}
diff --git a/tests/leanbackjank/OWNERS b/tests/leanbackjank/OWNERS
new file mode 100644
index 0000000..729b9b6
--- /dev/null
+++ b/tests/leanbackjank/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 188489
+dake@google.com
\ No newline at end of file
diff --git a/tests/perfetto/OWNERS b/tests/perfetto/OWNERS
new file mode 100644
index 0000000..05798d7
--- /dev/null
+++ b/tests/perfetto/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 323270
+primiano@google.com
+lalitm@google.com
diff --git a/tests/rollback/OWNERS b/tests/rollback/OWNERS
new file mode 100644
index 0000000..5a631b6
--- /dev/null
+++ b/tests/rollback/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 557916
+include /hostsidetests/rollback/OWNERS
diff --git a/tests/sample/OWNERS b/tests/sample/OWNERS
new file mode 100644
index 0000000..7782fbe
--- /dev/null
+++ b/tests/sample/OWNERS
@@ -0,0 +1,10 @@
+# Bug component: 346961
+diqian@google.com
+fdeng@google.com
+moonk@google.com
+normancheung@google.com
+williamgoh@google.com
+peykov@google.com
+yichunli@google.com
+yimingpan@google.com
+
diff --git a/tests/tests/animation/OWNERS b/tests/tests/animation/OWNERS
new file mode 100644
index 0000000..475f1b8
--- /dev/null
+++ b/tests/tests/animation/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 47085
+tianliu@google.com
+mount@google.com
+andreykulikov@google.com
diff --git a/tests/tests/batterysaving/OWNERS b/tests/tests/batterysaving/OWNERS
new file mode 100644
index 0000000..1fe2293
--- /dev/null
+++ b/tests/tests/batterysaving/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 330055
+omakoto@google.com
+yamasani@google.com
diff --git a/tests/tests/externalservice/OWNERS b/tests/tests/externalservice/OWNERS
new file mode 100644
index 0000000..210a568
--- /dev/null
+++ b/tests/tests/externalservice/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 76427
+maco@google.com
+narayan@google.com
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png
index e3be1d1..e67fce8 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png
index ce18075..8a48104 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png
index f991189..2145eec 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_repeat_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_repeat_golden.png
index f2798b4..5428052 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_repeat_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_repeat_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
index aee71ec..70ee76a 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
index a879e3c..0a195a8 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
Binary files differ
diff --git a/tests/tests/graphics/src/android/graphics/cts/CameraTest.java b/tests/tests/graphics/src/android/graphics/cts/CameraTest.java
index ff8f77c..92f6322 100644
--- a/tests/tests/graphics/src/android/graphics/cts/CameraTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/CameraTest.java
@@ -91,8 +91,8 @@
float[] f = new float[9];
m2.getValues(f);
assertArrayEquals(new float[] {
- 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.0017361111f, 1.0f
- }, f, 0.0f);
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
+ }, f, 0.0017361111f);
}
@Test
@@ -107,8 +107,8 @@
float[] f = new float[9];
m2.getValues(f);
assertArrayEquals(new float[] {
- 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0017361111f, 0.0f, 1.0f
- }, f, 0.0f);
+ 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f
+ }, f, 0.0017361111f);
}
@Test
@@ -124,7 +124,7 @@
m2.getValues(f);
assertArrayEquals(new float[] {
0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
- }, f, 0.0f);
+ }, f, 0.0017361111f);
}
@Test
diff --git a/tests/tests/jni/OWNERS b/tests/tests/jni/OWNERS
new file mode 100644
index 0000000..29fea99
--- /dev/null
+++ b/tests/tests/jni/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 86431
+include /hostsidetests/classloaders/OWNERS
diff --git a/tests/tests/media/Android.bp b/tests/tests/media/Android.bp
index e8be516..b066af1 100644
--- a/tests/tests/media/Android.bp
+++ b/tests/tests/media/Android.bp
@@ -40,7 +40,6 @@
"truth-prebuilt",
"mockito-target-minus-junit4",
"androidx.heifwriter_heifwriter",
- "androidx.media2_media2",
],
jni_libs: [
"libaudio_jni",
diff --git a/tests/tests/media/src/android/media/cts/AudioPlaybackConfigurationTest.java b/tests/tests/media/src/android/media/cts/AudioPlaybackConfigurationTest.java
index 6256175..21f7a1b 100644
--- a/tests/tests/media/src/android/media/cts/AudioPlaybackConfigurationTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioPlaybackConfigurationTest.java
@@ -33,6 +33,7 @@
import android.media.AudioPlaybackConfiguration;
import com.android.compatibility.common.util.CtsAndroidTestCase;
+import com.android.internal.annotations.GuardedBy;
import java.lang.reflect.Method;
import java.util.ArrayList;
@@ -361,16 +362,16 @@
}
private static class MyAudioPlaybackCallback extends AudioManager.AudioPlaybackCallback {
- private int mCalled = 0;
- private int mNbConfigs = 0;
- private List<AudioPlaybackConfiguration> mConfigs;
private final Object mCbLock = new Object();
+ @GuardedBy("mCbLock")
+ private int mCalled;
+ @GuardedBy("mCbLock")
+ private List<AudioPlaybackConfiguration> mConfigs;
void reset() {
synchronized (mCbLock) {
mCalled = 0;
- mNbConfigs = 0;
- mConfigs.clear();
+ mConfigs = new ArrayList<AudioPlaybackConfiguration>();
}
}
@@ -381,9 +382,7 @@
}
int getNbConfigs() {
- synchronized (mCbLock) {
- return mNbConfigs;
- }
+ return getConfigs().size();
}
List<AudioPlaybackConfiguration> getConfigs() {
@@ -393,13 +392,13 @@
}
MyAudioPlaybackCallback() {
+ reset();
}
@Override
public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
synchronized (mCbLock) {
mCalled++;
- mNbConfigs = configs.size();
mConfigs = configs;
}
}
diff --git a/tests/tests/midi/OWNERS b/tests/tests/midi/OWNERS
new file mode 100644
index 0000000..e78e1d0
--- /dev/null
+++ b/tests/tests/midi/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 1344
+philburk@google.com
diff --git a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
index 91949db..42d3057 100644
--- a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
+++ b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
@@ -1556,10 +1556,7 @@
}
}
} else {
- // TODO(b/123042748): The fact that glEGLImageTargetTexStorageEXT does not work for YUV
- // textures is a bug. The condition for the target should be removed
- // once the bug is fixed.
- if (HasGLExtension("GL_EXT_EGL_image_storage") && mTexTarget != GL_TEXTURE_EXTERNAL_OES) {
+ if (HasGLExtension("GL_EXT_EGL_image_storage")) {
glEGLImageTargetTexStorageEXT(mTexTarget, static_cast<GLeglImageOES>(mEGLImage),
nullptr);
} else {
diff --git a/tests/tests/nativemedia/sl/OWNERS b/tests/tests/nativemedia/sl/OWNERS
new file mode 100644
index 0000000..38b4a35
--- /dev/null
+++ b/tests/tests/nativemedia/sl/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 1344
+jmtrivi@google.com
diff --git a/tests/tests/nativemedia/xa/OWNERS b/tests/tests/nativemedia/xa/OWNERS
new file mode 100644
index 0000000..90b75e4
--- /dev/null
+++ b/tests/tests/nativemedia/xa/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 1344
+include ../sl/OWNERS
diff --git a/tests/tests/nativemidi/OWNERS b/tests/tests/nativemidi/OWNERS
new file mode 100644
index 0000000..ce5adf1
--- /dev/null
+++ b/tests/tests/nativemidi/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 48436
+pmclean@google.com
\ No newline at end of file
diff --git a/tests/tests/netsecpolicy/OWNERS b/tests/tests/netsecpolicy/OWNERS
new file mode 100644
index 0000000..fdd42d8
--- /dev/null
+++ b/tests/tests/netsecpolicy/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 36824
+include ../networksecurityconfig/OWNERS
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-attributes/OWNERS b/tests/tests/networksecurityconfig/networksecurityconfig-attributes/OWNERS
deleted file mode 100644
index 7705bfe..0000000
--- a/tests/tests/networksecurityconfig/networksecurityconfig-attributes/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# Inherits OWNERS from parent directory.
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/OWNERS b/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/OWNERS
deleted file mode 100644
index 7705bfe..0000000
--- a/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# Inherits OWNERS from parent directory.
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext-pre-P/OWNERS b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext-pre-P/OWNERS
deleted file mode 100644
index 7705bfe..0000000
--- a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext-pre-P/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# Inherits OWNERS from parent directory.
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/OWNERS b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/OWNERS
deleted file mode 100644
index 7705bfe..0000000
--- a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# Inherits OWNERS from parent directory.
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/OWNERS b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/OWNERS
deleted file mode 100644
index 7705bfe..0000000
--- a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# Inherits OWNERS from parent directory.
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/OWNERS b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/OWNERS
deleted file mode 100644
index 7705bfe..0000000
--- a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# Inherits OWNERS from parent directory.
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/OWNERS b/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/OWNERS
deleted file mode 100644
index 7705bfe..0000000
--- a/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# Inherits OWNERS from parent directory.
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/OWNERS b/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/OWNERS
deleted file mode 100644
index 7705bfe..0000000
--- a/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# Inherits OWNERS from parent directory.
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/OWNERS b/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/OWNERS
deleted file mode 100644
index 7705bfe..0000000
--- a/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# Inherits OWNERS from parent directory.
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/OWNERS b/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/OWNERS
deleted file mode 100644
index 7705bfe..0000000
--- a/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# Inherits OWNERS from parent directory.
diff --git a/tests/tests/notificationlegacy/notificationlegacy20/OWNERS b/tests/tests/notificationlegacy/notificationlegacy20/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/tests/tests/notificationlegacy/notificationlegacy20/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/tests/tests/notificationlegacy/notificationlegacy27/OWNERS b/tests/tests/notificationlegacy/notificationlegacy27/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/tests/tests/notificationlegacy/notificationlegacy27/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/tests/tests/notificationlegacy/notificationlegacy28/OWNERS b/tests/tests/notificationlegacy/notificationlegacy28/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/tests/tests/notificationlegacy/notificationlegacy28/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/OWNERS b/tests/tests/notificationlegacy/notificationlegacy29/OWNERS
deleted file mode 100644
index d6078e0..0000000
--- a/tests/tests/notificationlegacy/notificationlegacy29/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT DELETE: OWNERS is intended to be empty as module owner and bug component are defined
-# in parent directory. This file is needed as a placeholder for verification purpose as we
-# need to tell the difference between "no owner is specified for this module" vs "explicitly
-# defer to parent OWNERS file"
diff --git a/tests/tests/os/Android.bp b/tests/tests/os/Android.bp
index 6c48c87..1f9ca09 100644
--- a/tests/tests/os/Android.bp
+++ b/tests/tests/os/Android.bp
@@ -47,7 +47,7 @@
"vts",
"general-tests",
],
- platform_apis: true,
+ sdk_version: "test_current",
libs: [
"android.test.runner.stubs",
"android.test.base.stubs",
diff --git a/tests/tests/packageinstaller/atomicinstall/OWNERS b/tests/tests/packageinstaller/atomicinstall/OWNERS
new file mode 100644
index 0000000..25775b8
--- /dev/null
+++ b/tests/tests/packageinstaller/atomicinstall/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 36137
+include /hostsidetests/stagedinstall/OWNERS
diff --git a/tests/tests/packageinstaller/install/AndroidManifest.xml b/tests/tests/packageinstaller/install/AndroidManifest.xml
index 7d2e984..eeef252 100644
--- a/tests/tests/packageinstaller/install/AndroidManifest.xml
+++ b/tests/tests/packageinstaller/install/AndroidManifest.xml
@@ -22,7 +22,7 @@
<application android:label="Cts Package Installer Tests">
<uses-library android:name="android.test.runner" />
- <activity android:name=".InstallConfirmDialogStarter" />
+ <activity android:name="com.android.compatibility.common.util.FutureResultActivity" />
<provider android:authorities="android.packageinstaller.install.cts.fileprovider"
android:name="androidx.core.content.FileProvider"
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/InstallConfirmDialogStarter.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/InstallConfirmDialogStarter.kt
deleted file mode 100644
index b026943..0000000
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/InstallConfirmDialogStarter.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.packageinstaller.install.cts
-
-import android.app.Activity
-import android.content.Intent
-import android.os.Bundle
-import java.util.concurrent.LinkedBlockingQueue
-
-val installDialogResults = LinkedBlockingQueue<Int>()
-
-class InstallConfirmDialogStarter : Activity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- savedInstanceState ?: installDialogResults.clear()
- }
-
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- installDialogResults.offer(resultCode)
- }
-}
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt
index e163a32..a8a8917 100644
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt
@@ -28,6 +28,7 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import java.util.concurrent.TimeUnit
private const val INSTALL_BUTTON_ID = "button1"
private const val CANCEL_BUTTON_ID = "button2"
@@ -47,11 +48,11 @@
*/
@Test
fun confirmInstallation() {
- startInstallationViaIntent()
+ val installation = startInstallationViaIntent()
clickInstallerUIButton(INSTALL_BUTTON_ID)
// Install should have succeeded
- assertEquals(RESULT_OK, getInstallDialogResult())
+ assertEquals(RESULT_OK, installation.get(TIMEOUT, TimeUnit.MILLISECONDS))
assertInstalled()
}
@@ -61,14 +62,12 @@
*/
@Test
fun cancelInstallation() {
- startInstallationViaIntent()
+ val installation = startInstallationViaIntent()
clickInstallerUIButton(CANCEL_BUTTON_ID)
// Install should have been aborted
- assertEquals(RESULT_CANCELED, getInstallDialogResult())
+ assertEquals(RESULT_CANCELED, installation.get(TIMEOUT, TimeUnit.MILLISECONDS))
assertNotInstalled()
-
- assertNoMoreInstallResults()
}
/**
@@ -85,12 +84,12 @@
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
- installDialogStarter.activity.startActivityForResult(intent, 0)
+ val reinstall = installDialogStarter.activity.startActivityForResult(intent)
clickInstallerUIButton(INSTALL_BUTTON_ID)
// Install should have succeeded
- assertEquals(RESULT_OK, getInstallDialogResult())
+ assertEquals(RESULT_OK, reinstall.get(TIMEOUT, TimeUnit.MILLISECONDS))
assertInstalled()
}
}
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/PackageInstallerTestBase.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/PackageInstallerTestBase.kt
index f6bbe06..d84ab1b 100644
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/PackageInstallerTestBase.kt
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/PackageInstallerTestBase.kt
@@ -38,12 +38,14 @@
import android.support.test.uiautomator.Until
import androidx.core.content.FileProvider
import com.android.compatibility.common.util.AppOpsUtils
+import com.android.compatibility.common.util.FutureResultActivity
import org.junit.After
import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import java.io.File
import java.lang.IllegalArgumentException
+import java.util.concurrent.CompletableFuture
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit
@@ -62,7 +64,7 @@
open class PackageInstallerTestBase {
@get:Rule
- val installDialogStarter = ActivityTestRule(InstallConfirmDialogStarter::class.java)
+ val installDialogStarter = ActivityTestRule(FutureResultActivity::class.java)
private val context = InstrumentationRegistry.getTargetContext()
private val pm = context.packageManager
@@ -79,7 +81,7 @@
if (status == STATUS_PENDING_USER_ACTION) {
val activityIntent = intent.getParcelableExtra<Intent>(EXTRA_INTENT)
activityIntent!!.addFlags(FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK)
- installDialogStarter.activity.startActivityForResult(activityIntent, 0)
+ installDialogStarter.activity.startActivityForResult(activityIntent)
}
installSessionResult.offer(status)
@@ -128,7 +130,7 @@
/**
* Start an installation via a session
*/
- protected fun startInstallationViaSession(): PackageInstaller.Session {
+ protected fun startInstallationViaSession(): CompletableFuture<Int> {
val pi = pm.packageInstaller
// Create session
@@ -143,33 +145,28 @@
}
// Commit session
- val pendingIntent = PendingIntent.getBroadcast(context, 0, Intent(INSTALL_ACTION_CB),
- FLAG_UPDATE_CURRENT)
- session.commit(pendingIntent.intentSender)
+ val dialog = FutureResultActivity.doAndAwaitStart {
+ val pendingIntent = PendingIntent.getBroadcast(context, 0, Intent(INSTALL_ACTION_CB),
+ FLAG_UPDATE_CURRENT)
+ session.commit(pendingIntent.intentSender)
+ }
// The system should have asked us to launch the installer
Assert.assertEquals(STATUS_PENDING_USER_ACTION, getInstallSessionResult())
- return session
+ return dialog
}
/**
* Start an installation via a session
*/
- protected fun startInstallationViaIntent() {
+ protected fun startInstallationViaIntent(): CompletableFuture<Int> {
val intent = Intent(Intent.ACTION_INSTALL_PACKAGE)
intent.data = FileProvider.getUriForFile(context, CONTENT_AUTHORITY, apkFile)
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
- installDialogStarter.activity.startActivityForResult(intent, 0)
- }
-
- /**
- * Wait for result of install dialog and return it
- */
- fun getInstallDialogResult(timeout: Long = TIMEOUT): Int? {
- return installDialogResults.poll(timeout, TimeUnit.MILLISECONDS)
+ return installDialogStarter.activity.startActivityForResult(intent)
}
fun assertInstalled() {
@@ -195,14 +192,6 @@
.click()
}
- /**
- * Assert that there are no more callbacks from the install session or install dialog
- */
- fun assertNoMoreInstallResults() {
- Assert.assertNull(getInstallSessionResult(0))
- Assert.assertEquals(0, installDialogResults.size)
- }
-
@After
fun unregisterInstallResultReceiver() {
try {
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/SessionTest.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/SessionTest.kt
index 34b78c3..111e6a8 100644
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/SessionTest.kt
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/SessionTest.kt
@@ -30,6 +30,7 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import java.util.concurrent.TimeUnit
private const val INSTALL_BUTTON_ID = "button1"
private const val CANCEL_BUTTON_ID = "button2"
@@ -50,7 +51,7 @@
*/
@Test
fun confirmInstallation() {
- startInstallationViaSession()
+ val installation = startInstallationViaSession()
clickInstallerUIButton(INSTALL_BUTTON_ID)
// Install should have succeeded
@@ -58,9 +59,7 @@
assertInstalled()
// Even when the install succeeds the install confirm dialog returns 'canceled'
- assertEquals(RESULT_CANCELED, getInstallDialogResult())
-
- assertNoMoreInstallResults()
+ assertEquals(RESULT_CANCELED, installation.get(TIMEOUT, TimeUnit.MILLISECONDS))
assertTrue(AppOpsUtils.allowedOperationLogged(context.packageName, APP_OP_STR))
}
@@ -70,7 +69,7 @@
*/
@Test
fun setAppCategory() {
- startInstallationViaSession()
+ val installation = startInstallationViaSession()
clickInstallerUIButton(INSTALL_BUTTON_ID)
// Wait for installation to finish
@@ -90,14 +89,12 @@
*/
@Test
fun cancelInstallation() {
- startInstallationViaSession()
+ val installation = startInstallationViaSession()
clickInstallerUIButton(CANCEL_BUTTON_ID)
// Install should have been aborted
assertEquals(STATUS_FAILURE_ABORTED, getInstallSessionResult())
- assertEquals(RESULT_CANCELED, getInstallDialogResult())
+ assertEquals(RESULT_CANCELED, installation.get(TIMEOUT, TimeUnit.MILLISECONDS))
assertNotInstalled()
-
- assertNoMoreInstallResults()
}
}
diff --git a/tests/tests/packageinstaller/tapjacking/OWNERS b/tests/tests/packageinstaller/tapjacking/OWNERS
new file mode 100644
index 0000000..0088192
--- /dev/null
+++ b/tests/tests/packageinstaller/tapjacking/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 36137
+moltmann@google.com
\ No newline at end of file
diff --git a/tests/tests/packageinstaller/uninstall/OWNERS b/tests/tests/packageinstaller/uninstall/OWNERS
new file mode 100644
index 0000000..0088192
--- /dev/null
+++ b/tests/tests/packageinstaller/uninstall/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 36137
+moltmann@google.com
\ No newline at end of file
diff --git a/tests/tests/permission/sdk28/OWNERS b/tests/tests/permission/sdk28/OWNERS
new file mode 100644
index 0000000..c126a70
--- /dev/null
+++ b/tests/tests/permission/sdk28/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
\ No newline at end of file
diff --git a/tests/tests/permission2/Android.bp b/tests/tests/permission2/Android.bp
index f4f25b0..916e986 100644
--- a/tests/tests/permission2/Android.bp
+++ b/tests/tests/permission2/Android.bp
@@ -26,6 +26,7 @@
],
libs: ["android.test.base.stubs"],
static_libs: [
+ "androidx.test.core",
"compatibility-device-util-axt",
"ctstestrunner-axt",
"guava",
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 49c28b4..402a286 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -1522,18 +1522,6 @@
<permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"
android:protectionLevel="signature|privileged" />
- <!-- @hide -->
- <permission android:name="android.permission.ACCESS_WIMAX_STATE"
- android:description="@string/permdesc_accessWimaxState"
- android:label="@string/permlab_accessWimaxState"
- android:protectionLevel="normal" />
-
- <!-- @hide -->
- <permission android:name="android.permission.CHANGE_WIMAX_STATE"
- android:description="@string/permdesc_changeWimaxState"
- android:label="@string/permlab_changeWimaxState"
- android:protectionLevel="normal" />
-
<!-- Allows applications to act as network scorers. @hide @SystemApi-->
<permission android:name="android.permission.SCORE_NETWORKS"
android:protectionLevel="signature|privileged" />
@@ -1603,12 +1591,6 @@
<permission android:name="android.permission.MANAGE_LOWPAN_INTERFACES"
android:protectionLevel="signature|privileged" />
- <!-- @hide Allows internal management of Wi-Fi connectivity state when on
- wireless consent mode.
- <p>Not for use by third-party applications. -->
- <permission android:name="android.permission.MANAGE_WIFI_WHEN_WIRELESS_CONSENT_REQUIRED"
- android:protectionLevel="signature" />
-
<!-- #SystemApi @hide Allows an app to bypass Private DNS.
<p>Not for use by third-party applications.
TODO: publish as system API in next API release. -->
@@ -2829,6 +2811,11 @@
<permission android:name="android.permission.STATUS_BAR_SERVICE"
android:protectionLevel="signature" />
+ <!-- Allows an application to trigger bugreports via the shell app (which uses bugreport API)
+ @hide -->
+ <permission android:name="android.permission.TRIGGER_SHELL_BUGREPORT"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to bind to third party quick settings tiles.
<p>Should only be requested by the System, should be required by
TileService declarations.-->
@@ -3457,6 +3444,11 @@
<permission android:name="android.permission.OBSERVE_ROLE_HOLDERS"
android:protectionLevel="signature|installer" />
+ <!-- Allows an application to manage the companion devices.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_COMPANION_DEVICES"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to use SurfaceFlinger's low level features.
<p>Not for use by third-party applications.
@hide
diff --git a/tests/tests/preference/OWNERS b/tests/tests/preference/OWNERS
index 827134e..0ea8182 100644
--- a/tests/tests/preference/OWNERS
+++ b/tests/tests/preference/OWNERS
@@ -1,3 +1,4 @@
+# Bug component: 25700
lpf@google.com
pavlis@google.com
clarabayarri@google.com
diff --git a/tests/tests/provider/OWNERS b/tests/tests/provider/OWNERS
new file mode 100644
index 0000000..fea932d
--- /dev/null
+++ b/tests/tests/provider/OWNERS
@@ -0,0 +1,7 @@
+# Bug component: 1344
+jsharkey@android.com
+omakoto@google.com
+yamasani@google.com
+tgunn@google.com
+nicksauer@google.com
+nona@google.com
diff --git a/tests/tests/renderscript/OWNERS b/tests/tests/renderscript/OWNERS
new file mode 100644
index 0000000..d61905a
--- /dev/null
+++ b/tests/tests/renderscript/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 43047
+include platform/frameworks/rs:/OWNERS
diff --git a/tests/tests/role/Android.bp b/tests/tests/role/Android.bp
index ac8d967..47e84fc 100644
--- a/tests/tests/role/Android.bp
+++ b/tests/tests/role/Android.bp
@@ -24,7 +24,7 @@
"androidx.test.rules",
"compatibility-device-util-axt",
"ctstestrunner-axt",
- "truth-prebuilt"
+ "truth-prebuilt",
],
test_suites: [
diff --git a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
index 736e501..42cce23 100644
--- a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
+++ b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
@@ -50,7 +50,9 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.AppOpsUtils;
+import com.android.compatibility.common.util.ExceptionUtils;
import com.android.compatibility.common.util.ThrowingRunnable;
+import com.android.compatibility.common.util.UiDumpUtils;
import org.junit.After;
import org.junit.Before;
@@ -326,14 +328,15 @@
@NonNull
private Pair<Integer, Intent> clickButtonAndWaitForResult(boolean positive) throws IOException,
InterruptedException {
- String buttonId = positive ? "android:id/button1" : "android:id/button2";
- UiObject2 button = sUiDevice.wait(Until.findObject(By.res(buttonId)), TIMEOUT_MILLIS);
- if (button == null) {
- dumpWindowHierarchy();
- fail("Cannot find button to click");
- }
- button.click();
- return waitForResult();
+ return ExceptionUtils.wrappingExceptions(UiDumpUtils::wrapWithUiDump, () -> {
+ String buttonId = positive ? "android:id/button1" : "android:id/button2";
+ UiObject2 button = sUiDevice.wait(Until.findObject(By.res(buttonId)), TIMEOUT_MILLIS);
+ if (button == null) {
+ fail("Cannot find button to click");
+ }
+ button.click();
+ return waitForResult();
+ });
}
private void dumpWindowHierarchy() throws InterruptedException, IOException {
diff --git a/tests/tests/security/OWNERS b/tests/tests/security/OWNERS
new file mode 100644
index 0000000..c5cfd1e
--- /dev/null
+++ b/tests/tests/security/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 36824
+cbrubaker@google.com
+jeffv@google.com
+nnk@google.com
diff --git a/tests/tests/syncmanager/OWNERS b/tests/tests/syncmanager/OWNERS
new file mode 100644
index 0000000..c475c6e
--- /dev/null
+++ b/tests/tests/syncmanager/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 197138
+omakoto@google.com
+yamasani@google.com
diff --git a/tests/tests/systemintents/OWNERS b/tests/tests/systemintents/OWNERS
new file mode 100644
index 0000000..b465964
--- /dev/null
+++ b/tests/tests/systemintents/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 25692
+ctate@google.com
\ No newline at end of file
diff --git a/tests/tests/telecom/OWNERS b/tests/tests/telecom/OWNERS
new file mode 100644
index 0000000..f4921e0
--- /dev/null
+++ b/tests/tests/telecom/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 20868
+include ../telephony/OWNERS
diff --git a/tests/tests/telecom2/OWNERS b/tests/tests/telecom2/OWNERS
new file mode 100644
index 0000000..f4921e0
--- /dev/null
+++ b/tests/tests/telecom2/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 20868
+include ../telephony/OWNERS
diff --git a/tests/tests/telecom3/OWNERS b/tests/tests/telecom3/OWNERS
new file mode 100644
index 0000000..f4921e0
--- /dev/null
+++ b/tests/tests/telecom3/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 20868
+include ../telephony/OWNERS
diff --git a/tests/tests/telephony/OWNERS b/tests/tests/telephony/OWNERS
new file mode 100644
index 0000000..73fa25e
--- /dev/null
+++ b/tests/tests/telephony/OWNERS
@@ -0,0 +1,14 @@
+# Bug component: 20868
+amitmahajan@google.com
+fionaxu@google.com
+jackyu@google.com
+rgreenwalt@google.com
+refuhoo@google.com
+mpq@google.com
+jminjie@google.com
+shuoq@google.com
+hallliu@google.com
+tgunn@google.com
+breadley@google.com
+paulye@google.com
+nazaninb@google.com
diff --git a/tests/tests/telephony/current/OWNERS b/tests/tests/telephony/current/OWNERS
deleted file mode 100644
index 7c8e7d8..0000000
--- a/tests/tests/telephony/current/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 20868
-rgreenwalt@google.com
-jackyu@google.com
-tgunn@google.com
-amitmahajan@google.com
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
index 5e4abf4..714eca6 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -134,21 +134,25 @@
}
/**
- * Sanity check that the device has a cellular network and a valid default data subId
- * when {@link PackageManager#FEATURE_TELEPHONY} support.
+ * Sanity check that both {@link PackageManager#FEATURE_TELEPHONY} and
+ * {@link NetworkCapabilities#TRANSPORT_CELLULAR} network must both be
+ * either defined or undefined; you can't cross the streams.
*/
@Test
public void testSanity() throws Exception {
- if (!isSupported()) return;
-
final boolean hasCellular = findCellularNetwork() != null;
- if (!hasCellular) {
+ if (isSupported() && !hasCellular) {
fail("Device claims to support " + PackageManager.FEATURE_TELEPHONY
+ " but has no active cellular network, which is required for validation");
+ } else if (!isSupported() && hasCellular) {
+ fail("Device has active cellular network, but claims to not support "
+ + PackageManager.FEATURE_TELEPHONY);
}
- if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- fail("Device must have a valid default data subId for validation");
+ if (isSupported()) {
+ if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ fail("Device must have a valid default data subId for validation");
+ }
}
}
diff --git a/tests/tests/telephony2/OWNERS b/tests/tests/telephony2/OWNERS
index 7c8e7d8..f4921e0 100644
--- a/tests/tests/telephony2/OWNERS
+++ b/tests/tests/telephony2/OWNERS
@@ -1,5 +1,2 @@
# Bug component: 20868
-rgreenwalt@google.com
-jackyu@google.com
-tgunn@google.com
-amitmahajan@google.com
+include ../telephony/OWNERS
diff --git a/tests/tests/telephony3/OWNERS b/tests/tests/telephony3/OWNERS
new file mode 100644
index 0000000..f4921e0
--- /dev/null
+++ b/tests/tests/telephony3/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 20868
+include ../telephony/OWNERS
diff --git a/tests/tests/telephony4/OWNERS b/tests/tests/telephony4/OWNERS
index 5617896..3a905dd 100644
--- a/tests/tests/telephony4/OWNERS
+++ b/tests/tests/telephony4/OWNERS
@@ -1,2 +1,4 @@
# Bug component: 20868
-yinxu@google.com
\ No newline at end of file
+include ../telephony/OWNERS
+
+yinxu@google.com
diff --git a/tests/tests/telephonyprovider/OWNERS b/tests/tests/telephonyprovider/OWNERS
index 92458db..7f7694d 100644
--- a/tests/tests/telephonyprovider/OWNERS
+++ b/tests/tests/telephonyprovider/OWNERS
@@ -1,12 +1,3 @@
-amitmahajan@google.com
-fionaxu@google.com
-jackyu@google.com
-rgreenwalt@google.com
-refuhoo@google.com
-mpq@google.com
-jminjie@google.com
-shuoq@google.com
-hallliu@google.com
-tgunn@google.com
-breadley@google.com
-nazaninb@google.com
+# Bug component: 450841
+include ../telephony/OWNERS
+lelandmiller@google.com
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java
index 05acf32..7933791 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java
@@ -41,25 +41,18 @@
// In JB MR1 access to the TelephonyProvider's Carriers table was clamped down and would
// throw a SecurityException when queried. That was fixed in JB MR2. Verify that 3rd parties
// can access the APN info the carriers table, after JB MR1.
+
+ // However, in R, a security bug was discovered that let apps read the password by querying
+ // multiple times and matching passwords against a regex in the query. Due to this hole, we're
+ // locking down the API and no longer allowing the exception. Accordingly, the behavior of this
+ // test is now reversed and we expect a SecurityException to be thrown.
public void testAccessToApns() {
try {
String selection = Carriers.CURRENT + " IS NOT NULL";
String[] selectionArgs = null;
Cursor cursor = mContentResolver.query(Carriers.CONTENT_URI,
APN_PROJECTION, selection, selectionArgs, null);
- } catch (SecurityException e) {
- fail("No access to current APN");
- }
- }
-
- public void testNoAccessToPassword() {
- try {
- String selection = Carriers.CURRENT + " IS NOT NULL AND "
- + Carriers.PASSWORD + " IS NOT NULL";
- String[] selectionArgs = null;
- Cursor cursor = mContentResolver.query(Carriers.CONTENT_URI,
- APN_PROJECTION, selection, selectionArgs, null);
- fail("Expected SecurityExceptio");
+ fail("No SecurityException thrown");
} catch (SecurityException e) {
// expected
}
diff --git a/tests/tests/tools/processors/view_inspector/OWNERS b/tests/tests/tools/processors/view_inspector/OWNERS
new file mode 100644
index 0000000..1572c57
--- /dev/null
+++ b/tests/tests/tools/processors/view_inspector/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 25700
+ashleyrose@google.com
+aurimas@google.com
diff --git a/tests/tests/uiautomation/Android.bp b/tests/tests/uiautomation/Android.bp
index 22dd8f6..67f3ed7 100644
--- a/tests/tests/uiautomation/Android.bp
+++ b/tests/tests/uiautomation/Android.bp
@@ -23,7 +23,7 @@
"cts_instant",
],
static_libs: [
- "compatibility-device-util-axt",
+ "CtsAccessibilityCommon",
"ctstestrunner-axt",
"ub-uiautomator",
],
diff --git a/tests/tests/uiautomation/AndroidManifest.xml b/tests/tests/uiautomation/AndroidManifest.xml
index af4f4cd..4da45fc 100644
--- a/tests/tests/uiautomation/AndroidManifest.xml
+++ b/tests/tests/uiautomation/AndroidManifest.xml
@@ -21,10 +21,12 @@
android:targetSandboxVersion="2">
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.CAMERA" />
- <application android:theme="@android:style/Theme.Holo.NoActionBar" >
+ <application android:theme="@android:style/Theme.Holo.NoActionBar"
+ android:requestLegacyExternalStorage="true">
<uses-library android:name="android.test.runner"/>
diff --git a/tests/tests/uiautomation/AndroidTest.xml b/tests/tests/uiautomation/AndroidTest.xml
index f5cf748..9fe5a4f 100644
--- a/tests/tests/uiautomation/AndroidTest.xml
+++ b/tests/tests/uiautomation/AndroidTest.xml
@@ -29,4 +29,8 @@
<option name="package" value="android.app.uiautomation.cts" />
<option name="runtime-hint" value="6m42s" />
</test>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/sdcard/android.app.uiautomation.cts" />
+ <option name="collect-on-run-ended-only" value="true" />
+ </metrics_collector>
</configuration>
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationLogRule.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationLogRule.java
deleted file mode 100644
index 3f81d3a..0000000
--- a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationLogRule.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.uiautomation.cts;
-
-import android.app.UiAutomation;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.test.InstrumentationRegistry;
-
-import com.android.compatibility.common.util.SystemUtil;
-
-import org.junit.AssumptionViolatedException;
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import java.io.IOException;
-
-/**
- * Improves UiAutomationTest logging, dumps log when a test case gets failed.
- *
- * <ol>
- * <li>Call {@code dumpsys accessibility}.
- * </ol>
- */
-public final class UiAutomationLogRule implements TestRule {
-
- private final String mTestName;
-
- public UiAutomationLogRule(@NonNull String testName) {
- mTestName = testName;
- }
-
- @Override
- public Statement apply(Statement base, Description description) {
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- Throwable throwable = null;
- // First run the test
- try {
- base.evaluate();
- } catch (Throwable t) {
- throwable = t;
- }
-
- // Ignore AssumptionViolatedException. It's not a test fail.
- if (throwable != null && throwable instanceof AssumptionViolatedException) {
- throwable = null;
- }
-
- if (throwable != null) {
- try {
- Log.e(mTestName, "TEST FAIL");
- dump();
- } catch (Throwable t) {
- Log.e(mTestName, "Dump fail", t);
- }
- }
-
- // Finally, throw exception!
- if (throwable == null) return;
- throw throwable;
- }
- };
- }
-
- private void dump() throws IOException {
- UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(
- UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
- try {
- final String a11yDump = SystemUtil.runShellCommand(
- uiAutomation, "dumpsys accessibility");
- Log.e(mTestName, "==== dumpsys accessibility ====\n" + a11yDump);
- } finally {
- uiAutomation.destroy();
- }
- }
-}
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
index 828d9b5..dd354d7 100755
--- a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
+++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
@@ -17,13 +17,13 @@
package android.app.uiautomation.cts;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.Manifest;
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Activity;
import android.app.ActivityManager;
@@ -71,8 +71,8 @@
private static final int TIMEOUT_FOR_SERVICE_ENABLE = 10000; // millis; 10s
@Rule
- public final UiAutomationLogRule mLogRule = new UiAutomationLogRule(
- UiAutomationTest.class.getSimpleName());
+ public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+ new AccessibilityDumpOnFailureRule();
@Before
public void setUp() throws Exception {
diff --git a/tests/tests/uidisolation/OWNERS b/tests/tests/uidisolation/OWNERS
new file mode 100644
index 0000000..94522e3
--- /dev/null
+++ b/tests/tests/uidisolation/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 36824
+include /tests/tests/security/OWNERS
diff --git a/tests/tests/view/OWNERS b/tests/tests/view/OWNERS
new file mode 100644
index 0000000..8200a30
--- /dev/null
+++ b/tests/tests/view/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 25700
+adamp@google.com
+shepshapard@google.com
+clarabayarri@google.com
diff --git a/tests/tests/view/jni/android_view_cts_ASurfaceControlTest.cpp b/tests/tests/view/jni/android_view_cts_ASurfaceControlTest.cpp
index 2bfab1e..3bc8890 100644
--- a/tests/tests/view/jni/android_view_cts_ASurfaceControlTest.cpp
+++ b/tests/tests/view/jni/android_view_cts_ASurfaceControlTest.cpp
@@ -31,7 +31,9 @@
#include <android/surface_control.h>
#include <android/sync.h>
+#include <errno.h>
#include <jni.h>
+#include <time.h>
namespace {
@@ -57,6 +59,16 @@
return; \
}
+#define NANOS_PER_SECOND 1000000000LL
+int64_t systemTime() {
+ struct timespec time;
+ int result = clock_gettime(CLOCK_MONOTONIC, &time);
+ if (result < 0) {
+ return -errno;
+ }
+ return (time.tv_sec * NANOS_PER_SECOND) + time.tv_nsec;
+}
+
static AHardwareBuffer* allocateBuffer(int32_t width, int32_t height) {
AHardwareBuffer* buffer = nullptr;
AHardwareBuffer_Desc desc = {};
@@ -337,12 +349,16 @@
int* contextIntPtr = reinterpret_cast<int*>(context);
contextIntPtr[0]++;
contextIntPtr[1] = presentFence;
+ int64_t* systemTimeLongPtr = reinterpret_cast<int64_t*>(contextIntPtr + 2);
+ *systemTimeLongPtr = systemTime();
}
jlong SurfaceTransaction_setOnComplete(JNIEnv* /*env*/, jclass, jlong surfaceTransaction) {
- int* context = new int[2];
+ int* context = new int[4];
context[0] = 0;
context[1] = -1;
+ context[2] = -1;
+ context[3] = -1;
ASurfaceTransaction_setOnComplete(
reinterpret_cast<ASurfaceTransaction*>(surfaceTransaction),
@@ -358,6 +374,9 @@
int data = contextPtr[0];
int presentFence = contextPtr[1];
+ int64_t* callbackTimePtr = reinterpret_cast<int64_t*>(contextPtr + 2);
+ int64_t callbackTime = *callbackTimePtr;
+
delete[] contextPtr;
if (desiredPresentTime < 0) {
@@ -367,31 +386,41 @@
return;
}
- struct sync_file_info* syncFileInfo = sync_file_info(presentFence);
- ASSERT(syncFileInfo, "invalid fence")
+ if (presentFence >= 0) {
+ struct sync_file_info* syncFileInfo = sync_file_info(presentFence);
+ ASSERT(syncFileInfo, "invalid fence");
- if (syncFileInfo->status != 1) {
- sync_file_info_free(syncFileInfo);
- ASSERT(syncFileInfo->status == 1, "fence did not signal")
- }
-
- uint64_t presentTime = 0;
- struct sync_fence_info* syncFenceInfo = sync_get_fence_info(syncFileInfo);
- for (size_t i = 0; i < syncFileInfo->num_fences; i++) {
- if (syncFenceInfo[i].timestamp_ns > presentTime) {
- presentTime = syncFenceInfo[i].timestamp_ns;
+ if (syncFileInfo->status != 1) {
+ sync_file_info_free(syncFileInfo);
+ ASSERT(syncFileInfo->status == 1, "fence did not signal")
}
+
+ uint64_t presentTime = 0;
+ struct sync_fence_info* syncFenceInfo = sync_get_fence_info(syncFileInfo);
+ for (size_t i = 0; i < syncFileInfo->num_fences; i++) {
+ if (syncFenceInfo[i].timestamp_ns > presentTime) {
+ presentTime = syncFenceInfo[i].timestamp_ns;
+ }
+ }
+
+ sync_file_info_free(syncFileInfo);
+ close(presentFence);
+
+ // In the worst case the worst present time should be no more than three frames off from the
+ // desired present time. Since the test case is using a virtual display and there are no
+ // requirements for virtual display refresh rate timing, lets assume a refresh rate of 16fps.
+ ASSERT(presentTime < desiredPresentTime + 0.188 * 1e9, "transaction was presented too late");
+ ASSERT(presentTime >= desiredPresentTime, "transaction was presented too early");
+ } else {
+ ASSERT(presentFence == -1, "invalid fences should be -1");
+ // The device doesn't support present fences. We will use the callback time to roughly
+ // verify the result. Since the callback could take up to half a frame, do the normal bound
+ // check plus an additional half frame.
+ ASSERT(callbackTime < desiredPresentTime + (0.188 + 0.031) * 1e9,
+ "transaction was presented too late");
+ ASSERT(callbackTime >= desiredPresentTime, "transaction was presented too early");
}
- sync_file_info_free(syncFileInfo);
- close(presentFence);
-
- // In the worst case the worst present time should be no more than three frames off from the
- // desired present time. Since the test case is using a virtual display and there are no
- // requirements for virtual display refresh rate timing, lets assume a refresh rate of 16fps.
- ASSERT(presentTime < desiredPresentTime + 0.188 * 1e9, "transaction was presented too late");
- ASSERT(presentTime >= desiredPresentTime, "transaction was presented too early");
-
ASSERT(data >= 1, "did not receive a callback")
ASSERT(data <= 1, "received too many callbacks")
}
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/DirectActionsTest.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/DirectActionsTest.java
index 338c361..6c4a3a7 100644
--- a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/DirectActionsTest.java
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/DirectActionsTest.java
@@ -134,7 +134,6 @@
mActivityControl.finishActivity();
}
}
-
private final class SessionControl {
private @Nullable RemoteCallback mControl;
diff --git a/tests/tests/widget/OWNERS b/tests/tests/widget/OWNERS
new file mode 100644
index 0000000..12f176d
--- /dev/null
+++ b/tests/tests/widget/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 25700
+adamp@google.com
+mount@google.com
+shepshapard@google.com
+clarabayarri@google.com
diff --git a/tests/tests/widget/src/android/widget/cts/MagnifierTest.java b/tests/tests/widget/src/android/widget/cts/MagnifierTest.java
index a31963c..0264665 100644
--- a/tests/tests/widget/src/android/widget/cts/MagnifierTest.java
+++ b/tests/tests/widget/src/android/widget/cts/MagnifierTest.java
@@ -728,14 +728,15 @@
WidgetTestUtils.runOnMainAndLayoutSync(mActivityRule, () -> {
mActivity.setContentView(R.layout.magnifier_activity_centered_surfaceview_layout);
}, false /* forceLayout */);
- final View view = mActivity.findViewById(R.id.magnifier_centered_view);
- WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, view, () -> {
+ WidgetTestUtils.runOnMainAndLayoutSync(mActivityRule, () -> {
// Draw something in the SurfaceView for the Magnifier to copy.
+ final View view = mActivity.findViewById(R.id.magnifier_centered_view);
final SurfaceHolder surfaceHolder = ((SurfaceView) view).getHolder();
final Canvas canvas = surfaceHolder.lockHardwareCanvas();
canvas.drawColor(Color.BLUE);
surfaceHolder.unlockCanvasAndPost(canvas);
- });
+ }, false /* forceLayout */);
+ final View view = mActivity.findViewById(R.id.magnifier_centered_view);
final Magnifier.Builder builder = new Magnifier.Builder(view)
.setSize(100, 100)
.setInitialZoom(5f) /* 20x20 source size */
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 01d5cd8..86e674e 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -169,6 +169,7 @@
import java.io.IOException;
import java.lang.annotation.Retention;
import java.util.Arrays;
+import java.util.List;
import java.util.Locale;
/**
@@ -7149,6 +7150,106 @@
TextUtils.equals(hintText, info.getHintText()));
}
+ @UiThreadTest
+ @Test
+ public void testOnInitializeA11yNodeInfo_removesClickabilityWithLinkMovementMethod() {
+ mTextView = findTextView(R.id.textview_text);
+ mTextView.setMovementMethod(new LinkMovementMethod());
+
+ assertTrue("clickable should be true", mTextView.isClickable());
+ assertFalse("View should not have onClickListeners", mTextView.hasOnClickListeners());
+ assertTrue("longClickable should be true", mTextView.isLongClickable());
+ assertFalse("View should not have onLongClickListeners",
+ mTextView.hasOnLongClickListeners());
+
+ final AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+ mTextView.onInitializeAccessibilityNodeInfo(info);
+ List<AccessibilityNodeInfo.AccessibilityAction> actionList = info.getActionList();
+ assertFalse("info's isClickable should be false", info.isClickable());
+ assertFalse("info should not have ACTION_CLICK",
+ actionList.contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK));
+ assertFalse("info's isLongClickable should be false",
+ info.isLongClickable());
+ assertFalse("info should not have ACTION_LONG_CLICK",
+ actionList.contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK));
+ }
+
+ @UiThreadTest
+ @Test
+ public void testOnInitializeA11yNodeInfo_keepsClickabilityWithMovementMethod() {
+ mTextView = findTextView(R.id.textview_text);
+ mTextView.setMovementMethod(new ArrowKeyMovementMethod());
+
+ assertTrue("clickable should be true", mTextView.isClickable());
+ assertFalse("View should not have onClickListeners", mTextView.hasOnClickListeners());
+ assertTrue("longClickable should be false", mTextView.isLongClickable());
+ assertFalse("View should not have onLongClickListeners",
+ mTextView.hasOnLongClickListeners());
+
+ final AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+ mTextView.onInitializeAccessibilityNodeInfo(info);
+ List<AccessibilityNodeInfo.AccessibilityAction> actionList = info.getActionList();
+ assertTrue("info's isClickable should be true", info.isClickable());
+ assertTrue("info should have ACTION_CLICK",
+ actionList.contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK));
+ assertTrue("info's isLongClickable should be true",
+ info.isLongClickable());
+ assertTrue("info should have ACTION_LONG_CLICK",
+ actionList.contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK));
+ }
+
+ @UiThreadTest
+ @Test
+ public void testOnInitializeA11yNodeInfo_keepsClickabilityWithOnClickListener() {
+ mTextView = findTextView(R.id.textview_text);
+ mTextView.setMovementMethod(new LinkMovementMethod());
+
+ assertTrue("clickable should be true", mTextView.isClickable());
+ assertFalse("View should not have onClickListeners", mTextView.hasOnClickListeners());
+ assertTrue("longClickable should be true", mTextView.isLongClickable());
+ assertFalse("View should not have onLongClickListeners",
+ mTextView.hasOnLongClickListeners());
+
+ mTextView.setOnClickListener(mock(View.OnClickListener.class));
+
+ final AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+ mTextView.onInitializeAccessibilityNodeInfo(info);
+ List<AccessibilityNodeInfo.AccessibilityAction> actionList = info.getActionList();
+ assertTrue("info's isClickable should be true", info.isClickable());
+ assertTrue("info should have ACTION_CLICK",
+ actionList.contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK));
+ assertFalse("info's isLongClickable should not be true",
+ info.isLongClickable());
+ assertFalse("info should have ACTION_LONG_CLICK",
+ actionList.contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK));
+ }
+
+ @UiThreadTest
+ @Test
+ public void testOnInitializeA11yNodeInfo_keepsLongClickabilityWithOnLongClickListener() {
+ mTextView = findTextView(R.id.textview_text);
+ mTextView.setMovementMethod(new LinkMovementMethod());
+
+ assertTrue("clickable should be true", mTextView.isClickable());
+ assertFalse("View should not have onClickListeners", mTextView.hasOnClickListeners());
+ assertTrue("longClickable should be true", mTextView.isLongClickable());
+ assertFalse("View should not have onLongClickListeners",
+ mTextView.hasOnLongClickListeners());
+
+ mTextView.setOnLongClickListener(mock(View.OnLongClickListener.class));
+
+ final AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+ mTextView.onInitializeAccessibilityNodeInfo(info);
+ List<AccessibilityNodeInfo.AccessibilityAction> actionList = info.getActionList();
+ assertFalse("info's isClickable should be false", info.isClickable());
+ assertFalse("info should not have ACTION_CLICK",
+ actionList.contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK));
+ assertTrue("info's isLongClickable should be true",
+ info.isLongClickable());
+ assertTrue("info should have ACTION_LONG_CLICK",
+ actionList.contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK));
+ }
+
@Test
public void testAutosizeWithMaxLines_shouldNotThrowException() throws Throwable {
// the layout contains an instance of CustomTextViewWithTransformationMethod
diff --git a/tests/vr/OWNERS b/tests/vr/OWNERS
new file mode 100644
index 0000000..b0936ba
--- /dev/null
+++ b/tests/vr/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 189591
+krzysio@google.com
diff --git a/tools/vm-tests-tf/OWNERS b/tools/vm-tests-tf/OWNERS
new file mode 100644
index 0000000..29fea99
--- /dev/null
+++ b/tools/vm-tests-tf/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 86431
+include /hostsidetests/classloaders/OWNERS