Merge "Update test as per the updated ClipDescription.getTimeStamp api." into oc-dev
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/NetworkConnectivityChecker.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/NetworkConnectivityChecker.java
index 5479474..d77d931 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/NetworkConnectivityChecker.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/NetworkConnectivityChecker.java
@@ -19,6 +19,7 @@
import com.android.compatibility.common.util.MonitoringUtils;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.suite.checker.ISystemStatusChecker;
/**
@@ -26,14 +27,23 @@
*/
public class NetworkConnectivityChecker implements ISystemStatusChecker {
+ // Only report is as failed (capture bugreport) when status goes from pass-> fail
+ private boolean mIsFailed = false;
+
/**
* {@inheritDoc}
*/
@Override
public boolean postExecutionCheck(ITestDevice device) throws DeviceNotAvailableException {
if (!MonitoringUtils.checkDeviceConnectivity(device)) {
+ if (mIsFailed) {
+ CLog.w("NetworkConnectivityChecker is still failing.");
+ return true;
+ }
+ mIsFailed = true;
return false;
}
+ mIsFailed = false;
return true;
}
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
index 41528f1..cd80500 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
@@ -21,9 +21,9 @@
import com.android.compatibility.common.tradefed.result.InvocationFailureHandler;
import com.android.compatibility.common.tradefed.result.SubPlanHelper;
import com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker;
-import com.android.compatibility.common.tradefed.util.OptionHelper;
import com.android.compatibility.common.tradefed.util.RetryFilterHelper;
import com.android.compatibility.common.tradefed.util.RetryType;
+import com.android.compatibility.common.tradefed.util.UniqueModuleCountUtil;
import com.android.compatibility.common.util.IInvocationResult;
import com.android.compatibility.common.util.ResultHandler;
import com.android.compatibility.common.util.TestFilter;
@@ -57,15 +57,11 @@
import com.android.tradefed.util.ArrayUtil;
import com.android.tradefed.util.StreamUtil;
import com.android.tradefed.util.TimeUtil;
-import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
import com.google.common.annotations.VisibleForTesting;
import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -357,6 +353,15 @@
// Add the entire list of modules to the CompatibilityBuildHelper for reporting
mBuildHelper.setModuleIds(mModuleRepo.getModuleIds());
+
+ int count = UniqueModuleCountUtil.countUniqueModules(
+ mModuleRepo.getTokenModules()) +
+ UniqueModuleCountUtil.countUniqueModules(
+ mModuleRepo.getNonTokenModules());
+ CLog.logAndDisplay(LogLevel.INFO, "========================================");
+ CLog.logAndDisplay(LogLevel.INFO, "Starting a run with %s unique modules.",
+ count);
+ CLog.logAndDisplay(LogLevel.INFO, "========================================");
} else {
CLog.d("ModuleRepo already initialized.");
}
@@ -383,8 +388,10 @@
}
return;
} else {
- CLog.logAndDisplay(LogLevel.INFO, "Starting %d module%s on %s", moduleCount,
- (moduleCount > 1) ? "s" : "", mDevice.getSerialNumber());
+ int uniqueModuleCount = UniqueModuleCountUtil.countUniqueModules(modules);
+ CLog.logAndDisplay(LogLevel.INFO, "Starting %d test sub-module%s on %s",
+ uniqueModuleCount, (uniqueModuleCount > 1) ? "s" : "",
+ mDevice.getSerialNumber());
}
if (mRebootBeforeTest) {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
index 794e45e..ea76919 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
@@ -18,6 +18,7 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.result.TestRunHandler;
import com.android.compatibility.common.tradefed.util.LinearPartition;
+import com.android.compatibility.common.tradefed.util.UniqueModuleCountUtil;
import com.android.compatibility.common.util.TestFilter;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
@@ -491,14 +492,19 @@
if (mInitCount == (mTotalShards - 1) &&
mTokenModuleScheduled.size() != mTokenModules.size()) {
mTokenModules.removeAll(mTokenModuleScheduled);
- CLog.e("Could not find any token for %s. Adding to last shard.", mTokenModules);
+ if (mTotalShards != 1) {
+ // Only print the warnings if we are sharding.
+ CLog.e("Could not find any token for %s. Adding to last shard.", mTokenModules);
+ }
modules.addAll(mTokenModules);
}
mInitCount++;
}
Collections.sort(modules, new ExecutionOrderComparator());
- CLog.logAndDisplay(LogLevel.INFO, "%s running %s modules, expected to complete in %s: %s",
- serial, modules.size(), TimeUtil.formatElapsedTime(estimatedTime), modules);
+ int uniqueCount = UniqueModuleCountUtil.countUniqueModules(modules);
+ CLog.logAndDisplay(LogLevel.INFO, "%s running %s test sub-modules, expected to complete "
+ + "in %s.", serial, uniqueCount, TimeUtil.formatElapsedTime(estimatedTime));
+ CLog.d("module list for this shard: %s", modules);
LinkedList<IModuleDef> tests = new LinkedList<>();
tests.addAll(modules);
return tests;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtil.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtil.java
new file mode 100644
index 0000000..e801ab3
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtil.java
@@ -0,0 +1,42 @@
+/*
+ * 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.tradefed.util;
+
+import com.android.compatibility.common.tradefed.testtype.IModuleDef;
+
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Utility to count the number of unique module from list of {@link IModuleDef}.
+ */
+public class UniqueModuleCountUtil {
+
+ /**
+ * Count the number of unique modules within the list using module id. If two IModuleDef have
+ * the same id, they are part of the same module.
+ *
+ * @param listModules list of {@link IModuleDef} to count from
+ * @return the count of unique module.
+ */
+ public static int countUniqueModules(List<IModuleDef> listModules) {
+ HashSet<String> uniqueNames = new HashSet<>();
+ for (IModuleDef subModule : listModules) {
+ uniqueNames.add(subModule.getId());
+ }
+ return uniqueNames.size();
+ }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
index b6861db..4e7c8c2 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
@@ -37,6 +37,7 @@
import com.android.compatibility.common.tradefed.util.CollectorUtilTest;
import com.android.compatibility.common.tradefed.util.OptionHelperTest;
import com.android.compatibility.common.tradefed.util.RetryFilterHelperTest;
+import com.android.compatibility.common.tradefed.util.UniqueModuleCountUtilTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -86,6 +87,7 @@
CollectorUtilTest.class,
OptionHelperTest.class,
RetryFilterHelperTest.class,
+ UniqueModuleCountUtilTest.class,
})
public class UnitTests {
// empty on purpose
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtilTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtilTest.java
new file mode 100644
index 0000000..799cff3
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtilTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.tradefed.util;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.compatibility.common.tradefed.testtype.IModuleDef;
+import com.android.compatibility.common.tradefed.testtype.ModuleDef;
+import com.android.compatibility.common.tradefed.testtype.TestStub;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.testtype.Abi;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit tests for {@link UniqueModuleCountUtil}.
+ */
+public class UniqueModuleCountUtilTest {
+
+ @Test
+ public void testCountEmptyList() {
+ List<IModuleDef> emptyList = new ArrayList<>();
+ assertEquals(0, UniqueModuleCountUtil.countUniqueModules(emptyList));
+ }
+
+ @Test
+ public void testCount_2uniquesModules() {
+ List<IModuleDef> list = new ArrayList<>();
+ list.add(new ModuleDef("moduleA", new Abi("arm64", "64"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ assertEquals(2, UniqueModuleCountUtil.countUniqueModules(list));
+ }
+
+ @Test
+ public void testCount_2subModules() {
+ List<IModuleDef> list = new ArrayList<>();
+ list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ assertEquals(1, UniqueModuleCountUtil.countUniqueModules(list));
+ }
+
+ @Test
+ public void testCount_mix() {
+ List<IModuleDef> list = new ArrayList<>();
+ list.add(new ModuleDef("moduleA", new Abi("arm64", "64"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleC", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleB", new Abi("arm64", "64"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleB", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleC", new Abi("arm64", "64"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ list.add(new ModuleDef("moduleC", new Abi("arm32", "32"), new TestStub(),
+ new ArrayList<ITargetPreparer>()));
+ assertEquals(6, UniqueModuleCountUtil.countUniqueModules(list));
+ }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
index 78f4a78..e0ac96f 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
@@ -47,6 +47,7 @@
private static final String UNEXPOSED_PKG = "com.android.cts.unexposedapp";
private static final String TEST_CLASS = ".ClientTest";
+ private static final String WEBVIEW_TEST_CLASS = ".WebViewTest";
private String mOldVerifierValue;
private IAbi mAbi;
@@ -120,6 +121,10 @@
runDeviceTests(EPHEMERAL_1_PKG, TEST_CLASS, "testPackageInfo");
}
+ public void testWebViewLoads() throws Exception {
+ runDeviceTests(EPHEMERAL_1_PKG, WEBVIEW_TEST_CLASS, "testWebViewLoads");
+ }
+
private void runDeviceTests(String packageName, String testClassName, String testMethodName)
throws DeviceNotAvailableException {
Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk
index 672bcd4..b13432b 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk
@@ -17,11 +17,14 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_MODULE_TAGS := tests
LOCAL_STATIC_JAVA_LIBRARIES := \
cts-aia-util \
android-support-test \
- legacy-android-test
+ legacy-android-test \
+ ctsdeviceutillegacy \
+ ctstestrunner
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml
index 63caebc..b0f53e0 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml
@@ -63,7 +63,7 @@
android:theme="@android:style/Theme.NoDisplay">
<!-- TEST: ephemeral apps can start this activity using directed intent -->
</activity>
-
+ <activity android:name=".WebViewTestActivity" />
<service
android:name=".EphemeralService">
<!-- TEST: ephemeral apps can see this service using query methods -->
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
index c0f4d2b..12797a1 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
@@ -127,7 +127,7 @@
filter.addCategory(Intent.CATEGORY_DEFAULT);
mReceiver = new ActivityBroadcastReceiver(mResultQueue);
InstrumentationRegistry.getContext()
- .registerReceiver(mReceiver, filter, true /*visibleToEmphemeral*/);
+ .registerReceiver(mReceiver, filter, Context.RECEIVER_VISIBLE_TO_INSTANT_APPS);
}
@After
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTest.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTest.java
new file mode 100644
index 0000000..11d1c60
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.cts.ephemeralapp1;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+
+import android.webkit.WebView;
+import android.webkit.cts.WebViewOnUiThread;
+
+public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewTestActivity> {
+
+ private WebView mWebView;
+ private WebViewOnUiThread mOnUiThread;
+
+ public WebViewTest() {
+ super("com.android.cts.ephemeralapp1", WebViewTestActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ final WebViewTestActivity activity = getActivity();
+ mWebView = activity.getWebView();
+ mOnUiThread = new WebViewOnUiThread(this, mWebView);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mOnUiThread.cleanUp();
+ super.tearDown();
+ }
+
+ @UiThreadTest
+ public void testWebViewLoads() throws Exception {
+ mOnUiThread.loadUrlAndWaitForCompletion("about:blank");
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTestActivity.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTestActivity.java
new file mode 100644
index 0000000..aae2b65
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTestActivity.java
@@ -0,0 +1,56 @@
+/*
+ * 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.cts.ephemeralapp1;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.webkit.WebView;
+
+import com.android.compatibility.common.util.NullWebViewUtils;
+
+public class WebViewTestActivity extends Activity {
+ private WebView mWebView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ try {
+ super.onCreate(savedInstanceState);
+ mWebView = new WebView(this);
+ setContentView(mWebView);
+ } catch (Exception e) {
+ NullWebViewUtils.determineIfWebViewAvailable(this, e);
+ }
+ }
+
+ public WebView getWebView() {
+ return mWebView;
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mWebView != null) {
+ ViewParent parent = mWebView.getParent();
+ if (parent instanceof ViewGroup) {
+ ((ViewGroup) parent).removeView(mWebView);
+ }
+ mWebView.destroy();
+ }
+ super.onDestroy();
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java
index 14ee824..22b8c25 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java
@@ -76,7 +76,7 @@
filter.addCategory(Intent.CATEGORY_DEFAULT);
mReceiver = new ActivityBroadcastReceiver(mResultQueue);
InstrumentationRegistry.getContext()
- .registerReceiver(mReceiver, filter, true /*visibleToEmphemeral*/);
+ .registerReceiver(mReceiver, filter, Context.RECEIVER_VISIBLE_TO_INSTANT_APPS);
}
@After
diff --git a/hostsidetests/appsecurity/test-apps/InstantCookieApp/src/test/instant/cookie/CookieTest.java b/hostsidetests/appsecurity/test-apps/InstantCookieApp/src/test/instant/cookie/CookieTest.java
index 37f6bba..774296b 100644
--- a/hostsidetests/appsecurity/test-apps/InstantCookieApp/src/test/instant/cookie/CookieTest.java
+++ b/hostsidetests/appsecurity/test-apps/InstantCookieApp/src/test/instant/cookie/CookieTest.java
@@ -25,6 +25,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
@RunWith(AndroidJUnit4.class)
public class CookieTest {
@@ -36,18 +37,23 @@
assertTrue(pm.isInstantApp());
// The max cookie size is greater than zero
- assertTrue(pm.getInstantAppCookieMaxSize() > 0);
+ assertTrue(pm.getInstantAppCookieMaxBytes() > 0);
// Initially there is no cookie
byte[] cookie = pm.getInstantAppCookie();
assertTrue(cookie != null && cookie.length == 0);
// Setting a cookie below max size should work
- assertTrue(pm.setInstantAppCookie("1".getBytes()));
+ pm.updateInstantAppCookie("1".getBytes());
// Setting a cookie above max size should not work
- assertFalse(pm.setInstantAppCookie(
- new byte[pm.getInstantAppCookieMaxSize() + 1]));
+ try {
+ pm.updateInstantAppCookie(
+ new byte[pm.getInstantAppCookieMaxBytes() + 1]);
+ fail("Shouldn't be able to set a cookie larger than max size");
+ } catch (IllegalArgumentException e) {
+ /* expected */
+ }
// Ensure cookie not modified
assertEquals("1", new String(pm.getInstantAppCookie()));
@@ -58,7 +64,7 @@
PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
// Set a cookie to later check when reinstalled as instant app
- assertTrue(pm.setInstantAppCookie("2".getBytes()));
+ pm.updateInstantAppCookie("2".getBytes());
}
@Test
@@ -77,7 +83,7 @@
assertTrue(pm.isInstantApp());
// Set a cookie to later check when upgrade to a normal app
- assertTrue(pm.setInstantAppCookie("3".getBytes()));
+ pm.updateInstantAppCookie("3".getBytes());
}
@Test
@@ -96,7 +102,7 @@
PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
// Set a cookie to later check when reinstalled as normal app
- assertTrue(pm.setInstantAppCookie("4".getBytes()));
+ pm.updateInstantAppCookie("4".getBytes());
}
@Test
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
index 4bd993e..a35574b 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
+++ b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
@@ -25,6 +25,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -126,7 +127,12 @@
public void testAccessPrimaryProfileFromManagedProfile() throws Exception {
// Try to access main profile from managed profile, which is not allowed.
assertEquals(0, mLauncherApps.getActivityList(null, mUser).size());
- assertNull(mLauncherApps.getApplicationInfo(SIMPLE_APP_PACKAGE, /* flags= */ 0, mUser));
+ try {
+ mLauncherApps.getApplicationInfo(SIMPLE_APP_PACKAGE, /* flags= */ 0, mUser);
+ fail("Missing exception");
+ } catch (PackageManager.NameNotFoundException e) {
+ // Expected.
+ }
assertFalse(mLauncherApps.isPackageEnabled(SIMPLE_APP_PACKAGE, mUser));
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.android.com/"));
diff --git a/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java b/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java
index d8f2f75..f4c0698 100644
--- a/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java
+++ b/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java
@@ -22,7 +22,6 @@
import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType.ON_CREATE;
import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType.ON_DESTROY;
import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType.ON_START_INPUT;
-import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType.ON_START_INPUT_VIEW;
import static android.inputmethodservice.cts.common.ImeCommandConstants.ACTION_IME_COMMAND;
import static android.inputmethodservice.cts.common.ImeCommandConstants.COMMAND_SWITCH_INPUT_METHOD;
import static android.inputmethodservice.cts.common.ImeCommandConstants.EXTRA_ARG_STRING1;
@@ -54,9 +53,7 @@
private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
- /**
- * Test to check {@link Ime1Constants} receives onCreate, onStartInput, and onStartInputView.
- */
+ /** Test to check CtsInputMethod1 receives onCreate and onStartInput. */
@Test
public void testCreateIme1() throws Throwable {
final TestHelper helper = new TestHelper(getClass(), DeviceTestConstants.TEST_CREATE_IME1);
@@ -65,7 +62,7 @@
.collect(startingFrom(helper.isStartOfTest()))
.filter(isFrom(Ime1Constants.CLASS).and(isType(ON_CREATE)))
.findAny().isPresent(),
- TIMEOUT, "Ime1Constants.onCreate is called");
+ TIMEOUT, "CtsInputMethod1.onCreate is called");
final long startActivityTime = SystemClock.uptimeMillis();
helper.launchActivity(DeviceTestConstants.PACKAGE, DeviceTestConstants.TEST_ACTIVITY_CLASS);
@@ -74,18 +71,10 @@
.filter(isNewerThan(startActivityTime))
.filter(isFrom(Ime1Constants.CLASS).and(isType(ON_START_INPUT)))
.findAny().isPresent(),
- TIMEOUT, "Ime1Constants.onStartInput is called");
-
- final long touchEntryTime = SystemClock.uptimeMillis();
- helper.findUiObject(R.id.text_entry).click();
-
- pollingCheck(() -> helper.queryAllEvents()
- .filter(isNewerThan(touchEntryTime))
- .filter(isFrom(Ime1Constants.CLASS).and(isType(ON_START_INPUT_VIEW)))
- .findAny().isPresent(),
- TIMEOUT, "Ime1Constants.onStartInputView is called");
+ TIMEOUT, "CtsInputMethod1.onStartInput is called");
}
+ /** Test to check IME is switched from CtsInputMethod1 to CtsInputMethod2. */
@Test
public void testSwitchIme1ToIme2() throws Throwable {
final TestHelper helper = new TestHelper(
@@ -95,7 +84,7 @@
.collect(startingFrom(helper.isStartOfTest()))
.filter(isFrom(Ime1Constants.CLASS).and(isType(ON_CREATE)))
.findAny().isPresent(),
- TIMEOUT, "Ime1Constants.onCreate is called");
+ TIMEOUT, "CtsInputMethod1.onCreate is called");
final long startActivityTime = SystemClock.uptimeMillis();
helper.launchActivity(DeviceTestConstants.PACKAGE, DeviceTestConstants.TEST_ACTIVITY_CLASS);
@@ -104,18 +93,11 @@
.filter(isNewerThan(startActivityTime))
.filter(isFrom(Ime1Constants.CLASS).and(isType(ON_START_INPUT)))
.findAny().isPresent(),
- TIMEOUT, "Ime1Constants.onStartInput is called");
+ TIMEOUT, "CtsInputMethod1.onStartInput is called");
- final long touchEntryTime = SystemClock.uptimeMillis();
helper.findUiObject(R.id.text_entry).click();
- pollingCheck(() -> helper.queryAllEvents()
- .filter(isNewerThan(touchEntryTime))
- .filter(isFrom(Ime1Constants.CLASS).and(isType(ON_START_INPUT_VIEW)))
- .findAny().isPresent(),
- TIMEOUT, "Ime1Constants.onStartInputView is called");
-
- // Switch IME from Ime1Constants to Ime2Constants.
+ // Switch IME from CtsInputMethod1 to CtsInputMethod2.
final long switchImeTime = SystemClock.uptimeMillis();
helper.shell(ShellCommandUtils.broadcastIntent(
ACTION_IME_COMMAND, Ime1Constants.PACKAGE,
@@ -124,21 +106,22 @@
pollingCheck(() -> helper.shell(ShellCommandUtils.getCurrentIme())
.equals(Ime2Constants.IME_ID),
- TIMEOUT, "Ime2Constants is current IME");
+ TIMEOUT, "CtsInputMethod2 is current IME");
pollingCheck(() -> helper.queryAllEvents()
.filter(isNewerThan(switchImeTime))
.filter(isFrom(Ime1Constants.CLASS).and(isType(ON_DESTROY)))
.findAny().isPresent(),
- TIMEOUT, "Ime1Constants.onDestroy is called");
+ TIMEOUT, "CtsInputMethod1.onDestroy is called");
pollingCheck(() -> helper.queryAllEvents()
.filter(isNewerThan(switchImeTime))
.filter(isFrom(Ime2Constants.CLASS))
- .collect(sequenceOfTypes(ON_CREATE, ON_START_INPUT, ON_START_INPUT_VIEW))
+ .collect(sequenceOfTypes(ON_CREATE, ON_START_INPUT))
.matched(),
TIMEOUT,
- "Ime2Constants.onCreate,onStartInput,onStartInputView are called in sequence");
+ "CtsInputMethod2.onCreate and onStartInput are called in sequence");
}
+ /** Test to check CtsInputMethod1 isn't current IME. */
@Test
public void testIme1IsNotCurrentIme() throws Throwable {
final TestHelper helper =
@@ -150,7 +133,7 @@
pollingCheck(() -> !helper.shell(ShellCommandUtils.getCurrentIme())
.equals(Ime1Constants.IME_ID),
TIMEOUT,
- "Ime1Constants is uninstalled or disabled, and current IME becomes other IME");
+ "CtsInputMethod1 is uninstalled or disabled, and current IME becomes other IME");
}
/**
diff --git a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java
index ad77b03..4be6ffe 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java
+++ b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java
@@ -101,7 +101,7 @@
List<VersionedPackage> dependentPackages = sharedLib.getDependentPackages();
- switch (sharedLib.getVersion()) {
+ switch ((int) sharedLib.getVersion()) {
case 1: {
firstLibFound = true;
assertSame(1, declaringPackage.getVersionCode());
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
index d7800c4..ade0963 100755
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
@@ -27,8 +27,14 @@
<application>
<activity android:name=".TestActivity"
android:resizeableActivity="true"
+ android:supportsPictureInPicture="true"
android:exported="true"
/>
+ <activity android:name=".TranslucentTestActivity"
+ android:resizeableActivity="true"
+ android:supportsPictureInPicture="true"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+ android:theme="@style/Theme.Transparent" />
<activity android:name=".VrTestActivity"
android:resizeableActivity="true"
android:exported="true"
@@ -113,12 +119,6 @@
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
android:exported="true"
/>
- <activity android:name=".VisibleBehindActivity"
- android:resizeableActivity="false"
- android:supportsPictureInPicture="true"
- android:exported="true"
- android:taskAffinity="nobody.but.VisibleBehindActivity"
- />
<activity android:name=".LaunchPipOnPipActivity"
android:resizeableActivity="false"
android:supportsPictureInPicture="true"
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/task_overlay.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/task_overlay.xml
new file mode 100644
index 0000000..67e0b08
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/task_overlay.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ 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
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#800000ff">
+</FrameLayout>
\ No newline at end of file
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
index 7e116a9..7b8a695 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
@@ -40,6 +40,12 @@
}
@Override
+ protected void onResume() {
+ super.onResume();
+ Log.i(getTag(), "onResume");
+ }
+
+ @Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.i(getTag(), "onConfigurationChanged");
@@ -76,6 +82,18 @@
}
@Override
+ protected void onPause() {
+ super.onPause();
+ Log.i(getTag(), "onPause");
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ Log.i(getTag(), "onStop");
+ }
+
+ @Override
protected void onDestroy() {
super.onDestroy();
Log.i(getTag(), "onDestroy");
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
index 0d49519..f60abfa 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
@@ -50,6 +50,8 @@
// Will apply the oriention to the value set in the EXTRA_FIXED_ORIENTATION extra.
private static final String ACTION_SET_REQUESTED_ORIENTATION =
"android.server.cts.PipActivity.set_requested_orientation";
+ // Intent action that will finish this activity
+ private static final String ACTION_FINISH = "android.server.cts.PipActivity.finish";
// Sets the fixed orientation (can be one of {@link ActivityInfo.ScreenOrientation}
private static final String EXTRA_FIXED_ORIENTATION = "fixed_orientation";
@@ -115,6 +117,9 @@
setRequestedOrientation(Integer.parseInt(intent.getStringExtra(
EXTRA_FIXED_ORIENTATION)));
break;
+ case ACTION_FINISH:
+ finish();
+ break;
}
}
}
@@ -177,17 +182,14 @@
launchIntent.setComponent(ComponentName.unflattenFromString(launchActivityComponent));
startActivity(launchIntent);
}
- }
- @Override
- protected void onStart() {
- super.onStart();
-
+ // Register the broadcast receiver
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_ENTER_PIP);
filter.addAction(ACTION_MOVE_TO_BACK);
filter.addAction(ACTION_EXPAND_PIP);
filter.addAction(ACTION_SET_REQUESTED_ORIENTATION);
+ filter.addAction(ACTION_FINISH);
registerReceiver(mReceiver, filter);
}
@@ -219,7 +221,6 @@
@Override
protected void onStop() {
super.onStop();
- unregisterReceiver(mReceiver);
if (getIntent().hasExtra(EXTRA_ASSERT_NO_ON_STOP_BEFORE_PIP) && !mEnteredPictureInPicture) {
Log.w("PipActivity", "Unexpected onStop() called before entering picture-in-picture");
@@ -228,6 +229,13 @@
}
@Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ unregisterReceiver(mReceiver);
+ }
+
+ @Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode);
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
index 567cbbb..ec45357 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
@@ -55,17 +55,22 @@
}
@Override
+ protected void onStart() {
+ super.onStart();
+ registerReceiver(mReceiver, new IntentFilter(ACTION_FINISH_SELF));
+ }
+
+ @Override
protected void onResume() {
super.onResume();
- registerReceiver(mReceiver, new IntentFilter(ACTION_FINISH_SELF));
final Configuration config = getResources().getConfiguration();
dumpDisplaySize(config);
dumpConfiguration(config);
}
@Override
- protected void onPause() {
- super.onPause();
+ protected void onStop() {
+ super.onStop();
unregisterReceiver(mReceiver);
}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentTestActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentTestActivity.java
new file mode 100644
index 0000000..1d10a51
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentTestActivity.java
@@ -0,0 +1,36 @@
+/*
+ * 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 android.server.cts;
+
+import android.os.Bundle;
+
+public class TranslucentTestActivity extends TestActivity {
+
+ private static final String TAG = TranslucentTestActivity.class.getSimpleName();
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.task_overlay);
+ }
+
+ @Override
+ protected String getTag() {
+ return TAG;
+ }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VisibleBehindActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VisibleBehindActivity.java
deleted file mode 100644
index 29feba9..0000000
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VisibleBehindActivity.java
+++ /dev/null
@@ -1,31 +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 android.server.cts;
-
-import android.app.Activity;
-import android.util.Log;
-
-public class VisibleBehindActivity extends Activity {
- private static final String TAG = "VisibleBehindActivity";
- @Override
- protected void onPause() {
- super.onPause();
- if (requestVisibleBehind(true)) {
- Log.e(TAG, "Failed to request visibility behind...");
- }
- }
-}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
index c89b9c4..d0db632 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
@@ -33,7 +33,6 @@
*/
public class ActivityManagerActivityVisibilityTests extends ActivityManagerTestBase {
private static final String TRANSLUCENT_ACTIVITY = "AlwaysFocusablePipActivity";
- private static final String VISIBLE_BEHIND_ACTIVITY = "VisibleBehindActivity";
private static final String PIP_ON_PIP_ACTIVITY = "LaunchPipOnPipActivity";
private static final String TEST_ACTIVITY_NAME = "TestActivity";
private static final String TRANSLUCENT_ACTIVITY_NAME = "TranslucentActivity";
@@ -41,54 +40,6 @@
private static final String TURN_SCREEN_ON_ACTIVITY_NAME = "TurnScreenOnActivity";
private static final String MOVE_TASK_TO_BACK_ACTIVITY_NAME = "MoveTaskToBackActivity";
- public void testVisibleBehindHomeActivity() throws Exception {
- if (noHomeScreen()) {
- return;
- }
-
- launchActivity(VISIBLE_BEHIND_ACTIVITY);
- mAmWmState.waitForValidState(mDevice, VISIBLE_BEHIND_ACTIVITY,
- FULLSCREEN_WORKSPACE_STACK_ID);
- launchHomeActivity();
-
- /* TODO: Find a proper way to wait until launcher activity
- * becomes fully visible. It appears that both VisibleBehindActivity
- * and home activity are visible at some point before the former
- * disappears.*/
- Thread.sleep(3000);
- mAmWmState.computeState(mDevice, null);
- mAmWmState.assertContainsStack(
- "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
- mAmWmState.assertFrontStack("Home stack must be the front stack.", HOME_STACK_ID);
- mAmWmState.assertVisibility(
- VISIBLE_BEHIND_ACTIVITY, hasDeviceFeature("android.software.leanback"));
- }
-
- public void testVisibleBehindOtherActivity_NotOverHome() throws Exception {
- launchActivity(VISIBLE_BEHIND_ACTIVITY);
- launchActivity(TRANSLUCENT_ACTIVITY);
-
- mAmWmState.computeState(mDevice,
- new String[] {VISIBLE_BEHIND_ACTIVITY, TRANSLUCENT_ACTIVITY});
- mAmWmState.assertVisibility(VISIBLE_BEHIND_ACTIVITY, true);
- mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
- }
-
- public void testVisibleBehindOtherActivity_OverHome() throws Exception {
- if (noHomeScreen()) {
- return;
- }
-
- executeShellCommand(getAmStartCmdOverHome(VISIBLE_BEHIND_ACTIVITY));
- mAmWmState.waitForValidState(mDevice, VISIBLE_BEHIND_ACTIVITY);
- executeShellCommand(getAmStartCmdOverHome(TRANSLUCENT_ACTIVITY));
-
- mAmWmState.computeState(mDevice,
- new String[] {VISIBLE_BEHIND_ACTIVITY, TRANSLUCENT_ACTIVITY});
- mAmWmState.assertVisibility(VISIBLE_BEHIND_ACTIVITY, true);
- mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
- }
-
public void testTranslucentActivityOnTopOfPinnedStack() throws Exception {
if (!supportsPip()) {
return;
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
index a6372a2..038eb8d 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
@@ -35,6 +35,7 @@
*/
public class ActivityManagerPinnedStackTests extends ActivityManagerTestBase {
private static final String TEST_ACTIVITY = "TestActivity";
+ private static final String TRANSLUCENT_TEST_ACTIVITY = "TranslucentTestActivity";
private static final String NON_RESIZEABLE_ACTIVITY = "NonResizeableActivity";
private static final String RESUME_WHILE_PAUSING_ACTIVITY = "ResumeWhilePausingActivity";
private static final String PIP_ACTIVITY = "PipActivity";
@@ -43,7 +44,7 @@
private static final String LAUNCH_INTO_PINNED_STACK_PIP_ACTIVITY =
"LaunchIntoPinnedStackPipActivity";
private static final String LAUNCH_IME_WITH_PIP_ACTIVITY = "LaunchImeWithPipActivity";
- private static final String LAUNCHER_ENTER_PIP_ACTIVITY = "LaunchEnterPipActivity";
+ private static final String LAUNCH_ENTER_PIP_ACTIVITY = "LaunchEnterPipActivity";
private static final String PIP_ON_STOP_ACTIVITY = "PipOnStopActivity";
private static final String EXTRA_FIXED_ORIENTATION = "fixed_orientation";
@@ -65,8 +66,12 @@
"android.server.cts.PipActivity.move_to_back";
private static final String PIP_ACTIVITY_ACTION_EXPAND_PIP =
"android.server.cts.PipActivity.expand_pip";
- private static final String ACTION_SET_REQUESTED_ORIENTATION =
+ private static final String PIP_ACTIVITY_ACTION_SET_REQUESTED_ORIENTATION =
"android.server.cts.PipActivity.set_requested_orientation";
+ private static final String PIP_ACTIVITY_ACTION_FINISH =
+ "android.server.cts.PipActivity.finish";
+ private static final String TEST_ACTIVITY_ACTION_FINISH =
+ "android.server.cts.TestActivity.finish_self";
private static final int APP_OPS_OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE = 67;
private static final int APP_OPS_MODE_ALLOWED = 0;
@@ -93,22 +98,25 @@
private static final float ABOVE_MAX_ASPECT_RATIO = MAX_ASPECT_RATIO + FLOAT_COMPARE_EPSILON;
public void testEnterPictureInPictureMode() throws Exception {
- pinnedStackTester(getAmStartCmd(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true"),
- PIP_ACTIVITY, false, false);
+ pinnedStackTester(getAmStartCmd(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true"), PIP_ACTIVITY,
+ false /* moveTopToPinnedStack */, false /* isFocusable */);
}
public void testMoveTopActivityToPinnedStack() throws Exception {
- pinnedStackTester(getAmStartCmd(PIP_ACTIVITY), PIP_ACTIVITY, true, false);
+ pinnedStackTester(getAmStartCmd(PIP_ACTIVITY), PIP_ACTIVITY,
+ true /* moveTopToPinnedStack */, false /* isFocusable */);
}
public void testAlwaysFocusablePipActivity() throws Exception {
pinnedStackTester(getAmStartCmd(ALWAYS_FOCUSABLE_PIP_ACTIVITY),
- ALWAYS_FOCUSABLE_PIP_ACTIVITY, true, true);
+ ALWAYS_FOCUSABLE_PIP_ACTIVITY, false /* moveTopToPinnedStack */,
+ true /* isFocusable */);
}
public void testLaunchIntoPinnedStack() throws Exception {
pinnedStackTester(getAmStartCmd(LAUNCH_INTO_PINNED_STACK_PIP_ACTIVITY),
- ALWAYS_FOCUSABLE_PIP_ACTIVITY, false, true);
+ ALWAYS_FOCUSABLE_PIP_ACTIVITY, false /* moveTopToPinnedStack */,
+ true /* isFocusable */);
}
public void testNonTappablePipActivity() throws Exception {
@@ -471,6 +479,9 @@
public void testDisallowMultipleTasksInPinnedStack() throws Exception {
if (!supportsPip()) return;
+ // Launch a test activity so that we have multiple fullscreen tasks
+ launchActivity(TEST_ACTIVITY);
+
// Launch first PIP activity
launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
@@ -581,7 +592,7 @@
// stack, but that the home stack is still focused
removeStacks(PINNED_STACK_ID);
assertPinnedStackStateOnMoveToFullscreen(PIP_ACTIVITY, HOME_STACK_ID,
- true /* expectTopTaskHasActivity */, false /* expectBottomTaskHasActivity */);
+ false /* expectTopTaskHasActivity */, true /* expectBottomTaskHasActivity */);
}
public void testMovePipToBackWithNoFullscreenStack() throws Exception {
@@ -598,7 +609,7 @@
// fullscreen stack existed before)
executeShellCommand("am broadcast -a " + PIP_ACTIVITY_ACTION_MOVE_TO_BACK);
assertPinnedStackStateOnMoveToFullscreen(PIP_ACTIVITY, HOME_STACK_ID,
- true /* expectTopTaskHasActivity */, true /* expectBottomTaskHasActivity */);
+ false /* expectTopTaskHasActivity */, true /* expectBottomTaskHasActivity */);
}
public void testMovePipToBackWithVisibleFullscreenStack() throws Exception {
@@ -630,7 +641,7 @@
// stack, but that the home stack is still focused
executeShellCommand("am broadcast -a " + PIP_ACTIVITY_ACTION_MOVE_TO_BACK);
assertPinnedStackStateOnMoveToFullscreen(PIP_ACTIVITY, HOME_STACK_ID,
- true /* expectTopTaskHasActivity */, false /* expectBottomTaskHasActivity */);
+ false /* expectTopTaskHasActivity */, true /* expectBottomTaskHasActivity */);
}
public void testPinnedStackAlwaysOnTop() throws Exception {
@@ -677,7 +688,7 @@
// Try to enter picture-in-picture from an activity that has more than one activity in the
// task and ensure that it works
- launchActivity(LAUNCHER_ENTER_PIP_ACTIVITY);
+ launchActivity(LAUNCH_ENTER_PIP_ACTIVITY);
mAmWmState.waitForValidState(mDevice, PIP_ACTIVITY, PINNED_STACK_ID);
assertPinnedStackExists();
}
@@ -750,6 +761,43 @@
assertValidPictureInPictureCallbackOrder(PIP_ACTIVITY, logSeparator);
}
+ public void testStopBeforeMultiWindowCallbacksOnDismiss() throws Exception {
+ if (!supportsPip()) return;
+
+ // Launch a PiP activity
+ launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
+ assertPinnedStackExists();
+
+ // Dismiss it
+ String logSeparator = clearLogcat();
+ removeStacks(PINNED_STACK_ID);
+ mAmWmState.waitForValidState(mDevice, PIP_ACTIVITY, FULLSCREEN_WORKSPACE_STACK_ID);
+
+ // Confirm that we get stop before the multi-window and picture-in-picture mode change
+ // callbacks
+ final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(PIP_ACTIVITY,
+ logSeparator);
+ if (lifecycleCounts.mStopCount != 1) {
+ fail(PIP_ACTIVITY + " has received " + lifecycleCounts.mStopCount
+ + " onStop() calls, expecting 1");
+ } else if (lifecycleCounts.mPictureInPictureModeChangedCount != 1) {
+ fail(PIP_ACTIVITY + " has received " + lifecycleCounts.mPictureInPictureModeChangedCount
+ + " onMultiWindowModeChanged() calls, expecting 1");
+ } else if (lifecycleCounts.mMultiWindowModeChangedCount != 1) {
+ fail(PIP_ACTIVITY + " has received " + lifecycleCounts.mMultiWindowModeChangedCount
+ + " onPictureInPictureModeChanged() calls, expecting 1");
+ } else {
+ int lastStopLine = lifecycleCounts.mLastStopLineIndex;
+ int lastPipLine = lifecycleCounts.mLastPictureInPictureModeChangedLineIndex;
+ int lastMwLine = lifecycleCounts.mLastMultiWindowModeChangedLineIndex;
+ if (!(lastStopLine < lastPipLine && lastPipLine < lastMwLine)) {
+ fail(PIP_ACTIVITY + " has received callbacks in unexpected order. Expected:"
+ + " stop < pip < mw, but got line indices: " + lastStopLine + ", "
+ + lastPipLine + ", " + lastMwLine + " respectively");
+ }
+ }
+ }
+
public void testPreventSetAspectRatioWhileExpanding() throws Exception {
if (!supportsPip()) return;
@@ -774,7 +822,8 @@
assertPinnedStackExists();
// Request that the orientation is set to landscape
- executeShellCommand("am broadcast -a " + ACTION_SET_REQUESTED_ORIENTATION + " -e "
+ executeShellCommand("am broadcast -a "
+ + PIP_ACTIVITY_ACTION_SET_REQUESTED_ORIENTATION + " -e "
+ EXTRA_FIXED_ORIENTATION + " " + String.valueOf(ORIENTATION_LANDSCAPE));
// Launch the activity back into fullscreen and ensure that it is now in landscape
@@ -794,6 +843,53 @@
assertPinnedStackExists();
}
+ public void testFinishPipActivityWithTaskOverlay() throws Exception {
+ if (!supportsPip()) return;
+
+ // Launch PiP activity
+ launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
+ assertPinnedStackExists();
+ int taskId = mAmWmState.getAmState().getStackById(PINNED_STACK_ID).getTopTask().mTaskId;
+
+ // Launch task overlay activity into PiP activity task
+ launchActivityAsTaskOverlay(TRANSLUCENT_TEST_ACTIVITY, taskId, PINNED_STACK_ID);
+
+ // Finish the PiP activity and ensure that there is no pinned stack
+ executeShellCommand("am broadcast -a " + PIP_ACTIVITY_ACTION_FINISH);
+ mAmWmState.waitForWithAmState(mDevice, (amState) -> {
+ ActivityStack stack = amState.getStackById(PINNED_STACK_ID);
+ if (stack != null) {
+ return false;
+ }
+ return true;
+ }, "Waiting for pinned stack to be removed...");
+ assertPinnedStackDoesNotExist();
+ }
+
+ public void testNoResumeAfterTaskOverlayFinishes() throws Exception {
+ if (!supportsPip()) return;
+
+ // Launch PiP activity
+ launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
+ assertPinnedStackExists();
+ int taskId = mAmWmState.getAmState().getStackById(PINNED_STACK_ID).getTopTask().mTaskId;
+
+ // Launch task overlay activity into PiP activity task
+ launchActivityAsTaskOverlay(TRANSLUCENT_TEST_ACTIVITY, taskId, PINNED_STACK_ID);
+
+ // Finish the task overlay activity while animating and ensure that the PiP activity never
+ // got resumed
+ String logSeparator = clearLogcat();
+ executeShellCommand("am stack resize-animated 4 20 20 500 500");
+ executeShellCommand("am broadcast -a " + TEST_ACTIVITY_ACTION_FINISH);
+ mAmWmState.waitFor(mDevice, (amState, wmState) -> !amState.containsActivity(
+ TRANSLUCENT_TEST_ACTIVITY), "Waiting for test activity to finish...");
+ final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(PIP_ACTIVITY,
+ logSeparator);
+ assertTrue(lifecycleCounts.mResumeCount == 0);
+ assertTrue(lifecycleCounts.mPauseCount == 0);
+ }
+
/**
* Called after the given {@param activityName} has been moved to the fullscreen stack. Ensures
* that the {@param focusedStackId} is focused, and checks the top and/or bottom tasks in the
@@ -942,6 +1038,16 @@
}
/**
+ * Launches the given {@param activityName} into the {@param taskId} as a task overlay.
+ */
+ private void launchActivityAsTaskOverlay(String activityName, int taskId, int stackId)
+ throws Exception {
+ executeShellCommand(getAmStartCmd(activityName) + " --task " + taskId + " --task-overlay");
+
+ mAmWmState.waitForValidState(mDevice, activityName, stackId);
+ }
+
+ /**
* Sets an app-ops op for a given package to a given mode.
*/
private void setAppOpsOpToMode(String packageName, int op, int mode) throws Exception {
@@ -955,6 +1061,10 @@
executeShellCommand(INPUT_KEYEVENT_WINDOW);
}
+ /**
+ * TODO: Improve tests check to actually check that apps are not interactive instead of checking
+ * if the stack is focused.
+ */
private void pinnedStackTester(String startActivityCmd, String topActivityName,
boolean moveTopToPinnedStack, boolean isFocusable) throws Exception {
@@ -982,8 +1092,8 @@
// Not checking for resumed state here because PiP overlay can be launched on top
// in different task by SystemUI.
} else {
- mAmWmState.assertNotFocusedStack(
- "Pinned stack can't be the focused stack.", PINNED_STACK_ID);
+ // Don't assert that the stack is not focused as a focusable PiP overlay can be
+ // launched on top as a task overlay by SystemUI.
mAmWmState.assertNotFocusedActivity(
"Pinned activity can't be the focused activity.", topActivityName);
mAmWmState.assertNotResumedActivity(
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
index 4ef07cf..bfd6b5a 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
@@ -905,10 +905,13 @@
}
private static final Pattern sCreatePattern = Pattern.compile("(.+): onCreate");
+ private static final Pattern sResumePattern = Pattern.compile("(.+): onResume");
+ private static final Pattern sPausePattern = Pattern.compile("(.+): onPause");
private static final Pattern sConfigurationChangedPattern =
Pattern.compile("(.+): onConfigurationChanged");
private static final Pattern sMovedToDisplayPattern =
Pattern.compile("(.+): onMovedToDisplay");
+ private static final Pattern sStopPattern = Pattern.compile("(.+): onStop");
private static final Pattern sDestroyPattern = Pattern.compile("(.+): onDestroy");
private static final Pattern sMultiWindowModeChangedPattern =
Pattern.compile("(.+): onMultiWindowModeChanged");
@@ -999,6 +1002,7 @@
class ActivityLifecycleCounts {
int mCreateCount;
+ int mResumeCount;
int mConfigurationChangedCount;
int mLastConfigurationChangedLineIndex;
int mMovedToDisplayCount;
@@ -1006,6 +1010,9 @@
int mLastMultiWindowModeChangedLineIndex;
int mPictureInPictureModeChangedCount;
int mLastPictureInPictureModeChangedLineIndex;
+ int mPauseCount;
+ int mStopCount;
+ int mLastStopLineIndex;
int mDestroyCount;
public ActivityLifecycleCounts(String activityName, String logSeparator)
@@ -1021,6 +1028,12 @@
continue;
}
+ matcher = sResumePattern.matcher(line);
+ if (matcher.matches()) {
+ mResumeCount++;
+ continue;
+ }
+
matcher = sConfigurationChangedPattern.matcher(line);
if (matcher.matches()) {
mConfigurationChangedCount++;
@@ -1048,6 +1061,19 @@
continue;
}
+ matcher = sPausePattern.matcher(line);
+ if (matcher.matches()) {
+ mPauseCount++;
+ continue;
+ }
+
+ matcher = sStopPattern.matcher(line);
+ if (matcher.matches()) {
+ mStopCount++;
+ mLastStopLineIndex = lineIndex;
+ continue;
+ }
+
matcher = sDestroyPattern.matcher(line);
if (matcher.matches()) {
mDestroyCount++;
diff --git a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java
index d3118ad..25f8317 100644
--- a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java
+++ b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java
@@ -20,6 +20,7 @@
import com.android.tradefed.log.LogUtil.CLog;
import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
public class ShortcutManagerBackupTest extends BaseShortcutManagerHostTest {
private static final String LAUNCHER1_APK = "CtsShortcutBackupLauncher1.apk";
@@ -62,13 +63,12 @@
clearShortcuts(PUBLISHER2_PKG, getPrimaryUserId());
clearShortcuts(PUBLISHER3_PKG, getPrimaryUserId());
- getDevice().uninstallPackage(LAUNCHER1_PKG);
- getDevice().uninstallPackage(LAUNCHER2_PKG);
- getDevice().uninstallPackage(LAUNCHER3_PKG);
-
- getDevice().uninstallPackage(PUBLISHER1_PKG);
- getDevice().uninstallPackage(PUBLISHER2_PKG);
- getDevice().uninstallPackage(PUBLISHER3_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER1_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER2_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER3_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER1_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER2_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER3_PKG);
waitUntilPackagesGone();
}
@@ -120,6 +120,42 @@
}
+ private void uninstallPackageAndWaitUntilBroadcastsDrain(String pkg) throws Exception {
+ getDevice().uninstallPackage(pkg);
+ waitUntilBroadcastsDrain();
+ }
+
+ /**
+ * Wait until the broadcasts queues all drain.
+ */
+ private void waitUntilBroadcastsDrain() throws Exception {
+ final long TIMEOUT = System.nanoTime() +
+ TimeUnit.SECONDS.toNanos(BROADCAST_TIMEOUT_SECONDS);
+
+ final Pattern re = Pattern.compile("^\\s+Active (ordered)? broadcasts \\[",
+ Pattern.MULTILINE);
+
+ String dumpsys = "";
+ while (System.nanoTime() < TIMEOUT) {
+ Thread.sleep(1000);
+
+ dumpsys = getDevice().executeShellCommand("dumpsys activity broadcasts");
+
+ if (re.matcher(dumpsys).find()) {
+ continue;
+ }
+
+ CLog.d("Broadcast queues drained:\n" + dumpsys);
+
+ dumpsys("Broadcast queues drained");
+
+ // All packages gone.
+ return;
+ }
+ fail("Broadcast queues didn't drain before time out."
+ + " Last dumpsys=\n" + dumpsys);
+ }
+
/**
* Wait until all the test packages are forgotten by the shortcut manager.
*/
@@ -146,7 +182,7 @@
if (dumpsys.contains("Package: " + PUBLISHER2_PKG)) continue;
if (dumpsys.contains("Package: " + PUBLISHER3_PKG)) continue;
- dumpsys("All clear");
+ dumpsys("Shortcut manager handled broadcasts");
// All packages gone.
return;
@@ -187,17 +223,20 @@
doBackup();
// Uninstall all apps
- getDevice().uninstallPackage(LAUNCHER1_PKG);
- getDevice().uninstallPackage(LAUNCHER2_PKG);
- getDevice().uninstallPackage(LAUNCHER3_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER1_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER2_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER3_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER1_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER2_PKG);
+ uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER3_PKG);
- getDevice().uninstallPackage(PUBLISHER1_PKG);
- getDevice().uninstallPackage(PUBLISHER2_PKG);
- getDevice().uninstallPackage(PUBLISHER3_PKG);
// Make sure the shortcut service handled all the uninstall broadcasts.
waitUntilPackagesGone();
+ // Do it one more time just in case...
+ waitUntilBroadcastsDrain();
+
// Then restore
doRestore();
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index 1979e97..c081df9 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -56,7 +56,6 @@
mAccessibilityManager = (AccessibilityManager)
getInstrumentation().getContext().getSystemService(Service.ACCESSIBILITY_SERVICE);
mTargetContext = getInstrumentation().getTargetContext();
- ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
}
@Override
@@ -83,6 +82,7 @@
}
public void testIsTouchExplorationEnabled() throws Exception {
+ ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
new PollingCheck() {
@Override
protected boolean check() {
@@ -115,6 +115,7 @@
}
public void testGetEnabledAccessibilityServiceList() throws Exception {
+ ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
List<AccessibilityServiceInfo> enabledServices =
mAccessibilityManager.getEnabledAccessibilityServiceList(
AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
@@ -138,6 +139,7 @@
}
public void testGetEnabledAccessibilityServiceListForType() throws Exception {
+ ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
List<AccessibilityServiceInfo> enabledServices =
mAccessibilityManager.getEnabledAccessibilityServiceList(
AccessibilityServiceInfo.FEEDBACK_SPOKEN);
@@ -155,6 +157,7 @@
}
public void testGetEnabledAccessibilityServiceListForTypes() throws Exception {
+ ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
// For this test, also enable a service with multiple feedback types
ServiceControlUtils.enableMultipleFeedbackTypesService(getInstrumentation());
@@ -214,6 +217,7 @@
public void testInterrupt() throws Exception {
// The APIs are heavily tested in the android.accessibilityservice package.
// This just makes sure the call does not throw an exception.
+ ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
waitForAccessibilityEnabled();
mAccessibilityManager.interrupt();
}
@@ -221,24 +225,71 @@
public void testSendAccessibilityEvent() throws Exception {
// The APIs are heavily tested in the android.accessibilityservice package.
// This just makes sure the call does not throw an exception.
+ ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
waitForAccessibilityEnabled();
mAccessibilityManager.sendAccessibilityEvent(AccessibilityEvent.obtain(
AccessibilityEvent.TYPE_VIEW_CLICKED));
}
- public void testTouchExplorationStateChanged() throws Exception {
- waitForTouchExplorationEnabled();
+ public void testTouchExplorationListener() throws Exception {
+ final Object waitObject = new Object();
+ final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
+
+ TouchExplorationStateChangeListener listener = (boolean b) -> {
+ synchronized (waitObject) {
+ atomicBoolean.set(b);
+ waitObject.notifyAll();
+ }
+ };
+ mAccessibilityManager.addTouchExplorationStateChangeListener(listener);
+ ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
+ assertAtomicBooleanBecomes(atomicBoolean, true, waitObject,
+ "Touch exploration state listener not called when services enabled");
+ assertTrue("Listener told that touch exploration is enabled, but manager says disabled",
+ mAccessibilityManager.isTouchExplorationEnabled());
+ ServiceControlUtils.turnAccessibilityOff(getInstrumentation());
+ assertAtomicBooleanBecomes(atomicBoolean, false, waitObject,
+ "Touch exploration state listener not called when services disabled");
+ assertFalse("Listener told that touch exploration is disabled, but manager says it enabled",
+ mAccessibilityManager.isTouchExplorationEnabled());
+ mAccessibilityManager.removeTouchExplorationStateChangeListener(listener);
}
- private void assertListenerCalled(AtomicBoolean listenerCalled, Object waitObject)
+ public void testAccessibilityStateListener() throws Exception {
+ final Object waitObject = new Object();
+ final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
+
+ AccessibilityStateChangeListener listener = (boolean b) -> {
+ synchronized (waitObject) {
+ atomicBoolean.set(b);
+ waitObject.notifyAll();
+ }
+ };
+ mAccessibilityManager.addAccessibilityStateChangeListener(listener);
+ ServiceControlUtils.enableMultipleFeedbackTypesService(getInstrumentation());
+ assertAtomicBooleanBecomes(atomicBoolean, true, waitObject,
+ "Accessibility state listener not called when services enabled");
+ assertTrue("Listener told that accessibility is enabled, but manager says disabled",
+ mAccessibilityManager.isEnabled());
+ ServiceControlUtils.turnAccessibilityOff(getInstrumentation());
+ assertAtomicBooleanBecomes(atomicBoolean, false, waitObject,
+ "Accessibility state listener not called when services disabled");
+ assertFalse("Listener told that accessibility is disabled, but manager says enabled",
+ mAccessibilityManager.isEnabled());
+ mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
+ }
+
+ private void assertAtomicBooleanBecomes(AtomicBoolean atomicBoolean,
+ boolean expectedValue, Object waitObject, String message)
throws Exception {
long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
synchronized (waitObject) {
- while (!listenerCalled.get() && (System.currentTimeMillis() < timeoutTime)) {
+ while ((atomicBoolean.get() != expectedValue)
+ && (System.currentTimeMillis() < timeoutTime)) {
waitObject.wait(timeoutTime - System.currentTimeMillis());
}
}
- assertTrue("Timed out waiting for listener called", listenerCalled.get());
+ assertTrue(message, atomicBoolean.get() == expectedValue);
}
private void waitForAccessibilityEnabled() throws InterruptedException {
@@ -247,7 +298,7 @@
AccessibilityStateChangeListener listener = (boolean b) -> {
synchronized (waitObject) {
waitObject.notifyAll();
- }
+ }
};
mAccessibilityManager.addAccessibilityStateChangeListener(listener);
long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
@@ -260,25 +311,4 @@
mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
assertTrue("Timed out enabling accessibility", mAccessibilityManager.isEnabled());
}
-
- private void waitForTouchExplorationEnabled() throws InterruptedException {
- final Object waitObject = new Object();
-
- TouchExplorationStateChangeListener listener = (boolean b) -> {
- synchronized (waitObject) {
- waitObject.notifyAll();
- }
- };
- mAccessibilityManager.addTouchExplorationStateChangeListener(listener);
- long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
- synchronized (waitObject) {
- while (!mAccessibilityManager.isTouchExplorationEnabled()
- && (System.currentTimeMillis() < timeoutTime)) {
- waitObject.wait(timeoutTime - System.currentTimeMillis());
- }
- }
- mAccessibilityManager.removeTouchExplorationStateChangeListener(listener);
- assertTrue("Timed out enabling touch exploration",
- mAccessibilityManager.isTouchExplorationEnabled());
- }
}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java b/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java
index 9c4d9da..9783cb8 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java
@@ -165,10 +165,14 @@
* @param instrumentation A valid instrumentation
*/
public static void turnAccessibilityOff(Instrumentation instrumentation) {
- SpeakingAccessibilityService.sConnectedInstance.disableSelf();
- SpeakingAccessibilityService.sConnectedInstance = null;
- VibratingAccessibilityService.sConnectedInstance.disableSelf();
- VibratingAccessibilityService.sConnectedInstance = null;
+ if (SpeakingAccessibilityService.sConnectedInstance != null) {
+ SpeakingAccessibilityService.sConnectedInstance.disableSelf();
+ SpeakingAccessibilityService.sConnectedInstance = null;
+ }
+ if (VibratingAccessibilityService.sConnectedInstance != null) {
+ VibratingAccessibilityService.sConnectedInstance.disableSelf();
+ VibratingAccessibilityService.sConnectedInstance = null;
+ }
if (SpeakingAndVibratingAccessibilityService.sConnectedInstance != null) {
SpeakingAndVibratingAccessibilityService.sConnectedInstance.disableSelf();
SpeakingAndVibratingAccessibilityService.sConnectedInstance = null;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
index 23650a6..0f8b9c0 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
@@ -289,6 +289,8 @@
final AccessibilityNodeInfo text = mUiAutomation.getRootInActiveWindow()
.findAccessibilityNodeInfosByText(getString(stringId)).get(0);
CharSequence accessibilityTextWithSpan = text.getText();
+ // The span should work even with the node recycled
+ text.recycle();
assertTrue(accessibilityTextWithSpan instanceof Spanned);
T spans[] = ((Spanned) accessibilityTextWithSpan)
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
index 2ed4b39..8f9c51c 100755
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
@@ -653,7 +653,7 @@
numPictureInPictureWindows++;
}
}
- assertEquals(1, numPictureInPictureWindows);
+ assertTrue(numPictureInPictureWindows >= 1);
}
private boolean isDividerWindowPresent(UiAutomation uiAutomation) {
diff --git a/tests/app/app/src/android/app/stubs/LocalForegroundService.java b/tests/app/app/src/android/app/stubs/LocalForegroundService.java
index e0051a4..d60a1df 100644
--- a/tests/app/app/src/android/app/stubs/LocalForegroundService.java
+++ b/tests/app/app/src/android/app/stubs/LocalForegroundService.java
@@ -45,9 +45,13 @@
private int mNotificationId = 0;
@Override
- public void onStart(Intent intent, int startId) {
- super.onStart(intent, startId);
+ public void onCreate() {
+ super.onCreate();
+ Log.d(TAG, "service created: " + this + " in " + android.os.Process.myPid());
+ }
+ @Override
+ public void onStart(Intent intent, int startId) {
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(new NotificationChannel(
NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID,
@@ -56,6 +60,8 @@
Context context = getApplicationContext();
int command = intent.getIntExtra(EXTRA_COMMAND, -1);
+ Log.d(TAG, "service start cmd " + command + ", intent " + intent);
+
switch (command) {
case COMMAND_START_FOREGROUND:
mNotificationId ++;
@@ -89,11 +95,15 @@
default:
Log.e(TAG, "Unknown command: " + command);
}
+
+ // Do parent's onStart at the end, so we don't race with the test code waiting for us to
+ // execute.
+ super.onStart(intent, startId);
}
@Override
public void onDestroy() {
- Log.d(TAG, "service destroyed");
+ Log.d(TAG, "service destroyed: " + this + " in " + android.os.Process.myPid());
super.onDestroy();
}
diff --git a/tests/app/src/android/app/cts/ActionBarTest.java b/tests/app/src/android/app/cts/ActionBarTest.java
index 351339b..8bfaa59 100644
--- a/tests/app/src/android/app/cts/ActionBarTest.java
+++ b/tests/app/src/android/app/cts/ActionBarTest.java
@@ -24,7 +24,6 @@
import android.test.UiThreadTest;
import android.view.KeyEvent;
import android.view.Window;
-import org.junit.Assume;
public class ActionBarTest extends ActivityInstrumentationTestCase2<ActionBarActivity> {
@@ -85,7 +84,9 @@
}
public void testOptionsMenuKey() {
- Assume.assumeTrue(mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL));
+ if (!mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
+ return;
+ }
final boolean menuIsVisible[] = {false};
mActivity.getActionBar().addOnMenuVisibilityListener(
isVisible -> menuIsVisible[0] = isVisible);
diff --git a/tests/app/src/android/app/cts/ActivityOptionsTest.java b/tests/app/src/android/app/cts/ActivityOptionsTest.java
new file mode 100644
index 0000000..eab44c5
--- /dev/null
+++ b/tests/app/src/android/app/cts/ActivityOptionsTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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 android.app.cts;
+
+import android.app.ActivityOptions;
+import android.os.Bundle;
+import android.test.AndroidTestCase;
+
+public class ActivityOptionsTest extends AndroidTestCase {
+
+ public void testActivityOptionsBundle_makeBasic() throws Throwable {
+ ActivityOptions options = ActivityOptions.makeBasic();
+ Bundle bundle = options.toBundle();
+
+ assertNotNull(bundle);
+ }
+}
diff --git a/tests/app/src/android/app/cts/ServiceTest.java b/tests/app/src/android/app/cts/ServiceTest.java
index 0e7b308..5f8202d 100644
--- a/tests/app/src/android/app/cts/ServiceTest.java
+++ b/tests/app/src/android/app/cts/ServiceTest.java
@@ -574,12 +574,14 @@
boolean success = false;
try {
// Start service as foreground - it should show notification #1
+ Log.d(TAG, "Expecting first start state...");
mExpectedServiceState = STATE_START_1;
startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND);
waitForResultOrThrow(DELAY, "service to start first time");
assertNotification(1, LocalForegroundService.getNotificationTitle(1));
// Stop foreground removing notification
+ Log.d(TAG, "Expecting second start state...");
mExpectedServiceState = STATE_START_2;
if (usingFlags) {
startForegroundService(LocalForegroundService
@@ -730,7 +732,8 @@
boolean success = false;
PendingIntent pi = PendingIntent.getForegroundService(mContext, 1,
- foregroundServiceIntent(LocalForegroundService.COMMAND_START_FOREGROUND), 0);
+ foregroundServiceIntent(LocalForegroundService.COMMAND_START_FOREGROUND),
+ PendingIntent.FLAG_CANCEL_CURRENT);
TestSendCallback callback = new TestSendCallback();
try {
diff --git a/tests/app/src/android/app/cts/ToolbarActionBarTest.java b/tests/app/src/android/app/cts/ToolbarActionBarTest.java
index d625802..46ab200 100644
--- a/tests/app/src/android/app/cts/ToolbarActionBarTest.java
+++ b/tests/app/src/android/app/cts/ToolbarActionBarTest.java
@@ -21,7 +21,6 @@
import android.view.KeyEvent;
import android.view.Window;
-import org.junit.Assume;
public class ToolbarActionBarTest extends ActivityInstrumentationTestCase2<ToolbarActivity> {
@@ -40,7 +39,9 @@
}
public void testOptionsMenuKey() {
- Assume.assumeTrue(mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL));
+ if (!mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
+ return;
+ }
final boolean menuIsVisible[] = {false};
mActivity.getActionBar().addOnMenuVisibilityListener(
isVisible -> menuIsVisible[0] = isVisible);
diff --git a/tests/app/src/android/app/cts/android/app/cts/tools/ServiceConnectionHandler.java b/tests/app/src/android/app/cts/android/app/cts/tools/ServiceConnectionHandler.java
index 5094366..46dd551 100644
--- a/tests/app/src/android/app/cts/android/app/cts/tools/ServiceConnectionHandler.java
+++ b/tests/app/src/android/app/cts/android/app/cts/tools/ServiceConnectionHandler.java
@@ -164,7 +164,7 @@
}
@Override
- public void onBindingDead(ComponentName name) {
+ public void onBindingDied(ComponentName name) {
synchronized (this) {
// We want to remain connected to this service.
if (mMonitoring) {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
index b4f5f06..cb23ab5 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
@@ -262,12 +262,14 @@
private final Map<String, RemoteViews> mFieldPresentations;
private final RemoteViews mPresentation;
private final IntentSender mAuthentication;
+ private final String mId;
private CannedDataset(Builder builder) {
mFieldValues = builder.mFieldValues;
mFieldPresentations = builder.mFieldPresentations;
mPresentation = builder.mPresentation;
mAuthentication = builder.mAuthentication;
+ mId = builder.mId;
}
/**
@@ -296,13 +298,13 @@
}
}
}
- builder.setAuthentication(mAuthentication);
+ builder.setId(mId).setAuthentication(mAuthentication);
return builder.build();
}
@Override
public String toString() {
- return "CannedDataset: [hasPresentation=" + (mPresentation != null)
+ return "CannedDataset " + mId + " : [hasPresentation=" + (mPresentation != null)
+ ", fieldPresentations=" + (mFieldPresentations)
+ ", hasAuthentication=" + (mAuthentication != null)
+ ", fieldValuess=" + mFieldValues + "]";
@@ -313,6 +315,7 @@
private final Map<String, RemoteViews> mFieldPresentations = new HashMap<>();
private RemoteViews mPresentation;
private IntentSender mAuthentication;
+ private String mId;
public Builder() {
@@ -383,6 +386,14 @@
return this;
}
+ /**
+ * Sets the name.
+ */
+ public Builder setId(String id) {
+ mId = id;
+ return this;
+ }
+
public CannedDataset build() {
return new CannedDataset(this);
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java
index 03be6a4..b04b45f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java
@@ -28,6 +28,7 @@
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -64,6 +65,7 @@
private EditText mCcNumber;
private Spinner mCcExpiration;
+ private ArrayAdapter<CharSequence> mCcExpirationAdapter;
private RadioGroup mAddress;
private RadioButton mHomeAddress;
private CheckBox mSaveCc;
@@ -87,11 +89,11 @@
mBuyButton = (Button) findViewById(R.id.buy);
mClearButton = (Button) findViewById(R.id.clear);
- final ArrayAdapter<CharSequence> expirationValuesAdapter = createFromResource(this,
+ mCcExpirationAdapter = createFromResource(this,
R.array.cc_expiration_values, android.R.layout.simple_spinner_item);
- expirationValuesAdapter
+ mCcExpirationAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- mCcExpiration.setAdapter(expirationValuesAdapter);
+ mCcExpiration.setAdapter(mCcExpirationAdapter);
mBuyButton.setOnClickListener((v) -> buy());
mClearButton.setOnClickListener((v) -> resetFields());
@@ -164,6 +166,13 @@
}
/**
+ * Visits the {@code ccExpirationDate} adapter in the UiThread.
+ */
+ void onCcExpirationAdapter(Visitor<ArrayAdapter<CharSequence>> v) {
+ syncRunOnUiThread(() -> v.visit(mCcExpirationAdapter));
+ }
+
+ /**
* Visits the {@code address} in the UiThread.
*/
void onAddress(Visitor<RadioGroup> v) {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
index 7289b5a..5a46c78 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
@@ -41,10 +41,7 @@
import android.autofillservice.cts.CannedFillResponse.CannedDataset;
import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
-import android.content.Context;
import android.support.test.rule.ActivityTestRule;
-import android.view.View;
-import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
@@ -54,8 +51,6 @@
import org.junit.Test;
import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* Test case for an activity containing non-TextField views.
@@ -79,7 +74,7 @@
}
@Test
- public void testAutoFill() throws Exception {
+ public void testAutofill() throws Exception {
// Set service.
enableService();
@@ -103,11 +98,12 @@
assertTextIsSanitized(fillRequest.structure, ID_CC_EXPIRATION);
assertThat(ccExpirationNode.getClassName()).isEqualTo(Spinner.class.getName());
assertThat(ccExpirationNode.getAutofillType()).isEqualTo(AUTOFILL_TYPE_LIST);
- final String[] options = ccExpirationNode.getAutofillOptions();
+ final CharSequence[] options = ccExpirationNode.getAutofillOptions();
assertWithMessage("ccExpirationNode.getAutoFillOptions()").that(options).isNotNull();
assertWithMessage("Wrong auto-fill options for spinner").that(options).asList()
.containsExactly(
- getContext().getResources().getStringArray(R.array.cc_expiration_values));
+ getContext().getResources().getStringArray(R.array.cc_expiration_values))
+ .inOrder();
// Auto-fill it.
sUiBot.selectDataset("ACME CC");
@@ -117,7 +113,7 @@
}
@Test
- public void testAutoFillDynamicAdapter() throws Exception {
+ public void testAutofillDynamicAdapter() throws Exception {
// Set activity.
mActivity.onCcExpiration((v) -> v.setAdapter(new ArrayAdapter<String>(getContext(),
android.R.layout.simple_spinner_item,
@@ -146,10 +142,8 @@
assertTextIsSanitized(fillRequest.structure, ID_CC_EXPIRATION);
assertThat(ccExpirationNode.getClassName()).isEqualTo(Spinner.class.getName());
assertThat(ccExpirationNode.getAutofillType()).isEqualTo(AUTOFILL_TYPE_LIST);
- final String[] options = ccExpirationNode.getAutofillOptions();
- assertWithMessage("ccExpirationNode.getAutoFillOptions()").that(options).isNotNull();
- assertWithMessage("Wrong auto-fill options for spinner").that(options).asList()
- .containsExactly("YESTERDAY", "TODAY", "TOMORROW", "NEVER");
+ final CharSequence[] options = ccExpirationNode.getAutofillOptions();
+ assertWithMessage("ccExpirationNode.getAutoFillOptions()").that(options).isNull();
// Auto-fill it.
sUiBot.selectDataset("ACME CC");
@@ -161,26 +155,25 @@
// TODO(b/33197203): this should be a pure unit test exercising onProvideAutofillStructure(),
// but that would require creating a custom ViewStructure.
@Test
- public void testAutoFillDynamicAdapterWithNullItems() throws Exception {
- // Set activity.
- final MyAdapter adapter = new MyAdapter(getContext(),
- android.R.layout.simple_spinner_item,
- Arrays.asList("YESTERDAY", null, "TOMORROW", "NEVER"));
- mActivity.onCcExpiration((v) -> v.setAdapter(adapter));
-
+ public void testGetAutofillOptionsSorted() throws Exception {
// Set service.
enableService();
+ // Set activity.
+ mActivity.onCcExpirationAdapter((adapter) -> adapter.sort((a, b) -> {
+ return ((String) a).compareTo((String) b);
+ }));
+
// Set expectations.
- final int autoFilledIndex = 2; // NEVER
sReplier.addResponse(new CannedDataset.Builder()
.setPresentation(createPresentation("ACME CC"))
.setField(ID_CC_NUMBER, "4815162342")
- .setField(ID_CC_EXPIRATION, autoFilledIndex)
+ .setField(ID_CC_EXPIRATION, INDEX_CC_EXPIRATION_NEVER)
.setField(ID_ADDRESS, 1)
.setField(ID_SAVE_CC, true)
.build());
- mActivity.expectAutoFill("4815162342", autoFilledIndex, R.id.work_address, true);
+ mActivity.expectAutoFill("4815162342", INDEX_CC_EXPIRATION_NEVER, R.id.work_address,
+ true);
// Trigger auto-fill.
mActivity.onCcNumber((v) -> v.requestFocus());
@@ -191,25 +184,20 @@
assertTextIsSanitized(fillRequest.structure, ID_CC_EXPIRATION);
assertThat(ccExpirationNode.getClassName()).isEqualTo(Spinner.class.getName());
assertThat(ccExpirationNode.getAutofillType()).isEqualTo(AUTOFILL_TYPE_LIST);
- final String[] options = ccExpirationNode.getAutofillOptions();
- assertWithMessage("ccExpirationNode.getAutoFillOptions()").that(options).isNotNull();
+ final CharSequence[] options = ccExpirationNode.getAutofillOptions();
assertWithMessage("Wrong auto-fill options for spinner").that(options).asList()
- .containsExactly("YESTERDAY", "TOMORROW", "NEVER");
+ .containsExactly("never", "today", "tomorrow", "yesterday").inOrder();
// Auto-fill it.
sUiBot.selectDataset("ACME CC");
// Check the results.
mActivity.assertAutoFilled();
-
- // Make sure proper index was set.
- final AtomicInteger selected = new AtomicInteger();
- mActivity.onCcExpiration((v) -> selected.set(v.getSelectedItemPosition()));
- assertThat(selected.get()).isEqualTo(autoFilledIndex);
}
@Test
public void testSanitization() throws Exception {
+ // Set service.
enableService();
// Set expectations.
@@ -254,37 +242,4 @@
assertToggleValue(findNodeByResourceId(saveRequest.structure, ID_WORK_ADDRESS), true);
assertToggleValue(findNodeByResourceId(saveRequest.structure, ID_SAVE_CC), false);
}
-
- /**
- * Custom adapter used to change values after Spinner was rendered.
- */
- static class MyAdapter extends ArrayAdapter<String> {
-
- private final List<String> mList;
-
- public MyAdapter(Context context, int resource, List<String> objects) {
- super(context, resource, objects);
- mList = objects;
- }
-
- void setItem(int position, String value) {
- mList.set(position, value);
- }
-
- @Override
- public String getItem(int position) {
- return mList.get(position);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- // Hack: always return non-null item, otherwise Spinner.measure() will crash.
- for (int i = 0; i < mList.size(); i++) {
- if (mList.get(i) != null) {
- return super.getView(i, convertView, parent);
- }
- }
- return null;
- }
- }
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 635af0c..d22a5d0 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -31,6 +31,10 @@
import static android.autofillservice.cts.LoginActivity.AUTHENTICATION_MESSAGE;
import static android.autofillservice.cts.LoginActivity.ID_USERNAME_CONTAINER;
import static android.autofillservice.cts.LoginActivity.getWelcomeMessage;
+import static android.service.autofill.FillEventHistory.Event.TYPE_AUTHENTICATION_SELECTED;
+import static android.service.autofill.FillEventHistory.Event.TYPE_DATASET_AUTHENTICATION_SELECTED;
+import static android.service.autofill.FillEventHistory.Event.TYPE_DATASET_SELECTED;
+import static android.service.autofill.FillEventHistory.Event.TYPE_SAVE_SHOWN;
import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_ADDRESS;
import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD;
import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS;
@@ -56,6 +60,7 @@
import android.content.IntentFilter;
import android.content.IntentSender;
import android.os.Bundle;
+import android.service.autofill.FillEventHistory;
import android.support.test.rule.ActivityTestRule;
import android.support.test.uiautomator.UiObject2;
import android.view.View;
@@ -1500,4 +1505,185 @@
// The session should be gone
assertNoDanglingSessions();
}
+
+ @Test
+ public void checkFillSelectionAfterSelectingDatasetAuthentication() throws Exception {
+ enableService();
+
+ // Set up FillResponse with dataset authentication
+ Bundle clientState = new Bundle();
+ clientState.putCharSequence("clientStateKey", "clientStateValue");
+
+ // Prepare the authenticated response
+ AuthenticationActivity.setDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .setPresentation(createPresentation("Dataset"))
+ .build());
+
+ IntentSender authentication = PendingIntent.getActivity(getContext(), 0,
+ new Intent(getContext(), AuthenticationActivity.class), 0).getIntentSender();
+
+ sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "username")
+ .setId("name")
+ .setPresentation(createPresentation("authentication"))
+ .setAuthentication(authentication)
+ .build()).setExtras(clientState).build());
+
+ // Trigger autofill.
+ mActivity.onUsername(View::requestFocus);
+
+ // Authenticate
+ sUiBot.selectDataset("authentication");
+ sReplier.getNextFillRequest();
+
+ eventually(() -> {
+ // Verify fill selection
+ FillEventHistory selection =
+ InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+ assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+ "clientStateValue");
+
+ assertThat(selection.getEvents().size()).isEqualTo(1);
+ FillEventHistory.Event event = selection.getEvents().get(0);
+ assertThat(event.getType()).isEqualTo(TYPE_DATASET_AUTHENTICATION_SELECTED);
+ assertThat(event.getDatasetId()).isEqualTo("name");
+ });
+ }
+
+ @Test
+ public void checkFillSelectionAfterSelectingAuthentication() throws Exception {
+ enableService();
+
+ // Set up FillResponse with response wide authentication
+ Bundle clientState = new Bundle();
+ clientState.putCharSequence("clientStateKey", "clientStateValue");
+
+ // Prepare the authenticated response
+ AuthenticationActivity.setResponse(new CannedFillResponse.Builder().addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "username")
+ .setId("name")
+ .setPresentation(createPresentation("dataset"))
+ .build())
+ .setExtras(clientState).build());
+
+ IntentSender authentication = PendingIntent.getActivity(getContext(), 0,
+ new Intent(getContext(), AuthenticationActivity.class), 0).getIntentSender();
+
+ sReplier.addResponse(new CannedFillResponse.Builder().setExtras(clientState)
+ .setPresentation(createPresentation("authentication"))
+ .setAuthentication(authentication)
+ .build());
+
+ // Trigger autofill.
+ mActivity.onUsername(View::requestFocus);
+
+ // Authenticate
+ sUiBot.selectDataset("authentication");
+ sReplier.getNextFillRequest();
+
+ eventually(() -> {
+ // Verify fill selection
+ FillEventHistory selection =
+ InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+ assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+ "clientStateValue");
+
+ assertThat(selection.getEvents().size()).isEqualTo(1);
+ FillEventHistory.Event event = selection.getEvents().get(0);
+ assertThat(event.getType()).isEqualTo(TYPE_AUTHENTICATION_SELECTED);
+ assertThat(event.getDatasetId()).isNull();
+ });
+ }
+
+ @Test
+ public void checkFillSelectionAfterSelectingTwoDatasets() throws Exception {
+ enableService();
+
+ // Set up first partition with an anonymous dataset
+ sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "username")
+ .setPresentation(createPresentation("dataset1"))
+ .build())
+ .build());
+
+ // Trigger autofill on username
+ mActivity.onUsername(View::requestFocus);
+ sUiBot.selectDataset("dataset1");
+ sReplier.getNextFillRequest();
+
+ eventually(() -> {
+ // Verify fill selection
+ FillEventHistory selection =
+ InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+ assertThat(selection.getClientState()).isNull();
+
+ assertThat(selection.getEvents().size()).isEqualTo(1);
+ FillEventHistory.Event event = selection.getEvents().get(0);
+ assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
+ assertThat(event.getDatasetId()).isNull();
+ });
+
+ // Set up second partition with a named dataset
+ Bundle clientState = new Bundle();
+ clientState.putCharSequence("clientStateKey", "clientStateValue");
+
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_PASSWORD, "password2")
+ .setPresentation(createPresentation("dataset2"))
+ .setId("name2")
+ .build())
+ .addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_PASSWORD, "password3")
+ .setPresentation(createPresentation("dataset3"))
+ .setId("name3")
+ .build())
+ .setExtras(clientState)
+ .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_PASSWORD).build());
+
+ // Trigger autofill on password
+ mActivity.onPassword(View::requestFocus);
+ sUiBot.selectDataset("dataset3");
+ sReplier.getNextFillRequest();
+
+ eventually(() -> {
+ // Verify fill selection
+ FillEventHistory selection =
+ InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+ assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+ "clientStateValue");
+
+ assertThat(selection.getEvents().size()).isEqualTo(1);
+ FillEventHistory.Event event = selection.getEvents().get(0);
+ assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
+ assertThat(event.getDatasetId()).isEqualTo("name3");
+ });
+
+ mActivity.onPassword((v) -> v.setText("new password"));
+ mActivity.syncRunOnUiThread(() -> mActivity.finish());
+
+ eventually(() -> {
+ // Verify fill selection
+ FillEventHistory selection =
+ InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+ assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+ "clientStateValue");
+
+ assertThat(selection.getEvents().size()).isEqualTo(2);
+ FillEventHistory.Event event1 = selection.getEvents().get(0);
+ assertThat(event1.getType()).isEqualTo(TYPE_DATASET_SELECTED);
+ assertThat(event1.getDatasetId()).isEqualTo("name3");
+
+ FillEventHistory.Event event2 = selection.getEvents().get(1);
+ assertThat(event2.getType()).isEqualTo(TYPE_SAVE_SHOWN);
+ assertThat(event2.getDatasetId()).isNull();
+ });
+ }
}
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 655621c..e4ca5af 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -296,12 +296,5 @@
"android.telecom.cts.WiredHeadsetTest"
],
bug: 26149528
-},
-{
- desciption: "Seems to be failing on X86, flaky on arm. Root cause to be investigated",
- names: [
- "android.webkit.cts.WebViewClientTest#testOnRenderProcessGone"
- ],
- bug: 37281280
}
]
diff --git a/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java b/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
index f234155..df02750 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
@@ -28,14 +28,13 @@
import android.app.FragmentController;
import android.app.FragmentManager;
import android.app.FragmentManagerNonConfig;
-import android.app.Instrumentation;
import android.os.Parcelable;
-import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.util.Pair;
import android.view.View;
+import android.view.animation.TranslateAnimation;
import org.junit.Before;
import org.junit.Rule;
@@ -102,8 +101,9 @@
}
// Ensure that showing and popping a Fragment uses the enter and popExit animators
+ // This tests optimized transactions
@Test
- public void showAnimators() throws Throwable {
+ public void showAnimatorsOptimized() throws Throwable {
final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
// One fragment with a view
@@ -111,6 +111,10 @@
fm.beginTransaction().add(R.id.fragmentContainer, fragment).hide(fragment).commit();
FragmentTestUtil.waitForExecution(mActivityRule);
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(View.GONE, fragment.getView().getVisibility());
+ });
+
fm.beginTransaction()
.setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
.show(fragment)
@@ -118,7 +122,51 @@
.commit();
FragmentTestUtil.waitForExecution(mActivityRule);
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+ });
assertEnterPopExit(fragment);
+
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(View.GONE, fragment.getView().getVisibility());
+ });
+ }
+
+ // Ensure that showing and popping a Fragment uses the enter and popExit animators
+ // This tests unoptimized transactions
+ @Test
+ public void showAnimatorsUnoptimized() throws Throwable {
+ final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+ // One fragment with a view
+ final AnimatorFragment fragment = new AnimatorFragment();
+ fm.beginTransaction()
+ .add(R.id.fragmentContainer, fragment)
+ .hide(fragment)
+ .setAllowOptimization(false)
+ .commit();
+ FragmentTestUtil.waitForExecution(mActivityRule);
+
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(View.GONE, fragment.getView().getVisibility());
+ });
+
+ fm.beginTransaction()
+ .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+ .show(fragment)
+ .setAllowOptimization(false)
+ .addToBackStack(null)
+ .commit();
+ FragmentTestUtil.waitForExecution(mActivityRule);
+
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+ });
+ assertEnterPopExit(fragment);
+
+ mActivityRule.runOnUiThread(() -> {
+ assertEquals(View.GONE, fragment.getView().getVisibility());
+ });
}
// Ensure that hiding and popping a Fragment uses the exit and popEnter animators
@@ -388,6 +436,36 @@
assertNotNull(fragment1restored.getView());
}
+ // When an animation is running on a Fragment's View, the view shouldn't be
+ // prevented from being removed. There's no way to directly test this, so we have to
+ // test to see if the animation is still running.
+ @Test
+ public void clearAnimations() throws Throwable {
+ final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+ final StrictViewFragment fragment1 = new StrictViewFragment();
+ fm.beginTransaction()
+ .add(R.id.fragmentContainer, fragment1)
+ .addToBackStack(null)
+ .commit();
+ FragmentTestUtil.waitForExecution(mActivityRule);
+
+ final View fragmentView = fragment1.getView();
+
+ final TranslateAnimation xAnimation = new TranslateAnimation(0, 1000, 0, 0);
+ xAnimation.setDuration(10000);
+ mActivityRule.runOnUiThread(() -> {
+ fragmentView.startAnimation(xAnimation);
+ assertEquals(xAnimation, fragmentView.getAnimation());
+ });
+
+ FragmentTestUtil.waitForExecution(mActivityRule);
+ FragmentTestUtil.popBackStackImmediate(mActivityRule);
+ mActivityRule.runOnUiThread(() -> {
+ assertNull(fragmentView.getAnimation());
+ });
+ }
+
private void assertEnterPopExit(AnimatorFragment fragment) throws Throwable {
assertFragmentAnimation(fragment, 1, true, ENTER);
diff --git a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
index ebda7a2..abf7fd8 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
@@ -870,6 +870,45 @@
});
}
+ /**
+ * When the FragmentManager state changes, the pending transactions should execute.
+ */
+ @Test
+ public void runTransactionsOnChange() throws Throwable {
+ mActivityRule.runOnUiThread(() -> {
+ FragmentController fc = FragmentTestUtil.createController(mActivityRule);
+ FragmentTestUtil.resume(mActivityRule, fc, null);
+ FragmentManager fm = fc.getFragmentManager();
+
+ RemoveHelloInOnResume fragment1 = new RemoveHelloInOnResume();
+ StrictFragment fragment2 = new StrictFragment();
+ fm.beginTransaction()
+ .add(fragment1, "1")
+ .setAllowOptimization(false)
+ .commit();
+ fm.beginTransaction()
+ .add(fragment2, "Hello")
+ .setAllowOptimization(false)
+ .commit();
+ fm.executePendingTransactions();
+
+ assertEquals(2, fm.getFragments().size());
+ assertTrue(fm.getFragments().contains(fragment1));
+ assertTrue(fm.getFragments().contains(fragment2));
+
+ Pair<Parcelable, FragmentManagerNonConfig> savedState =
+ FragmentTestUtil.destroy(mActivityRule, fc);
+ fc = FragmentTestUtil.createController(mActivityRule);
+ FragmentTestUtil.resume(mActivityRule, fc, savedState);
+ fm = fc.getFragmentManager();
+
+ assertEquals(1, fm.getFragments().size());
+ for (Fragment fragment : fm.getFragments()) {
+ assertTrue(fragment instanceof RemoveHelloInOnResume);
+ }
+ });
+ }
+
private void executePendingTransactions(final FragmentManager fm) throws Throwable {
mActivityRule.runOnUiThread(new Runnable() {
@Override
@@ -1065,4 +1104,15 @@
return mValue;
}
}
+
+ public static class RemoveHelloInOnResume extends Fragment {
+ @Override
+ public void onResume() {
+ super.onResume();
+ Fragment fragment = getFragmentManager().findFragmentByTag("Hello");
+ if (fragment != null) {
+ getFragmentManager().beginTransaction().remove(fragment).commit();
+ }
+ }
+ }
}
diff --git a/tests/fragment/src/android/fragment/cts/FragmentTransactionTest.java b/tests/fragment/src/android/fragment/cts/FragmentTransactionTest.java
index aec30c1..7deea1b 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentTransactionTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentTransactionTest.java
@@ -20,6 +20,10 @@
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
@@ -354,6 +358,51 @@
}
}
+ @Test
+ public void testGetLayoutInflater() throws Throwable {
+ mActivityRule.runOnUiThread(() -> {
+ final OnGetLayoutInflaterFragment fragment1 = new OnGetLayoutInflaterFragment();
+ assertEquals(0, fragment1.onGetLayoutInflaterCalls);
+ mActivity.getFragmentManager().beginTransaction()
+ .add(android.R.id.content, fragment1)
+ .addToBackStack(null)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+ assertEquals(1, fragment1.onGetLayoutInflaterCalls);
+ assertEquals(fragment1.layoutInflater, fragment1.getLayoutInflater());
+ // getLayoutInflater() didn't force onGetLayoutInflater()
+ assertEquals(1, fragment1.onGetLayoutInflaterCalls);
+
+ LayoutInflater layoutInflater = fragment1.layoutInflater;
+ // Replacing fragment1 won't detach it, so the value won't be cleared
+ final OnGetLayoutInflaterFragment fragment2 = new OnGetLayoutInflaterFragment();
+ mActivity.getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, fragment2)
+ .addToBackStack(null)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+
+ assertSame(layoutInflater, fragment1.getLayoutInflater());
+ assertEquals(1, fragment1.onGetLayoutInflaterCalls);
+
+ // Popping it should cause onCreateView again, so a new LayoutInflater...
+ mActivity.getFragmentManager().popBackStackImmediate();
+ assertNotSame(layoutInflater, fragment1.getLayoutInflater());
+ assertEquals(2, fragment1.onGetLayoutInflaterCalls);
+ layoutInflater = fragment1.layoutInflater;
+ assertSame(layoutInflater, fragment1.getLayoutInflater());
+
+ // Popping it should detach it, clearing the cached value again
+ mActivity.getFragmentManager().popBackStackImmediate();
+
+ // once it is detached, the getLayoutInflater() will default to throw
+ // an exception, but we've made it return null instead.
+ assertEquals(2, fragment1.onGetLayoutInflaterCalls);
+ assertNull(fragment1.getLayoutInflater());
+ assertEquals(3, fragment1.onGetLayoutInflaterCalls);
+ });
+ }
+
private void getFragmentsUntilSize(int expectedSize) {
final long endTime = SystemClock.uptimeMillis() + 3000;
@@ -377,4 +426,26 @@
return inflater.inflate(R.layout.text_a, container, false);
}
}
+
+ public static class OnGetLayoutInflaterFragment extends Fragment {
+ public int onGetLayoutInflaterCalls = 0;
+ public LayoutInflater layoutInflater;
+
+ @Override
+ public LayoutInflater onGetLayoutInflater(Bundle savedInstanceState) {
+ onGetLayoutInflaterCalls++;
+ try {
+ layoutInflater = super.onGetLayoutInflater(savedInstanceState);
+ } catch (Exception e) {
+ return null;
+ }
+ return layoutInflater;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.text_a, container, false);
+ }
+ }
}
diff --git a/tests/sensor/jni/android_hardware_cts_SensorNativeTest.cpp b/tests/sensor/jni/android_hardware_cts_SensorNativeTest.cpp
index 40a5ff7..4c8b323 100644
--- a/tests/sensor/jni/android_hardware_cts_SensorNativeTest.cpp
+++ b/tests/sensor/jni/android_hardware_cts_SensorNativeTest.cpp
@@ -54,7 +54,7 @@
std::vector<int32_t> rates = {
ASENSOR_DIRECT_RATE_NORMAL, ASENSOR_DIRECT_RATE_FAST, ASENSOR_DIRECT_RATE_VERY_FAST};
std::vector<int32_t> channelTypes =
- {ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY, ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY};
+ {ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY, ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER};
for (auto s : sensorTypes) {
for (auto c : channelTypes) {
for (auto r : rates) {
diff --git a/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java b/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
index a017b6c..747a8bd 100644
--- a/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
+++ b/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
@@ -174,6 +174,38 @@
}
}
+ public void testGetAppWidgetIdsForHost() throws Exception {
+ if (!hasAppWidgets()) {
+ return;
+ }
+ AppWidgetHost host1 = new AppWidgetHost(getInstrumentation().getTargetContext(), 1);
+ AppWidgetHost host2 = new AppWidgetHost(getInstrumentation().getTargetContext(), 2);
+
+ host1.deleteHost();
+ host2.deleteHost();
+
+ assertTrue(Arrays.equals(host1.getAppWidgetIds(), new int[]{}));
+ assertTrue(Arrays.equals(host2.getAppWidgetIds(), new int[]{}));
+
+ int id1 = host1.allocateAppWidgetId();
+ assertTrue(Arrays.equals(host1.getAppWidgetIds(), new int[]{id1}));
+ assertTrue(Arrays.equals(host2.getAppWidgetIds(), new int[]{}));
+
+ int id2 = host1.allocateAppWidgetId();
+ assertTrue(Arrays.equals(host1.getAppWidgetIds(), new int[]{id1, id2}));
+ assertTrue(Arrays.equals(host2.getAppWidgetIds(), new int[]{}));
+
+ int id3 = host2.allocateAppWidgetId();
+ assertTrue(Arrays.equals(host1.getAppWidgetIds(), new int[]{id1, id2}));
+ assertTrue(Arrays.equals(host2.getAppWidgetIds(), new int[]{id3}));
+
+ host1.deleteHost();
+ assertTrue(Arrays.equals(host1.getAppWidgetIds(), new int[]{}));
+ assertTrue(Arrays.equals(host2.getAppWidgetIds(), new int[]{id3}));
+
+ host2.deleteHost();
+ }
+
public void testAppWidgetProviderCallbacks() throws Exception {
if (!hasAppWidgets()) {
return;
@@ -380,7 +412,7 @@
}
}
- public void testGetAppWidgetIds() throws Exception {
+ public void testGetAppWidgetIdsForProvider() throws Exception {
if (!hasAppWidgets()) {
return;
}
diff --git a/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java
index 5137d8a..c937e2a 100644
--- a/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java
@@ -20,11 +20,11 @@
import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.graphics.drawable.BitmapDrawable;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.test.AndroidTestCase;
-import android.util.LauncherIcons;
import android.util.Printer;
import android.util.StringBuilderPrinter;
@@ -68,9 +68,15 @@
}
}
- public void testLoadIcon() {
+ private Bitmap createIconBitmap(Drawable d) {
+ int size = Math.round(100 * getContext().getResources().getDisplayMetrics().density) + 100;
+ Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ d.setBounds(0, 0, size, size);
+ d.draw(new Canvas(bitmap));
+ return bitmap;
+ }
- LauncherIcons launcherIcons = new LauncherIcons(getContext());
+ public void testLoadIcon() {
mComponentInfo = new ComponentInfo();
mComponentInfo.applicationInfo = new ApplicationInfo();
@@ -83,14 +89,12 @@
d = mComponentInfo.loadIcon(pm);
assertNotNull(d);
assertNotSame(d, defaultIcon);
- WidgetTestUtils.assertEquals(launcherIcons.createIconBitmap(d),
- launcherIcons.createIconBitmap(defaultIcon));
+ WidgetTestUtils.assertEquals(createIconBitmap(d), createIconBitmap(defaultIcon));
d2 = mComponentInfo.loadIcon(pm);
assertNotNull(d2);
assertNotSame(d, d2);
- WidgetTestUtils.assertEquals(launcherIcons.createIconBitmap(d),
- launcherIcons.createIconBitmap(d2));
+ WidgetTestUtils.assertEquals(createIconBitmap(d), createIconBitmap(d2));
try {
mComponentInfo.loadIcon(null);
diff --git a/tests/tests/dpi/AndroidManifest.xml b/tests/tests/dpi/AndroidManifest.xml
index 8b02670..118050e 100644
--- a/tests/tests/dpi/AndroidManifest.xml
+++ b/tests/tests/dpi/AndroidManifest.xml
@@ -18,9 +18,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.dpi.cts">
- <uses-sdk
- android:minSdkVersion="23"
- android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
index 16a202e..4721afb 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
+++ b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
@@ -81,6 +81,13 @@
return false;
}
+static bool wrong_arch(const std::string& err) {
+ // https://issuetracker.google.com/37428428
+ // It's okay to not be able to load a library because it's for another
+ // architecture (typically on an x86 device, when we come across an arm library).
+ return err.find("unexpected e_machine: ") != std::string::npos;
+}
+
static bool check_lib(const std::string& path,
const std::string& library_path,
const std::unordered_set<std::string>& libraries,
@@ -107,7 +114,7 @@
} else { // (handle == nullptr && !shouldBeAccessible(path))
// Check the error message
std::string err = dlerror();
- if (!already_loaded(path, err)) {
+ if (!already_loaded(path, err) && !wrong_arch(err)) {
errors->push_back("unexpected dlerror: " + err);
return false;
}
diff --git a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
index 1a3a2f0..891fa11 100644
--- a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
+++ b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
@@ -181,9 +181,9 @@
int state = measurement.getState();
softAssert.assertTrue("state: Satellite code sync state",
timeInNs,
- "X > 0",
+ "X >= 0",
String.valueOf(state),
- state >=0);
+ state >= 0);
// Check received_gps_tow_uncertainty_ns
softAssert.assertTrueAsWarning("received_gps_tow_uncertainty_ns:" +
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java b/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
index 07f63da..2bf24b6 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.media.session.MediaController;
import android.media.session.MediaSession;
@@ -102,6 +103,13 @@
}
public void testSetOnVolumeKeyLongPressListener() throws Exception {
+ Context context = getInstrumentation().getTargetContext();
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+ // Skip this test on TV platform because the PhoneWindowManager dispatches volume key
+ // events directly to the audio service to change the system volume.
+ return;
+ }
+
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionTest.java b/tests/tests/media/src/android/media/cts/MediaSessionTest.java
index 5f13a2e..58a643d 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSessionTest.java
@@ -390,6 +390,26 @@
}
}
+ /**
+ * Test {@link MediaSession#release} doesn't crash when multiple media sessions are in the app
+ * which receives the media key events.
+ * See: b/36669550
+ */
+ public void testReleaseNoCrashWithMultipleSessions() throws Exception {
+ // Start a media playback for this app to receive media key events.
+ Utils.assertMediaPlaybackStarted(getContext());
+
+ MediaSession anotherSession = new MediaSession(getContext(), TEST_SESSION_TAG);
+ mSession.release();
+ anotherSession.release();
+
+ // Try release with the different order.
+ mSession = new MediaSession(getContext(), TEST_SESSION_TAG);
+ anotherSession = new MediaSession(getContext(), TEST_SESSION_TAG);
+ anotherSession.release();
+ mSession.release();
+ }
+
private void simulateMediaKeyInput(int keyCode) {
mAudioManager.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
mAudioManager.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio_misc.cpp b/tests/tests/nativemedia/aaudio/src/test_aaudio_misc.cpp
index a26f17a..8599d48 100644
--- a/tests/tests/nativemedia/aaudio/src/test_aaudio_misc.cpp
+++ b/tests/tests/nativemedia/aaudio/src/test_aaudio_misc.cpp
@@ -32,8 +32,6 @@
ASSERT_EQ(0, AAUDIO_FORMAT_UNSPECIFIED);
ASSERT_EQ(1, AAUDIO_FORMAT_PCM_I16);
ASSERT_EQ(2, AAUDIO_FORMAT_PCM_FLOAT);
- ASSERT_EQ(3, AAUDIO_FORMAT_PCM_I8_24);
- ASSERT_EQ(4, AAUDIO_FORMAT_PCM_I32);
ASSERT_EQ(0, AAUDIO_OK);
ASSERT_EQ(-900, AAUDIO_ERROR_BASE);
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 949e2c1..8f0de7f 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -37,6 +37,7 @@
<protected-broadcast android:name="android.intent.action.BOOT_COMPLETED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_INSTALL" />
<protected-broadcast android:name="android.intent.action.PACKAGE_ADDED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_ADDED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_REPLACED" />
<protected-broadcast android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_REMOVED" />
@@ -284,6 +285,7 @@
<protected-broadcast android:name="android.btopp.intent.action.STOP_HANDOVER_TRANSFER" />
<protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND" />
<protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND_MULTIPLE" />
+ <protected-broadcast android:name="com.android.nfc.handover.action.CANCEL_HANDOVER_TRANSFER" />
<protected-broadcast android:name="android.intent.action.CLEAR_DNS_CACHE" />
<protected-broadcast android:name="android.intent.action.PROXY_CHANGE" />
@@ -491,7 +493,9 @@
<protected-broadcast android:name="android.intent.action.ACTION_RADIO_OFF" />
<protected-broadcast android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
+ <protected-broadcast android:name="android.accounts.action.ACCOUNT_REMOVED" />
<protected-broadcast android:name="android.accounts.action.VISIBLE_ACCOUNTS_CHANGED" />
+
<protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" />
<protected-broadcast android:name="com.android.phone.SIP_INCOMING_CALL" />
@@ -528,9 +532,14 @@
<protected-broadcast android:name="com.android.internal.autofill.action.REQUEST_AUTOFILL" />
<protected-broadcast android:name="android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED" />
<protected-broadcast android:name="com.android.server.wm.ACTION_REVOKE_SYSTEM_ALERT_WINDOW_PERMISSION" />
+ <protected-broadcast android:name="android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED" />
<protected-broadcast android:name="android.content.pm.action.SESSION_COMMITTED" />
<protected-broadcast android:name="android.os.action.USER_RESTRICTIONS_CHANGED" />
+ <protected-broadcast android:name="android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT" />
+ <protected-broadcast android:name="android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED" />
+ <protected-broadcast android:name="android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED" />
+ <protected-broadcast android:name="android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
@@ -803,7 +812,7 @@
<p>Protection level: dangerous-->
<permission android:name="android.permission.READ_PHONE_NUMBERS"
android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_readPhoneNumber"
+ android:label="@string/permlab_readPhoneNumbers"
android:description="@string/permdesc_readPhoneNumbers"
android:protectionLevel="dangerous|ephemeral" />
@@ -1299,6 +1308,13 @@
<permission android:name="android.permission.REQUEST_NETWORK_SCORES"
android:protectionLevel="signature|setup" />
+ <!-- Allows network stack services (Connectivity and Wifi) to coordinate
+ <p>Not for use by third-party or privileged applications.
+ @hide This should only be used by Connectivity and Wifi Services.
+ -->
+ <permission android:name="android.permission.NETWORK_STACK"
+ android:protectionLevel="signature" />
+
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
<!-- ======================================= -->
@@ -1654,6 +1670,21 @@
<permission android:name="android.permission.BIND_IMS_SERVICE"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an application to manage embedded subscriptions (those on a eUICC) through
+ EuiccManager APIs.
+ <p>Protection level: signature|privileged|development
+ TODO(b/35851809): Mark this as a SystemApi.
+ @hide -->
+ <permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- Must be required by an EuiccService to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ TODO(b/35851809): Mark this as a SystemApi.
+ @hide -->
+ <permission android:name="android.permission.BIND_EUICC_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- ================================== -->
<!-- Permissions for sdcard interaction -->
@@ -1861,6 +1892,11 @@
android:description="@string/permdesc_useDataInBackground"
android:protectionLevel="signature" />
+ <!-- @hide Allows an application to set display offsets for the screen.
+ This permission is not available to third party applications. -->
+ <permission android:name="android.permission.SET_DISPLAY_OFFSET"
+ android:protectionLevel="signature|privileged" />
+
<!-- ================================== -->
<!-- Permissions affecting the system wallpaper -->
<!-- ================================== -->
@@ -2521,6 +2557,13 @@
<permission android:name="android.permission.MODIFY_PARENTAL_CONTROLS"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to notify TV inputs by sending broadcasts.
+ <p>Protection level: signature|privileged
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.NOTIFY_TV_INPUTS"
+ android:protectionLevel="signature|privileged" />
+
<!-- Must be required by a {@link android.media.routing.MediaRouteService}
to ensure that only the system can interact with it.
@hide -->
@@ -3139,6 +3182,15 @@
<permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
android:protectionLevel="signature" />
+ <!-- @SystemApi Must be required by services that extend
+ {@link android.service.resolver.ResolverRankerService}, to ensure that only the system can
+ bind to them.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_RESOLVER_RANKER_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- Must be required by a {@link
android.service.notification.ConditionProviderService},
to ensure that only the system can bind to it.
@@ -3356,7 +3408,8 @@
android:documentLaunchMode="never"
android:relinquishTaskIdentity="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
- android:process=":ui">
+ android:process=":ui"
+ android:visibleToInstantApps="true">
<intent-filter>
<action android:name="android.intent.action.CHOOSER" />
<category android:name="android.intent.category.DEFAULT" />
@@ -3364,15 +3417,17 @@
</intent-filter>
</activity>
<activity android:name="com.android.internal.app.AccessibilityButtonChooserActivity"
+ android:exported="false"
android:theme="@style/Theme.DeviceDefault.Resolver"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
android:documentLaunchMode="never"
android:relinquishTaskIdentity="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
- android:process=":ui">
+ android:process=":ui"
+ android:visibleToInstantApps="true">
<intent-filter>
- <action android:name="android.intent.action.CHOOSE_ACCESSIBILITY_BUTTON" />
+ <action android:name="com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
@@ -3431,7 +3486,8 @@
android:exported="true"
android:theme="@style/Theme.DeviceDefault.Light.Dialog"
android:label="@string/choose_account_label"
- android:process=":ui">
+ android:process=":ui"
+ android:visibleToInstantApps="true">
</activity>
<activity android:name="android.accounts.ChooseTypeAndAccountActivity"
@@ -3439,14 +3495,16 @@
android:exported="true"
android:theme="@style/Theme.DeviceDefault.Light.Dialog"
android:label="@string/choose_account_label"
- android:process=":ui">
+ android:process=":ui"
+ android:visibleToInstantApps="true">
</activity>
<activity android:name="android.accounts.ChooseAccountTypeActivity"
android:excludeFromRecents="true"
android:theme="@style/Theme.DeviceDefault.Light.Dialog"
android:label="@string/choose_account_label"
- android:process=":ui">
+ android:process=":ui"
+ android:visibleToInstantApps="true">
</activity>
<activity android:name="android.accounts.CantAddAccountActivity"
@@ -3460,7 +3518,8 @@
android:excludeFromRecents="true"
android:exported="true"
android:theme="@style/Theme.DeviceDefault.Light.DialogWhenLarge"
- android:process=":ui">
+ android:process=":ui"
+ android:visibleToInstantApps="true">
</activity>
<activity android:name="android.content.SyncActivityTooManyDeletes"
@@ -3518,6 +3577,11 @@
android:process=":ui">
</activity>
+ <activity android:name="com.android.settings.notification.NotificationAccessConfirmationActivity"
+ android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert"
+ android:excludeFromRecents="true">
+ </activity>
+
<receiver android:name="com.android.server.BootReceiver"
android:systemUserOnly="true">
<intent-filter android:priority="1000">
diff --git a/tests/tests/provider/AndroidManifest.xml b/tests/tests/provider/AndroidManifest.xml
index 9a79c64..284841b 100644
--- a/tests/tests/provider/AndroidManifest.xml
+++ b/tests/tests/provider/AndroidManifest.xml
@@ -89,6 +89,10 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
+ <provider android:name="android.provider.cts.MockFontProvider"
+ android:authorities="android.provider.fonts.cts.font"
+ android:exported="false"
+ android:multiprocess="true" />
</application>
diff --git a/tests/tests/provider/assets/samplefont1.ttf b/tests/tests/provider/assets/samplefont1.ttf
new file mode 100644
index 0000000..020436a
--- /dev/null
+++ b/tests/tests/provider/assets/samplefont1.ttf
Binary files differ
diff --git a/tests/tests/provider/assets/samplefont1.ttx b/tests/tests/provider/assets/samplefont1.ttx
new file mode 100644
index 0000000..40fa268
--- /dev/null
+++ b/tests/tests/provider/assets/samplefont1.ttx
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="a"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="a" width="500" lsb="93"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="3" platEncID="10" language="0">
+ <map code="0x0061" name="a" />
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="a" xMin="0" yMin="0" xMax="0" yMax="0" />
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/tests/tests/provider/assets/samplefont2.ttf b/tests/tests/provider/assets/samplefont2.ttf
new file mode 100644
index 0000000..491540f
--- /dev/null
+++ b/tests/tests/provider/assets/samplefont2.ttf
Binary files differ
diff --git a/tests/tests/provider/assets/samplefont2.ttx b/tests/tests/provider/assets/samplefont2.ttx
new file mode 100644
index 0000000..40fa268
--- /dev/null
+++ b/tests/tests/provider/assets/samplefont2.ttx
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="a"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="a" width="500" lsb="93"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="3" platEncID="10" language="0">
+ <map code="0x0061" name="a" />
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="a" xMin="0" yMin="0" xMax="0" yMax="0" />
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/tests/tests/provider/src/android/provider/cts/FontsContractTest.java b/tests/tests/provider/src/android/provider/cts/FontsContractTest.java
new file mode 100644
index 0000000..d95f74a
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/FontsContractTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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 android.provider.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.app.Instrumentation;
+import android.content.pm.Signature;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageInfo;
+import android.content.Context;
+import android.graphics.Typeface;
+import android.graphics.fonts.FontRequest;
+import android.graphics.fonts.FontResult;
+import android.graphics.fonts.FontVariationAxis;
+import android.provider.FontsContract;
+import android.provider.FontsContract.FontFamilyResult;
+import android.provider.FontsContract.FontInfo;
+import android.provider.FontsContract.Columns;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FontsContractTest {
+ private static final String AUTHORITY = "android.provider.fonts.cts.font";
+ private static final String PACKAGE = "android.provider.cts";
+
+ private static long TIMEOUT_MILLIS = 1000;
+
+ // Signature to be used for authentication to access content provider.
+ // In this test case, the content provider and consumer live in the same package, self package's
+ // signature works.
+ private static List<List<byte[]>> SIGNATURE;
+ static {
+ final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ try {
+ PackageManager manager = context.getPackageManager();
+ PackageInfo info = manager.getPackageInfo(
+ context.getPackageName(), PackageManager.GET_SIGNATURES);
+ ArrayList<byte[]> out = new ArrayList<>();
+ for (Signature sig : info.signatures) {
+ out.add(sig.toByteArray());
+ }
+ SIGNATURE = new ArrayList<>();
+ SIGNATURE.add(out);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ public void querySingleFont() throws NameNotFoundException {
+ Context ctx = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ FontRequest request = new FontRequest(AUTHORITY, PACKAGE, "singleFontFamily", SIGNATURE);
+ FontFamilyResult result = FontsContract.fetchFonts(
+ ctx, null /* cancellation signal */, request);
+ assertNotNull(result);
+ assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
+
+ FontInfo[] fonts = result.getFonts();
+ assertEquals(1, fonts.length);
+ FontInfo font = fonts[0];
+ assertNotNull(font.getUri());
+ assertEquals(Columns.RESULT_CODE_OK, font.getResultCode());
+ // TODO: add more test cases for FontInfo members once the MockFontProvider becomes
+ // configurable.
+ assertNotNull(FontsContract.buildTypeface(ctx, null /* cancellation signal */, fonts));
+ }
+
+ @Test
+ public void queryMultipleFont() throws NameNotFoundException {
+ Context ctx = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ FontRequest request = new FontRequest(AUTHORITY, PACKAGE, "multipleFontFamily", SIGNATURE);
+ FontFamilyResult result = FontsContract.fetchFonts(
+ ctx, null /* cancellation signal */, request);
+ assertNotNull(result);
+ assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
+
+ FontInfo[] fonts = result.getFonts();
+ assertEquals(4, fonts.length);
+ for (FontInfo font: fonts) {
+ assertNotNull(font.getUri());
+ assertEquals(Columns.RESULT_CODE_OK, font.getResultCode());
+ }
+ // TODO: add more test cases for FontInfo members once the MockFontProvider becomes
+ // configuarable.
+ assertNotNull(FontsContract.buildTypeface(ctx, null /* cancellation signal */, fonts));
+ }
+
+ @Test
+ public void restrictContextRejection() throws NameNotFoundException {
+ Context ctx = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ Context restrictedContext = ctx.createPackageContext(PACKAGE, Context.CONTEXT_RESTRICTED);
+
+ FontRequest request = new FontRequest(AUTHORITY, PACKAGE, "singleFontFamily", SIGNATURE);
+
+ // Rejected if restricted context is used.
+ FontFamilyResult result = FontsContract.fetchFonts(
+ restrictedContext, null /* cancellation signal */, request);
+ assertEquals(FontFamilyResult.STATUS_REJECTED, result.getStatusCode());
+
+ // Even if you have a result, buildTypeface should fail with restricted context.
+ result = FontsContract.fetchFonts(ctx, null /* cancellation signal */, request);
+ assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
+ assertNull(FontsContract.buildTypeface(
+ restrictedContext, null /* cancellation signal */, result.getFonts()));
+ }
+
+ // TODO: Add more test case.
+}
diff --git a/tests/tests/provider/src/android/provider/cts/MockFontProvider.java b/tests/tests/provider/src/android/provider/cts/MockFontProvider.java
new file mode 100644
index 0000000..a348de2
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/MockFontProvider.java
@@ -0,0 +1,195 @@
+/*
+ * 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 android.provider.cts;
+
+import static android.provider.FontsContract.Columns;
+
+import android.content.ContentProvider;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.graphics.fonts.FontVariationAxis;
+import android.net.Uri;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.util.SparseArray;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.HashMap;
+import java.io.File;
+import java.nio.file.Files;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileNotFoundException;
+import java.nio.file.StandardCopyOption;
+
+public class MockFontProvider extends ContentProvider {
+ final static String AUTHORITY = "android.provider.fonts.cts.font";
+
+ final static String[] FONT_FILES = {
+ "samplefont1.ttf", "samplefont2.ttf",
+ };
+ private static final int SAMPLE_FONT_FILE_0_ID = 0;
+ private static final int SAMPLE_FONT_FILE_1_ID = 1;
+
+ static class Font {
+ public Font(int id, int fileId, int ttcIndex, String varSettings, int weight, int italic,
+ int resultCode) {
+ mId = id;
+ mFileId = fileId;
+ mTtcIndex = ttcIndex;
+ mVarSettings = varSettings;
+ mWeight = weight;
+ mItalic = italic;
+ mResultCode = resultCode;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ public int getTtcIndex() {
+ return mTtcIndex;
+ }
+
+ public String getVarSettings() {
+ return mVarSettings;
+ }
+
+ public int getWeight() {
+ return mWeight;
+ }
+
+ public int getItalic() {
+ return mItalic;
+ }
+
+ public int getResultCode() {
+ return mResultCode;
+ }
+
+ public int getFileId() {
+ return mFileId;
+ }
+
+ private int mId;
+ private int mFileId;
+ private int mTtcIndex;
+ private String mVarSettings;
+ private int mWeight;
+ private int mItalic;
+ private int mResultCode;
+ };
+
+ private static Map<String, Font[]> QUERY_MAP;
+ static {
+ HashMap<String, Font[]> map = new HashMap<>();
+ int id = 0;
+
+ map.put("singleFontFamily", new Font[] {
+ new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK),
+ });
+
+ map.put("multipleFontFamily", new Font[] {
+ new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK),
+ new Font(id++, SAMPLE_FONT_FILE_1_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK),
+ new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 1, Columns.RESULT_CODE_OK),
+ new Font(id++, SAMPLE_FONT_FILE_1_ID, 0, null, 700, 1, Columns.RESULT_CODE_OK),
+ });
+
+ QUERY_MAP = Collections.unmodifiableMap(map);
+ }
+
+ private static Cursor buildCursor(Font[] in) {
+ MatrixCursor cursor = new MatrixCursor(new String[] {
+ Columns._ID, Columns.TTC_INDEX, Columns.VARIATION_SETTINGS, Columns.WEIGHT,
+ Columns.ITALIC, Columns.RESULT_CODE, Columns.FILE_ID});
+ for (Font font : in) {
+ MatrixCursor.RowBuilder builder = cursor.newRow();
+ builder.add(Columns._ID, font.getId());
+ builder.add(Columns.FILE_ID, font.getFileId());
+ builder.add(Columns.TTC_INDEX, font.getTtcIndex());
+ builder.add(Columns.VARIATION_SETTINGS, font.getVarSettings());
+ builder.add(Columns.WEIGHT, font.getWeight());
+ builder.add(Columns.ITALIC, font.getItalic());
+ builder.add(Columns.RESULT_CODE, font.getResultCode());
+ }
+ return cursor;
+ }
+
+ public MockFontProvider() {
+ }
+
+ @Override
+ public ParcelFileDescriptor openFile(Uri uri, String mode) {
+ final int id = (int)ContentUris.parseId(uri);
+ final File targetFile = getCopiedFile(FONT_FILES[id]);
+ try {
+ return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public File getCopiedFile(String path) {
+ return new File(getContext().getFilesDir(), path);
+ }
+
+ @Override
+ public boolean onCreate() {
+ final AssetManager mgr = getContext().getAssets();
+ for (String path : FONT_FILES) {
+ try (InputStream is = mgr.open(path)) {
+ Files.copy(is, getCopiedFile(path).toPath(), StandardCopyOption.REPLACE_EXISTING);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ // TODO: do we have good time to remove above files from files directory?
+ return true;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return "vnd.android.cursor.dir/vnd.android.provider.cts.font";
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return buildCursor(QUERY_MAP.get(selectionArgs[0]));
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ throw new UnsupportedOperationException("insert is not supported.");
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException("delete is not supported.");
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException("update is not supported.");
+ }
+}
diff --git a/tests/tests/security/res/raw/cve_2015_3836.xmf b/tests/tests/security/res/raw/cve_2015_3836.xmf
new file mode 100644
index 0000000..b897c09
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3836.xmf
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3864_b23034759.mp4 b/tests/tests/security/res/raw/cve_2015_3864_b23034759.mp4
new file mode 100644
index 0000000..3d1b223
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3864_b23034759.mp4
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index c458ffd..1ad199d 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -148,11 +148,21 @@
}
@SecurityTest
+ public void testStagefright_cve_2015_3836() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3836);
+ }
+
+ @SecurityTest
public void testStagefright_cve_2015_3864() throws Exception {
doStagefrightTest(R.raw.cve_2015_3864);
}
@SecurityTest
+ public void testStagefright_cve_2015_3864_b23034759() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3864_b23034759);
+ }
+
+ @SecurityTest
public void testStagefright_cve_2015_6598() throws Exception {
doStagefrightTest(R.raw.cve_2015_6598);
}
@@ -525,7 +535,11 @@
closeQuietly(fd);
}
} else {
- ex.setDataSource(url);
+ try {
+ ex.setDataSource(url);
+ } catch (Exception e) {
+ // indicative of problems with our tame CTS test web server
+ }
}
int numtracks = ex.getTrackCount();
String rname = url != null ? url: resources.getResourceEntryName(rid);
@@ -681,13 +695,17 @@
AssetFileDescriptor fd = resources.openRawResourceFd(rid);
try {
retriever.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
- } catch (IllegalArgumentException e) {
+ } catch (RuntimeException e) {
// ignore
} finally {
closeQuietly(fd);
}
} else {
- retriever.setDataSource(url, new HashMap<String, String>());
+ try {
+ retriever.setDataSource(url, new HashMap<String, String>());
+ } catch (Exception e) {
+ // indicative of problems with our tame CTS test web server
+ }
}
retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
retriever.getEmbeddedPicture();
diff --git a/tests/tests/transition/src/android/transition/cts/ActivityTransitionTest.java b/tests/tests/transition/src/android/transition/cts/ActivityTransitionTest.java
index 54a567a..872820a 100644
--- a/tests/tests/transition/src/android/transition/cts/ActivityTransitionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ActivityTransitionTest.java
@@ -95,6 +95,29 @@
TargetActivity.sLastCreated = null;
}
+ // When using ActivityOptions.makeBasic(), no transitions should run
+ @Test
+ public void testMakeBasic() {
+ assertFalse(mActivity.isActivityTransitionRunning());
+ mInstrumentation.runOnMainSync(() -> {
+ Intent intent = new Intent(mActivity, TargetActivity.class);
+ ActivityOptions activityOptions =
+ ActivityOptions.makeBasic();
+ mActivity.startActivity(intent, activityOptions.toBundle());
+ });
+
+ assertFalse(mActivity.isActivityTransitionRunning());
+
+ TargetActivity targetActivity = waitForTargetActivity();
+ assertFalse(targetActivity.isActivityTransitionRunning());
+ mInstrumentation.runOnMainSync(() -> {
+ targetActivity.finish();
+ });
+
+ assertFalse(targetActivity.isActivityTransitionRunning());
+ assertFalse(mActivity.isActivityTransitionRunning());
+ }
+
// Views that are outside the visible area only during the shared element start
// should not be stripped from the transition.
@Test
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BaseRenderScriptComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BaseRenderScriptComparer.java
deleted file mode 100644
index 3f9a9f6..0000000
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BaseRenderScriptComparer.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package android.uirendering.cts.bitmapcomparers;
-
-import android.content.res.Resources;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-
-/**
- * Base class for calculators that want to implement renderscript
- */
-public abstract class BaseRenderScriptComparer extends BitmapComparer {
- private Allocation mRowInputs;
- private Allocation mRowOutputs;
- private int mHeight;
-
- public abstract boolean verifySame(int[] ideal, int[] given, int offset, int stride, int width,
- int height);
-
- /**
- * The subclasses must implement this method, which will say that the rows follow their specific
- * algorithm
- */
- public abstract boolean verifySameRowsRS(Resources resources, Allocation ideal,
- Allocation given, int offset, int stride, int width, int height,
- RenderScript renderScript, Allocation inputAllocation, Allocation outputAllocation);
-
- public boolean verifySameRS(Resources resources, Allocation ideal,
- Allocation given, int offset, int stride, int width, int height,
- RenderScript renderScript) {
- if (mRowInputs == null) {
- mHeight = height;
- mRowInputs = createInputRowIndexAllocation(renderScript);
- mRowOutputs = createOutputRowAllocation(renderScript);
- }
- return verifySameRowsRS(resources, ideal, given, offset, stride, width, height,
- renderScript, mRowInputs, mRowOutputs);
- }
-
- public boolean supportsRenderScript() {
- return true;
- }
-
- /**
- * Sums the values in the output Allocation
- */
- public float sum1DFloatAllocation(Allocation rowOutputs) {
- //Get the values returned from the function
- float[] returnValue = new float[mHeight];
- rowOutputs.copyTo(returnValue);
- float sum = 0;
- //If any row had any different pixels, then it fails
- for (int i = 0; i < mHeight; i++) {
- sum += returnValue[i];
- }
- return sum;
- }
-
- /**
- * Creates an allocation where the values in it are the indices of each row
- */
- private Allocation createInputRowIndexAllocation(RenderScript renderScript) {
- //Create an array with the index of each row
- int[] inputIndices = new int[mHeight];
- for (int i = 0; i < mHeight; i++) {
- inputIndices[i] = i;
- }
- //Create the allocation from that given array
- Allocation inputAllocation = Allocation.createSized(renderScript, Element.I32(renderScript),
- inputIndices.length, Allocation.USAGE_SCRIPT);
- inputAllocation.copyFrom(inputIndices);
- return inputAllocation;
- }
-
- private Allocation createOutputRowAllocation(RenderScript renderScript) {
- return Allocation.createSized(renderScript, Element.F32(renderScript), mHeight,
- Allocation.USAGE_SCRIPT);
- }
-}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BitmapComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BitmapComparer.java
index 8d74aa5..c995e43 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BitmapComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BitmapComparer.java
@@ -15,10 +15,6 @@
*/
package android.uirendering.cts.bitmapcomparers;
-import android.content.res.Resources;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
-
/**
* This abstract class can be used by the tester to implement their own comparison methods
*/
@@ -35,28 +31,9 @@
int height);
/**
- * Compare the two bitmaps using RenderScript, if the comparer
- * {@link supportsRenderScript() supports it}. If it does not, this method will throw an
- * UnsupportedOperationException
- */
- public boolean verifySameRS(Resources resources, Allocation ideal,
- Allocation given, int offset, int stride, int width, int height,
- RenderScript renderScript) {
- throw new UnsupportedOperationException("Renderscript not supported for this calculator");
- }
-
- /**
* This calculates the position in an array that would represent a bitmap given the parameters.
*/
protected static int indexFromXAndY(int x, int y, int stride, int offset) {
return x + (y * stride) + offset;
}
-
- /**
- * Returns whether the verifySameRS() is implemented, and may be used on a RenderScript enabled
- * system
- */
- public boolean supportsRenderScript() {
- return false;
- }
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
index 562b730..99d1f71 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
@@ -15,20 +15,13 @@
*/
package android.uirendering.cts.bitmapcomparers;
-import android.uirendering.cts.R;
-import android.uirendering.cts.ScriptC_ExactComparer;
-
-import android.content.res.Resources;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
import android.util.Log;
/**
* This class does an exact comparison of the pixels in a bitmap.
*/
-public class ExactComparer extends BaseRenderScriptComparer {
+public class ExactComparer extends BitmapComparer {
private static final String TAG = "ExactComparer";
- private ScriptC_ExactComparer mScript;
/**
* This method does an exact 1 to 1 comparison of the two bitmaps
@@ -54,27 +47,4 @@
return (count == 0);
}
-
- @Override
- public boolean verifySameRowsRS(Resources resources, Allocation ideal,
- Allocation given, int offset, int stride, int width, int height,
- RenderScript renderScript, Allocation inputAllocation, Allocation outputAllocation) {
- if (mScript == null) {
- mScript = new ScriptC_ExactComparer(renderScript);
- }
- mScript.set_WIDTH(width);
- mScript.set_OFFSET(offset);
-
- //Set the bitmap allocations
- mScript.set_ideal(ideal);
- mScript.set_given(given);
-
- //Call the renderscript function on each row
- mScript.forEach_exactCompare(inputAllocation, outputAllocation);
-
- float val = sum1DFloatAllocation(outputAllocation);
- Log.d(TAG, "Number of different pixels RS : " + val);
-
- return val == 0;
- }
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.rs
deleted file mode 100644
index 6425c17..0000000
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(android.uirendering.cts)
-
-int WIDTH;
-int OFFSET;
-
-rs_allocation ideal;
-rs_allocation given;
-
-// This method does a simple comparison of all the values in the given and ideal allocations.
-// If any of the pixels are off, then the test will fail.
-void exactCompare(const int32_t *v_in, float *v_out){
- int y = v_in[0];
- v_out[0] = 0;
-
- for(int i = 0 ; i < WIDTH ; i ++){
- uchar4 idealPixel = rsGetElementAt_uchar4(ideal, i + OFFSET, y);
- uchar4 givenPixel = rsGetElementAt_uchar4(given, i + OFFSET, y);
- uchar4 diff = idealPixel - givenPixel;
- int totalDiff = diff.x + diff.y + diff.z;
- if(totalDiff != 0){
- v_out[0] ++;
- }
- }
-}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java
index 4a25695..e65ff2d 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java
@@ -15,12 +15,7 @@
*/
package android.uirendering.cts.bitmapcomparers;
-import android.uirendering.cts.ScriptC_MSSIMComparer;
-
-import android.content.res.Resources;
import android.graphics.Color;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
import android.util.Log;
/**
@@ -29,7 +24,7 @@
*
* https://ece.uwaterloo.ca/~z70wang/publications/ssim.pdf
*/
-public class MSSIMComparer extends BaseRenderScriptComparer {
+public class MSSIMComparer extends BitmapComparer {
// These values were taken from the publication
public static final String TAG_NAME = "MSSIM";
public static final double CONSTANT_L = 254;
@@ -40,7 +35,6 @@
public static final int WINDOW_SIZE = 10;
private double mThreshold;
- private ScriptC_MSSIMComparer mScript;
public MSSIMComparer(double threshold) {
mThreshold = threshold;
@@ -82,31 +76,6 @@
return (SSIMTotal >= mThreshold);
}
- @Override
- public boolean verifySameRowsRS(Resources resources, Allocation ideal,
- Allocation given, int offset, int stride, int width, int height,
- RenderScript renderScript, Allocation inputAllocation, Allocation outputAllocation) {
- if (mScript == null) {
- mScript = new ScriptC_MSSIMComparer(renderScript);
- }
- mScript.set_WIDTH(width);
- mScript.set_HEIGHT(height);
-
- //Set the bitmap allocations
- mScript.set_ideal(ideal);
- mScript.set_given(given);
-
- //Call the renderscript function on each row
- mScript.forEach_calcSSIM(inputAllocation, outputAllocation);
-
- float MSSIM = sum1DFloatAllocation(outputAllocation);
- MSSIM /= height;
-
- Log.d(TAG_NAME, "MSSIM RS : " + MSSIM);
-
- return (MSSIM >= mThreshold);
- }
-
private boolean isWindowWhite(int[] colors, int start, int stride) {
for (int y = 0 ; y < WINDOW_SIZE ; y++) {
for (int x = 0 ; x < WINDOW_SIZE ; x++) {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.rs
deleted file mode 100644
index b0e86b8..0000000
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(android.uirendering.cts)
-
-int WIDTH;
-int HEIGHT;
-
-rs_allocation ideal;
-rs_allocation given;
-
-static float getPixelWeight(uchar4 pixel) {
- const float MAX_VALUE_COLOR = 255;
- const float RED_WEIGHT = 0.21f / MAX_VALUE_COLOR;
- const float GREEN_WEIGHT = 0.72f / MAX_VALUE_COLOR;
- const float BLUE_WEIGHT = 0.07f / MAX_VALUE_COLOR;
- return (pixel.r * RED_WEIGHT) + (pixel.g * GREEN_WEIGHT) + (pixel.b * BLUE_WEIGHT);
-}
-
-// Calculates SSIM of a row of pixels
-void calcSSIM(const int32_t *v_in, float *v_out) {
- // TODO Test values for these constants
- const float C1 = 0.0000064516;
- const float C2 = 0.0000580644;
-
- int y = v_in[0];
- v_out[0] = 0;
-
- float meanIdeal = 0;
- float meanGiven = 0;
-
- for (int i = 0 ; i < WIDTH ; i++) {
- uchar4 idealPixel = rsGetElementAt_uchar4(ideal, i, y);
- uchar4 givenPixel = rsGetElementAt_uchar4(given, i, y);
- meanIdeal += getPixelWeight(idealPixel);
- meanGiven += getPixelWeight(givenPixel);
- }
-
- meanIdeal /= WIDTH;
- meanGiven /= WIDTH;
-
- float varIdeal = 0;
- float varGiven = 0;
- float varBoth = 0;
-
- for (int i = 0 ; i < WIDTH ; i++) {
- uchar4 idealPixel = rsGetElementAt_uchar4(ideal, i, y);
- uchar4 givenPixel = rsGetElementAt_uchar4(given, i, y);
- float idealWeight = getPixelWeight(idealPixel);
- float givenWeight = getPixelWeight(givenPixel);
- idealWeight -= meanIdeal;
- givenWeight -= meanGiven;
- varIdeal += idealWeight * idealWeight;
- varGiven += givenWeight * givenWeight;
- varBoth += idealWeight * givenWeight;
- }
-
- varIdeal /= WIDTH - 1;
- varGiven /= WIDTH - 1;
- varBoth /= WIDTH - 1;
-
- float SSIM = ((2 * meanIdeal * meanGiven) + C1) * ((2 * varBoth) + C2);
- float denom = ((meanIdeal * meanIdeal) + (meanGiven * meanGiven) + C1)
- * (varIdeal + varGiven + C2);
- SSIM /= denom;
-
- v_out[0] = SSIM;
-}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java
index 5cc896b..2b6ba0c 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java
@@ -15,21 +15,14 @@
*/
package android.uirendering.cts.bitmapcomparers;
-import android.uirendering.cts.R;
-import android.uirendering.cts.ScriptC_MeanSquaredComparer;
-
-import android.content.res.Resources;
import android.graphics.Color;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
import android.util.Log;
/**
* Finds the MSE using two images.
*/
-public class MeanSquaredComparer extends BaseRenderScriptComparer {
+public class MeanSquaredComparer extends BitmapComparer {
private static final String TAG = "MeanSquared";
- private ScriptC_MeanSquaredComparer mScript;
private float mErrorPerPixel;
/**
@@ -48,30 +41,6 @@
return (totalError < (mErrorPerPixel));
}
- @Override
- public boolean verifySameRowsRS(Resources resources, Allocation ideal,
- Allocation given, int offset, int stride, int width, int height,
- RenderScript renderScript, Allocation inputAllocation, Allocation outputAllocation) {
- if (mScript == null) {
- mScript = new ScriptC_MeanSquaredComparer(renderScript);
- }
- mScript.set_WIDTH(width);
-
- //Set the bitmap allocations
- mScript.set_ideal(ideal);
- mScript.set_given(given);
-
- //Call the renderscript function on each row
- mScript.forEach_calcMSE(inputAllocation, outputAllocation);
-
- float error = sum1DFloatAllocation(outputAllocation);
- error /= (height * width);
-
- Log.d(TAG, "Error RS : " + error);
-
- return (error < mErrorPerPixel);
- }
-
/**
* Gets the Mean Squared Error between two data sets.
*/
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.rs
deleted file mode 100644
index 3b37609..0000000
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(android.uirendering.cts)
-
-int REGION_SIZE;
-int WIDTH;
-
-rs_allocation ideal;
-rs_allocation given;
-
-// This method does a threshold comparison of the values
-void calcMSE(const int32_t *v_in, float *v_out){
- int y = v_in[0];
- v_out[0] = 0.0f;
- for (int x = 0 ; x < WIDTH ; x++) {
- float4 idealFloats = rsUnpackColor8888(rsGetElementAt_uchar4(ideal, x, y));
- float4 givenFloats = rsUnpackColor8888(rsGetElementAt_uchar4(given, x, y));
- float difference = (idealFloats.r - givenFloats.r) + (idealFloats.g - givenFloats.g) +
- (idealFloats.b - givenFloats.b);
- v_out[0] += (difference * difference);
- }
-}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java
index 6a78f11..b7a608a 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java
@@ -15,22 +15,14 @@
*/
package android.uirendering.cts.bitmapcomparers;
-import android.uirendering.cts.R;
-import android.uirendering.cts.ScriptC_ThresholdDifferenceComparer;
-
-import android.content.res.Resources;
import android.graphics.Color;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
-import android.uirendering.cts.bitmapcomparers.BaseRenderScriptComparer;
import android.util.Log;
/**
* Compares two images to see if each pixel is the same, within a certain threshold value
*/
-public class ThresholdDifferenceComparer extends BaseRenderScriptComparer {
+public class ThresholdDifferenceComparer extends BitmapComparer {
private static final String TAG = "ThresholdDifference";
- private ScriptC_ThresholdDifferenceComparer mScript;
private int mThreshold;
/**
@@ -63,27 +55,4 @@
Log.d(TAG, "Number of different pixels : " + differentPixels);
return (differentPixels == 0);
}
-
- @Override
- public boolean verifySameRowsRS(Resources resources, Allocation ideal,
- Allocation given, int offset, int stride, int width, int height,
- RenderScript renderScript, Allocation inputAllocation, Allocation outputAllocation) {
- if (mScript == null) {
- mScript = new ScriptC_ThresholdDifferenceComparer(renderScript);
- }
-
- mScript.set_THRESHOLD(mThreshold);
- mScript.set_WIDTH(width);
-
- //Set the bitmap allocations
- mScript.set_ideal(ideal);
- mScript.set_given(given);
-
- //Call the renderscript function on each row
- mScript.forEach_thresholdCompare(inputAllocation, outputAllocation);
-
- float differentPixels = sum1DFloatAllocation(outputAllocation);
- Log.d(TAG, "Number of different pixels RS : " + differentPixels);
- return (differentPixels == 0);
- }
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.rs
deleted file mode 100644
index 8a40ad6..0000000
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(android.uirendering.cts)
-
-int WIDTH;
-int THRESHOLD;
-
-rs_allocation ideal;
-rs_allocation given;
-
-// This method does a threshold comparison of the values
-void thresholdCompare(const int32_t *v_in, float *v_out){
- int y = v_in[0];
- v_out[0] = 0;
-
- for(int i = 0 ; i < WIDTH ; i ++){
- uchar4 idealPixel = rsGetElementAt_uchar4(ideal, i, y);
- uchar4 givenPixel = rsGetElementAt_uchar4(given, i, y);
- float l1 = (idealPixel.x * 0.21f) + (idealPixel.y * 0.72f) + (idealPixel.z * 0.07f);
- float l2 = (givenPixel.x * 0.21f) + (givenPixel.y * 0.72f) + (givenPixel.z * 0.07f);
- float diff = l1 - l2;
- if (fabs(diff) >= THRESHOLD) {
- v_out[0]++;
- }
- }
-}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapTests.java
index 789d8d5..f0afd53 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapTests.java
@@ -28,6 +28,7 @@
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
+import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
import android.uirendering.cts.bitmapverifiers.ColorCountVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
@@ -42,6 +43,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
+
@LargeTest
@RunWith(AndroidJUnit4.class)
public class BitmapTests extends ActivityTestBase {
@@ -147,21 +150,17 @@
*/
@Test
public void testChangeDuringUiAnimation() {
- class PureBlueOrRedVerifier extends BitmapVerifier {
+ class BlueOrRedVerifier extends BitmapVerifier {
@Override
public boolean verify(int[] bitmap, int offset, int stride, int width, int height) {
- int blueCount = 0;
- int redCount = 0;
- for (int x = 0; x < width; x++) {
- for (int y = 0; y < height; y++) {
- if (bitmap[indexFromXAndY(x, y, stride, offset)] == Color.BLUE) {
- blueCount++;
- } else if (bitmap[indexFromXAndY(x, y, stride, offset)] == Color.RED) {
- redCount++;
- }
- }
- }
- return blueCount == width * height || redCount == width * height;
+ MSSIMComparer comparer = new MSSIMComparer(0.99);
+ int[] red = new int[offset + height * stride];
+ Arrays.fill(red, Color.RED);
+ int[] blue = new int[offset + height * stride];
+ Arrays.fill(blue, Color.BLUE);
+ boolean isRed = comparer.verifySame(red, bitmap, offset, stride, width, height);
+ boolean isBlue = comparer.verifySame(blue, bitmap, offset, stride, width, height);
+ return isRed || isBlue;
}
}
@@ -211,6 +210,6 @@
createTest()
.addLayout(R.layout.frame_layout, initializer, true)
- .runWithAnimationVerifier(new PureBlueOrRedVerifier());
+ .runWithAnimationVerifier(new BlueOrRedVerifier());
}
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
index 5a3331c..d5f9324 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
@@ -20,17 +20,13 @@
import android.content.Context;
import android.graphics.Bitmap;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
import android.uirendering.cts.bitmapcomparers.BitmapComparer;
import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
import android.uirendering.cts.differencevisualizers.DifferenceVisualizer;
import android.uirendering.cts.differencevisualizers.PassFailVisualizer;
public class BitmapAsserter {
- public static final boolean USE_RS = false;
private DifferenceVisualizer mDifferenceVisualizer;
- private RenderScript mRenderScript;
private Context mContext;
private String mClassName;
@@ -50,9 +46,6 @@
public void setUp(Context context) {
mDifferenceVisualizer = new PassFailVisualizer();
mContext = context;
- if (USE_RS) {
- mRenderScript = RenderScript.create(context.getApplicationContext());
- }
}
/**
@@ -69,20 +62,11 @@
fail("Can't compare bitmaps of different sizes");
}
- if (USE_RS && comparer.supportsRenderScript()) {
- Allocation idealAllocation = Allocation.createFromBitmap(mRenderScript, bitmap1,
- Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
- Allocation givenAllocation = Allocation.createFromBitmap(mRenderScript, bitmap2,
- Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
- success = comparer.verifySameRS(mContext.getResources(), idealAllocation,
- givenAllocation, 0, width, width, height, mRenderScript);
- } else {
- int[] pixels1 = new int[width * height];
- int[] pixels2 = new int[width * height];
- bitmap1.getPixels(pixels1, 0, width, 0, 0, width, height);
- bitmap2.getPixels(pixels2, 0, width, 0, 0, width, height);
- success = comparer.verifySame(pixels1, pixels2, 0, width, width, height);
- }
+ int[] pixels1 = new int[width * height];
+ int[] pixels2 = new int[width * height];
+ bitmap1.getPixels(pixels1, 0, width, 0, 0, width, height);
+ bitmap2.getPixels(pixels2, 0, width, 0, 0, width, height);
+ success = comparer.verifySame(pixels1, pixels2, 0, width, width, height);
if (!success) {
BitmapDumper.dumpBitmaps(bitmap1, bitmap2, testName, mClassName, mDifferenceVisualizer);
diff --git a/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java b/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java
index c54f183..72c89df 100644
--- a/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java
+++ b/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java
@@ -71,22 +71,7 @@
return;
}
- final View content = mActivity.findViewById(android.R.id.content);
- assertNotNull(content);
- final ViewParent viewParent = content.getParent();
- assertNotNull(viewParent);
- assertTrue(viewParent instanceof ViewGroup);
- ViewGroup parent = (ViewGroup) viewParent;
- View actionBarView = null;
- for (int i = 0; i < parent.getChildCount(); i++) {
- View child = parent.getChildAt(i);
- if ("android:action_bar".equals(child.getTransitionName())) {
- actionBarView = child;
- break;
- }
- }
- assertNotNull(actionBarView);
- final View actionBar = actionBarView;
+ final View actionBar = getActionBarView();
// Should jump to the action bar after meta+tab
mActivityRule.runOnUiThread(() -> {
assertFalse(v1.hasFocus());
@@ -118,6 +103,47 @@
}
}
+ @Test
+ public void testNoFocusablesInContent() throws Throwable {
+ ViewGroup top = mActivity.findViewById(R.id.linearlayout);
+ top.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+ mActivityRule.runOnUiThread(top::clearFocus);
+ mInstrumentation.waitForIdleSync();
+ top.clearFocus();
+ final View content = mActivity.findViewById(android.R.id.content);
+ assertTrue(content.findFocus() == null);
+ sendMetaHotkey(KeyEvent.KEYCODE_TAB);
+ mInstrumentation.waitForIdleSync();
+
+ ActionBar action = mActivity.getActionBar();
+ if (action == null || !action.isShowing()) {
+ // No action bar, so we only needed to make sure that the shortcut didn't cause
+ // the framework to crash.
+ return;
+ }
+
+ assertTrue(getActionBarView().hasFocus());
+ }
+
+ private View getActionBarView() {
+ final View content = mActivity.findViewById(android.R.id.content);
+ assertNotNull(content);
+ final ViewParent viewParent = content.getParent();
+ assertNotNull(viewParent);
+ assertTrue(viewParent instanceof ViewGroup);
+ ViewGroup parent = (ViewGroup) viewParent;
+ View actionBarView = null;
+ for (int i = 0; i < parent.getChildCount(); i++) {
+ View child = parent.getChildAt(i);
+ if ("android:action_bar".equals(child.getTransitionName())) {
+ actionBarView = child;
+ break;
+ }
+ }
+ assertNotNull(actionBarView);
+ return actionBarView;
+ }
+
private void sendMetaHotkey(int keyCode) throws Throwable {
sendMetaKey(KeyEvent.ACTION_DOWN);
long time = SystemClock.uptimeMillis();
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index 472e371..8caf161 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -1005,6 +1005,18 @@
}
}
+ public void testEnableSafeBrowsing() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ assertFalse(mSettings.getSafeBrowsingEnabled());
+ mSettings.setSafeBrowsingEnabled(true);
+ assertTrue(mSettings.getSafeBrowsingEnabled());
+ mSettings.setSafeBrowsingEnabled(false);
+ assertFalse(mSettings.getSafeBrowsingEnabled());
+ }
+
+
/**
* Starts the internal web server. The server will be shut down automatically
* during tearDown().
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index 07ba11e..d77af03 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -582,14 +582,14 @@
}
final MockWebViewClient webViewClient = new MockWebViewClient();
mOnUiThread.setWebViewClient(webViewClient);
- mOnUiThread.loadUrl("chrome://crash");
+ mOnUiThread.loadUrl("chrome://kill");
new PollingCheck(TEST_TIMEOUT * 5) {
@Override
protected boolean check() {
return webViewClient.hasRenderProcessGoneCalled();
}
}.run();
- assertTrue(webViewClient.didRenderProcessCrash());
+ assertFalse(webViewClient.didRenderProcessCrash());
}
private void requireLoadedPage() throws Throwable {
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 2ef274a..4ff8eef 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -26,7 +26,6 @@
import android.graphics.Color;
import android.graphics.Picture;
import android.graphics.Rect;
-import android.graphics.pdf.PdfRenderer;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -2551,8 +2550,7 @@
// Called on UI thread
@Override
public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
- PageRange[] pageRanges = new PageRange[] {PageRange.ALL_PAGES};
- savePrintedPage(adapter, descriptor, pageRanges, result);
+ savePrintedPage(adapter, descriptor, result);
}
});
try {
@@ -2570,57 +2568,6 @@
}
}
- // Verify Print feature can create a PDF file with correct number of pages.
- public void testPrintingPagesCount() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- String content = "<html><head></head><body>";
- for (int i = 0; i < 500; ++i) {
- content += "<br />abcdefghijk<br />";
- }
- content += "</body></html>";
- mOnUiThread.loadDataAndWaitForCompletion(content, "text/html", null);
- final PrintDocumentAdapter adapter = mOnUiThread.createPrintDocumentAdapter();
- printDocumentStart(adapter);
- PrintAttributes attributes = new PrintAttributes.Builder()
- .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
- .setResolution(new PrintAttributes.Resolution("foo", "bar", 300, 300))
- .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
- .build();
- final WebViewCtsActivity activity = getActivity();
- final File file = activity.getFileStreamPath(PRINTER_TEST_FILE);
- final ParcelFileDescriptor descriptor = ParcelFileDescriptor.open(file,
- ParcelFileDescriptor.parseMode("w"));
- final FutureTask<Boolean> result =
- new FutureTask<Boolean>(new Callable<Boolean>() {
- public Boolean call() {
- return true;
- }
- });
- printDocumentLayout(adapter, null, attributes,
- new LayoutResultCallback() {
- // Called on UI thread
- @Override
- public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
- PageRange[] pageRanges = new PageRange[] {
- new PageRange(1, 1), new PageRange(4, 7)
- };
- savePrintedPage(adapter, descriptor, pageRanges, result);
- }
- });
- try {
- result.get(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
- assertTrue(file.length() > 0);
- PdfRenderer renderer = new PdfRenderer(
- ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY));
- assertEquals(5, renderer.getPageCount());
- } finally {
- descriptor.close();
- file.delete();
- }
- }
-
public void testVisualStateCallbackCalled() throws Exception {
// Check that the visual state callback is called correctly.
if (!NullWebViewUtils.isWebViewAvailable()) {
@@ -2692,9 +2639,8 @@
}
private void savePrintedPage(final PrintDocumentAdapter adapter,
- final ParcelFileDescriptor descriptor, final PageRange[] pageRanges,
- final FutureTask<Boolean> result) {
- adapter.onWrite(pageRanges, descriptor,
+ final ParcelFileDescriptor descriptor, final FutureTask<Boolean> result) {
+ adapter.onWrite(new PageRange[] {PageRange.ALL_PAGES}, descriptor,
new CancellationSignal(),
new WriteResultCallback() {
@Override