Merge "Fix BYOD CTS Verifier Test"
diff --git a/apps/CameraITS/pymodules/its/image.py b/apps/CameraITS/pymodules/its/image.py
index d4776c7..1654faa8 100644
--- a/apps/CameraITS/pymodules/its/image.py
+++ b/apps/CameraITS/pymodules/its/image.py
@@ -414,7 +414,7 @@
return img
-def get_black_level(chan, props, cap_res):
+def get_black_level(chan, props, cap_res=None):
"""Return the black level to use for a given capture.
Uses a dynamic value from the capture result if available, else falls back
@@ -428,7 +428,7 @@
Returns:
The black level value for the specified channel.
"""
- if (cap_res.has_key('android.sensor.dynamicBlackLevel') and
+ if (cap_res is not None and cap_res.has_key('android.sensor.dynamicBlackLevel') and
cap_res['android.sensor.dynamicBlackLevel'] is not None):
black_levels = cap_res['android.sensor.dynamicBlackLevel']
else:
diff --git a/apps/CameraITS/tests/scene1/test_raw_exposure.py b/apps/CameraITS/tests/scene1/test_raw_exposure.py
new file mode 100644
index 0000000..3a0dcf6
--- /dev/null
+++ b/apps/CameraITS/tests/scene1/test_raw_exposure.py
@@ -0,0 +1,160 @@
+# Copyright 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import its.device
+import its.caps
+import its.objects
+import its.image
+import os.path
+import numpy as np
+from matplotlib import pylab
+import matplotlib.pyplot
+
+IMG_STATS_GRID = 9 # find used to find the center 11.11%
+NAME = os.path.basename(__file__).split(".")[0]
+NUM_ISO_STEPS = 5
+SATURATION_TOL = 0.01
+BLK_LVL_TOL = 0.1
+# Test 3 steps per 2x exposure
+EXP_MULT = pow(2, 1.0/3)
+INCREASING_THR = 0.99
+# slice captures into burst of SLICE_LEN requests
+SLICE_LEN = 10
+
+def main():
+ """Capture a set of raw images with increasing exposure time and measure the pixel values.
+ """
+
+ with its.device.ItsSession() as cam:
+
+ props = cam.get_camera_properties()
+ its.caps.skip_unless(its.caps.raw16(props) and
+ its.caps.manual_sensor(props) and
+ its.caps.read_3a(props) and
+ its.caps.per_frame_control(props))
+ debug = its.caps.debug_mode()
+
+ # Expose for the scene with min sensitivity
+ exp_min, exp_max = props["android.sensor.info.exposureTimeRange"]
+ sens_min, _ = props["android.sensor.info.sensitivityRange"]
+ # Digital gains might not be visible on RAW data
+ sens_max = props["android.sensor.maxAnalogSensitivity"]
+ sens_step = (sens_max - sens_min) / NUM_ISO_STEPS
+ white_level = float(props["android.sensor.info.whiteLevel"])
+ black_levels = [its.image.get_black_level(i,props) for i in range(4)]
+ # Get the active array width and height.
+ aax = props["android.sensor.info.activeArraySize"]["left"]
+ aay = props["android.sensor.info.activeArraySize"]["top"]
+ aaw = props["android.sensor.info.activeArraySize"]["right"]-aax
+ aah = props["android.sensor.info.activeArraySize"]["bottom"]-aay
+ raw_stat_fmt = {"format": "rawStats",
+ "gridWidth": aaw/IMG_STATS_GRID,
+ "gridHeight": aah/IMG_STATS_GRID}
+
+ e_test = []
+ mult = 1.0
+ while exp_min*mult < exp_max:
+ e_test.append(int(exp_min*mult))
+ mult *= EXP_MULT
+ if e_test[-1] < exp_max * INCREASING_THR:
+ e_test.append(int(exp_max))
+ e_test_ms = [e / 1000000.0 for e in e_test]
+
+ for s in range(sens_min, sens_max, sens_step):
+ means = []
+ means.append(black_levels)
+ reqs = [its.objects.manual_capture_request(s, e, 0) for e in e_test]
+ # Capture raw in debug mode, rawStats otherwise
+ caps = []
+ for i in range(len(reqs) / SLICE_LEN):
+ if debug:
+ caps += cam.do_capture(reqs[i*SLICE_LEN:(i+1)*SLICE_LEN], cam.CAP_RAW)
+ else:
+ caps += cam.do_capture(reqs[i*SLICE_LEN:(i+1)*SLICE_LEN], raw_stat_fmt)
+ last_n = len(reqs) % SLICE_LEN
+ if last_n == 1:
+ if debug:
+ caps += [cam.do_capture(reqs[-last_n:], cam.CAP_RAW)]
+ else:
+ caps += [cam.do_capture(reqs[-last_n:], raw_stat_fmt)]
+ elif last_n > 0:
+ if debug:
+ caps += cam.do_capture(reqs[-last_n:], cam.CAP_RAW)
+ else:
+ caps += cam.do_capture(reqs[-last_n:], raw_stat_fmt)
+
+ # Measure the mean of each channel.
+ # Each shot should be brighter (except underexposed/overexposed scene)
+ for i,cap in enumerate(caps):
+ if debug:
+ planes = its.image.convert_capture_to_planes(cap, props)
+ tiles = [its.image.get_image_patch(p, 0.445, 0.445, 0.11, 0.11) for p in planes]
+ mean = [m * white_level for tile in tiles
+ for m in its.image.compute_image_means(tile)]
+ img = its.image.convert_capture_to_rgb_image(cap, props=props)
+ its.image.write_image(img, "%s_s=%d_e=%05d.jpg" % (NAME, s, e_test))
+ else:
+ mean_image, _ = its.image.unpack_rawstats_capture(cap)
+ mean = mean_image[IMG_STATS_GRID/2, IMG_STATS_GRID/2]
+
+ print "ISO=%d, exposure time=%.3fms, mean=%s" % (
+ s, e_test[i] / 1000000.0, str(mean))
+ means.append(mean)
+
+
+ # means[0] is black level value
+ r = [m[0] for m in means[1:]]
+ gr = [m[1] for m in means[1:]]
+ gb = [m[2] for m in means[1:]]
+ b = [m[3] for m in means[1:]]
+
+ pylab.plot(e_test_ms, r, "r.-")
+ pylab.plot(e_test_ms, b, "b.-")
+ pylab.plot(e_test_ms, gr, "g.-")
+ pylab.plot(e_test_ms, gb, "k.-")
+ pylab.xscale('log')
+ pylab.yscale('log')
+ pylab.title("%s ISO=%d" % (NAME, s))
+ pylab.xlabel("Exposure time (ms)")
+ pylab.ylabel("Center patch pixel mean")
+ matplotlib.pyplot.savefig("%s_s=%d.png" % (NAME, s))
+ pylab.clf()
+
+ allow_under_saturated = True
+ for i in xrange(1, len(means)):
+ prev_mean = means[i-1]
+ mean = means[i]
+
+ if np.isclose(max(mean), white_level, rtol=SATURATION_TOL):
+ print "Saturated: white_level %f, max_mean %f"% (white_level, max(mean))
+ break;
+
+ if allow_under_saturated and np.allclose(mean, black_levels, rtol=BLK_LVL_TOL):
+ # All channel means are close to black level
+ continue
+
+ allow_under_saturated = False
+ # Check pixel means are increasing (with small tolerance)
+ channels = ["Red", "Gr", "Gb", "Blue"]
+ for chan in range(4):
+ err_msg = "ISO=%d, %s, exptime %3fms mean: %.2f, %s mean: %.2f, TOL=%.f%%" % (
+ s, channels[chan],
+ e_test_ms[i-1], mean[chan],
+ "black level" if i == 1 else "exptime %3fms"%e_test_ms[i-2],
+ prev_mean[chan],
+ INCREASING_THR*100)
+ assert mean[chan] > prev_mean[chan] * INCREASING_THR, err_msg
+
+if __name__ == "__main__":
+ main()
diff --git a/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py b/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py
index 065f854..f7f2003 100644
--- a/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py
+++ b/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py
@@ -52,6 +52,8 @@
with its.device.ItsSession() as cam:
props = cam.get_camera_properties()
+ its.caps.skip_unless(its.caps.ae_lock(props) and
+ its.caps.awb_lock(props))
if its.caps.read_3a(props):
# Converge 3A and get the estimates.
sens, exp, gains, xform, focus = cam.do_3a(get_results=True,
diff --git a/apps/CameraITS/tools/validate_scene.py b/apps/CameraITS/tools/validate_scene.py
index cfe14e2..1c0f0fd 100644
--- a/apps/CameraITS/tools/validate_scene.py
+++ b/apps/CameraITS/tools/validate_scene.py
@@ -49,8 +49,9 @@
" to frame the test scene: " + scene_name +
"\nThe scene setup should be: " + scene_desc )
# Converge 3A prior to capture.
- cam.do_3a(do_af=do_af, lock_ae=True, lock_awb=True)
props = cam.get_camera_properties()
+ cam.do_3a(do_af=do_af, lock_ae=its.caps.ae_lock(props),
+ lock_awb=its.caps.awb_lock(props))
req = its.objects.fastest_auto_capture_request(props)
if its.caps.ae_lock(props):
req["android.control.awbLock"] = True
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index 10c33ba..144333d 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -25,6 +25,9 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
+LOCAL_AIDL_INCLUDES := \
+ frameworks/native/aidl/gui
+
LOCAL_STATIC_JAVA_LIBRARIES := android-ex-camera2 \
compatibility-common-util-devicesidelib \
cts-sensors-tests \
@@ -46,6 +49,7 @@
LOCAL_JAVA_LIBRARIES += android.test.base.stubs
LOCAL_JAVA_LIBRARIES += android.test.mock.stubs
LOCAL_JAVA_LIBRARIES += bouncycastle
+LOCAL_JAVA_LIBRARIES += voip-common
LOCAL_PACKAGE_NAME := CtsVerifier
@@ -55,8 +59,6 @@
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-LOCAL_SDK_VERSION := test_current
-
LOCAL_DEX_PREOPT := false
-include cts/error_prone_rules_tests.mk
include $(BUILD_PACKAGE)
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralButtonsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralButtonsActivity.java
index 861af28..8345184 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralButtonsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralButtonsActivity.java
@@ -16,6 +16,7 @@
package com.android.cts.verifier.audio;
+import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
@@ -110,13 +111,15 @@
if (mIsPeripheralAttached && mSelectedProfile != null) {
ProfileButtonAttributes mButtonAttributes = mSelectedProfile.getButtonAttributes();
boolean match = mButtonAttributes != null;
+ boolean interceptedVolume = getResources().getBoolean(Resources.getSystem()
+ .getIdentifier("config_handleVolumeKeysInWindowManager", "bool", "android"));
if (match && mButtonAttributes.mHasBtnA != mHasBtnA) {
match = false;
}
- if (match && mButtonAttributes.mHasBtnB != mHasBtnB) {
+ if (match && mButtonAttributes.mHasBtnB != mHasBtnB && !interceptedVolume) {
match = false;
}
- if (match && mButtonAttributes.mHasBtnC != mHasBtnC) {
+ if (match && mButtonAttributes.mHasBtnC != mHasBtnC && !interceptedVolume) {
match = false;
}
Log.i(TAG, "match:" + match);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index 5dbbc79..81226a6 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -1328,7 +1328,8 @@
int newCount = mCountCallbacksRemaining.get();
if (newCount == currentCount) {
- throw new ItsException("No callback received within timeout");
+ throw new ItsException("No callback received within timeout " +
+ timeoutMs + "ms");
}
currentCount = newCount;
}
@@ -1802,8 +1803,8 @@
logMsg.append(String.format(
"sens=%d, exp=%.1fms, dur=%.1fms, ",
result.get(CaptureResult.SENSOR_SENSITIVITY),
- result.get(CaptureResult.SENSOR_EXPOSURE_TIME).intValue() / 1000000.0f,
- result.get(CaptureResult.SENSOR_FRAME_DURATION).intValue() /
+ result.get(CaptureResult.SENSOR_EXPOSURE_TIME).longValue() / 1000000.0f,
+ result.get(CaptureResult.SENSOR_FRAME_DURATION).longValue() /
1000000.0f));
}
if (result.get(CaptureResult.COLOR_CORRECTION_GAINS) != null) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ICrossUserService.aidl b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ICrossUserService.aidl
index 630fe1e..8894745 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ICrossUserService.aidl
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ICrossUserService.aidl
@@ -16,6 +16,8 @@
package com.android.cts.verifier.managedprovisioning;
+import android.os.UserHandle;
+
interface ICrossUserService {
void switchUser(in UserHandle userHandle);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/LockTaskUiTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/LockTaskUiTestActivity.java
index a6e6b2f..5447536 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/LockTaskUiTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/LockTaskUiTestActivity.java
@@ -21,12 +21,11 @@
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NONE;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS;
-import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_RECENTS;
+import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO;
import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
-import android.app.Activity;
import android.app.ActivityManager;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -152,7 +151,7 @@
adapter.add(createSetLockTaskFeaturesTest(
TEST_ID_RECENTS,
- LOCK_TASK_FEATURE_RECENTS,
+ LOCK_TASK_FEATURE_OVERVIEW,
R.string.device_owner_lock_task_ui_recents_test,
R.string.device_owner_lock_task_ui_recents_test_info));
diff --git a/tests/autofillservice/src/android/autofillservice/cts/RequiredFeatureRule.java b/common/device-side/util/src/com/android/compatibility/common/util/RequiredFeatureRule.java
similarity index 95%
rename from tests/autofillservice/src/android/autofillservice/cts/RequiredFeatureRule.java
rename to common/device-side/util/src/com/android/compatibility/common/util/RequiredFeatureRule.java
index 17b2504..0968ddc 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/RequiredFeatureRule.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/RequiredFeatureRule.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.autofillservice.cts;
+package com.android.compatibility.common.util;
import android.support.test.InstrumentationRegistry;
import android.util.Log;
@@ -26,7 +26,6 @@
/**
* Custom JUnit4 rule that does not run a test case if the device does not have a given feature.
*/
-// TODO: move to common CTS codebase
public class RequiredFeatureRule implements TestRule {
private static final String TAG = "RequiredFeatureRule";
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
index db8a888..60400be 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
@@ -71,6 +71,9 @@
@Option(name="build-flavor", description="build flavor name to supply.")
private String mBuildFlavor = null;
+ @Option(name="build-target", description="build target name to supply.")
+ private String mBuildTarget = null;
+
@Option(name="build-attribute", description="build attributes to supply.")
private Map<String, String> mBuildAttributes = new HashMap<String,String>();
@@ -103,6 +106,9 @@
for (Map.Entry<String, String> entry : mBuildAttributes.entrySet()) {
buildInfo.addBuildAttribute(entry.getKey(), entry.getValue());
}
+ if (mTestTag != null) {
+ buildInfo.setTestTag(mTestTag);
+ }
}
/**
@@ -117,7 +123,7 @@
* {@inheritDoc}
*/
@Override
- public IBuildInfo getBuild() {
+ public IBuildInfo getBuild() throws BuildRetrievalError {
// Create a blank BuildInfo which will get populated later.
String version = null;
if (mBuildId != null) {
@@ -128,7 +134,7 @@
version = IBuildInfo.UNKNOWN_BUILD_ID;
}
}
- IBuildInfo ctsBuild = new DeviceBuildInfo(version, mTestTag);
+ IBuildInfo ctsBuild = new DeviceBuildInfo(version, mBuildTarget);
if (mBranch != null) {
ctsBuild.setBuildBranch(mBranch);
}
@@ -151,9 +157,18 @@
// build info fields
return getBuild();
} else {
- String buildId = device.getBuildId();
- String buildFlavor = device.getBuildFlavor();
- IBuildInfo info = new DeviceBuildInfo(buildId, mTestTag);
+ if (mBuildId == null) {
+ mBuildId = device.getBuildId();
+ }
+ if (mBuildFlavor == null) {
+ mBuildFlavor = device.getBuildFlavor();
+ }
+ if (mBuildTarget == null) {
+ String name = device.getProperty("ro.product.name");
+ String variant = device.getProperty("ro.build.type");
+ mBuildTarget = name + "-" + variant;
+ }
+ IBuildInfo info = new DeviceBuildInfo(mBuildId, mBuildTarget);
if (mBranch == null) {
// if branch is not specified via param, make a pseudo branch name based on platform
// version and product info from device
@@ -164,7 +179,7 @@
device.getProperty("ro.build.version.release"));
}
info.setBuildBranch(mBranch);
- info.setBuildFlavor(buildFlavor);
+ info.setBuildFlavor(mBuildFlavor);
String buildAlias = device.getBuildAlias();
if (RELEASE_BUILD.matcher(buildAlias).matches()) {
info.addBuildAttribute("build_alias", buildAlias);
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
index fe29c7f..5dcf2dd 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
@@ -22,6 +22,7 @@
import com.android.compatibility.common.util.IInvocationResult;
import com.android.compatibility.common.util.ResultHandler;
import com.android.compatibility.common.util.TestStatus;
+import com.android.tradefed.build.BuildRetrievalError;
import com.android.tradefed.command.Console;
import com.android.tradefed.config.ArgsOptionParser;
import com.android.tradefed.config.ConfigurationException;
@@ -426,8 +427,12 @@
private CompatibilityBuildHelper getBuildHelper() {
if (mBuildHelper == null) {
- CompatibilityBuildProvider buildProvider = new CompatibilityBuildProvider();
- mBuildHelper = new CompatibilityBuildHelper(buildProvider.getBuild());
+ try {
+ CompatibilityBuildProvider buildProvider = new CompatibilityBuildProvider();
+ mBuildHelper = new CompatibilityBuildHelper(buildProvider.getBuild());
+ } catch (BuildRetrievalError e) {
+ e.printStackTrace();
+ }
}
return mBuildHelper;
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/CertificationSuiteResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/CertificationSuiteResultReporter.java
index f57126d..7934abd 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/CertificationSuiteResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/CertificationSuiteResultReporter.java
@@ -60,7 +60,8 @@
import javax.xml.transform.stream.StreamSource;
/**
- * Extension of {@link SuiteResultReporter} to handle Compatibility specific format and operations.
+ * Extension of {@link XmlFormattedGeneratorReporter} and {@link SuiteResultReporter} to handle
+ * Compatibility specific format and operations.
*/
public class CertificationSuiteResultReporter extends XmlFormattedGeneratorReporter
implements ILogSaverListener, ITestSummaryListener {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTest.java
index a95ebfb..1ac2014 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTest.java
@@ -199,6 +199,7 @@
test.setInvocationContext(mContext);
// reset the retry id - Ensure that retry of retry does not throw
test.resetRetryId();
+ test.isRetry();
// clean the helper
helper.tearDown();
return test;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuite.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuite.java
index be64ccd..dd6a457 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuite.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuite.java
@@ -19,11 +19,13 @@
import com.android.compatibility.common.tradefed.testtype.ISubPlan;
import com.android.compatibility.common.tradefed.testtype.SubPlan;
import com.android.compatibility.common.tradefed.testtype.retry.RetryFactoryTest;
+import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.IConfiguration;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.Option.Importance;
import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.IAbi;
import com.android.tradefed.testtype.suite.BaseTestSuite;
import com.android.tradefed.testtype.suite.SuiteModuleLoader;
@@ -59,6 +61,8 @@
private String mSubPlan;
private CompatibilityBuildHelper mBuildHelper;
+ /** Tag if the current instance is running as a retry from RetryFactory */
+ private boolean mIsRetry = false;
@Override
public void setBuild(IBuildInfo buildInfo) {
@@ -84,8 +88,8 @@
@Override
public LinkedHashMap<String, IConfiguration> loadTests() {
if (mRetrySessionId != null) {
- throw new IllegalArgumentException("--retry cannot be specified with cts-suite.xml. "
- + "Use 'run cts --retry <session id>' instead.");
+ throw new IllegalArgumentException("--retry cannot be specified with cts[*].xml. "
+ + "Use 'run retry --retry <session id>' instead.");
}
return super.loadTests();
}
@@ -125,6 +129,13 @@
}
/**
+ * Mark the instance of CompatibilityTestSuite as a retry.
+ */
+ public final void isRetry() {
+ mIsRetry = true;
+ }
+
+ /**
* {@inheritDoc}
*/
@Override
@@ -136,9 +147,15 @@
getModuleLoader().loadConfigsFromDirectory(testsDir, abis, suitePrefix, suiteTag));
// Add an extra check in CTS since we never expect the config folder to be empty.
if (loadedConfigs.size() == 0) {
- throw new IllegalArgumentException(
- String.format("No config files found in %s or in resources.",
- testsDir.getAbsolutePath()));
+ if (mIsRetry) {
+ // Only log if it's a retry
+ CLog.logAndDisplay(LogLevel.DEBUG,
+ "No module that needed to run in retry were found. nothing to do.");
+ } else {
+ throw new IllegalArgumentException(
+ String.format("No config files found in %s or in resources.",
+ testsDir.getAbsolutePath()));
+ }
}
return loadedConfigs;
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProviderTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProviderTest.java
index 0e02c023..f7116d7 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProviderTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProviderTest.java
@@ -85,6 +85,8 @@
EasyMock.expect(mMockDevice.getBuildId()).andReturn("8888");
EasyMock.expect(mMockDevice.getBuildFlavor()).andReturn("flavor");
EasyMock.expect(mMockDevice.getBuildAlias()).andReturn("alias");
+ EasyMock.expect(mMockDevice.getProperty("ro.product.name")).andReturn("product");
+ EasyMock.expect(mMockDevice.getProperty("ro.build.type")).andReturn("userdebug");
EasyMock.replay(mMockDevice);
IBuildInfo info = mProvider.getBuild(mMockDevice);
EasyMock.verify(mMockDevice);
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java
index 0a972f1..ede86ef 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java
@@ -56,6 +56,7 @@
"art",
"auth",
"auto",
+ "autofill",
"backup",
"bionic",
"bluetooth",
diff --git a/common/util/src/com/android/compatibility/common/util/ResultHandler.java b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
index c394b8d..d85c678 100644
--- a/common/util/src/com/android/compatibility/common/util/ResultHandler.java
+++ b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
@@ -156,8 +156,9 @@
* @return an IInvocationResult for this result, or null upon error
*/
public static IInvocationResult getResultFromDir(File resultDir, Boolean useChecksum) {
+ File resultFile = null;
try {
- File resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
+ resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
if (!resultFile.exists()) {
return null;
}
@@ -277,6 +278,9 @@
parser.require(XmlPullParser.END_TAG, NS, RESULT_TAG);
return invocation;
} catch (XmlPullParserException | IOException e) {
+ System.out.println(
+ String.format("Exception when trying to load %s",
+ resultFile.getAbsolutePath()));
e.printStackTrace();
return null;
}
diff --git a/hostsidetests/appsecurity/test-apps/AccessSerialLegacy/Android.mk b/hostsidetests/appsecurity/test-apps/AccessSerialLegacy/Android.mk
index e4b7962..bfb88f0 100644
--- a/hostsidetests/appsecurity/test-apps/AccessSerialLegacy/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/AccessSerialLegacy/Android.mk
@@ -25,6 +25,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsAccessSerialLegacy
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/appsecurity/test-apps/AccessSerialModern/Android.mk b/hostsidetests/appsecurity/test-apps/AccessSerialModern/Android.mk
index 20d51b6..4bdb346 100644
--- a/hostsidetests/appsecurity/test-apps/AccessSerialModern/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/AccessSerialModern/Android.mk
@@ -26,6 +26,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsAccessSerialModern
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk
index 2683128..f37be44 100644
--- a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk
@@ -22,6 +22,7 @@
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
LOCAL_EXPORT_PACKAGE_RESOURCES := true
LOCAL_PACKAGE_NAME := CtsClassloaderSplitAppFeatureA
+LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk
index a1b43ea..3262e15 100644
--- a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk
@@ -21,6 +21,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
LOCAL_PACKAGE_NAME := CtsClassloaderSplitAppFeatureB
+LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.mk b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.mk
index dbf5284..6af9e72 100644
--- a/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.mk
@@ -21,6 +21,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := CtsDeclareNonRuntimePermissions
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk
index 99ee67c..dab340b 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk
@@ -32,6 +32,7 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := CtsEphemeralTestsEphemeralApp1
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_DEX_PREOPT := false
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/Android.mk
index 4f0ee6c..a5bc4b0 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/Android.mk
@@ -26,6 +26,7 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := CtsEphemeralTestsEphemeralApp2
+LOCAL_SDK_VERSION := current
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_DEX_PREOPT := false
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.mk
index 6309704..8b04f9b 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/ImplicitlyExposedApp/Android.mk
@@ -29,6 +29,7 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := CtsEphemeralTestsImplicitApp
+LOCAL_SDK_VERSION := current
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_DEX_PREOPT := false
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.mk
index bd1b2d8..d2c3667 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/Android.mk
@@ -31,6 +31,7 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := CtsEphemeralTestsNormalApp
+LOCAL_SDK_VERSION := system_current
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_DEX_PREOPT := false
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.mk
index 5fa3765..7ceaff3 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UnexposedApp/Android.mk
@@ -26,6 +26,7 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := CtsEphemeralTestsUnexposedApp
+LOCAL_SDK_VERSION := current
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_DEX_PREOPT := false
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserApp/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserApp/Android.mk
index 35c089f..28560d3 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserApp/Android.mk
@@ -29,6 +29,7 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := CtsEphemeralTestsUserApp
+LOCAL_SDK_VERSION := current
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_DEX_PREOPT := false
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/Android.mk
index cfa0b55..64f02cb 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/Android.mk
@@ -28,6 +28,7 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := CtsEphemeralTestsUserAppTest
+LOCAL_SDK_VERSION := current
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_DEX_PREOPT := false
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/util/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/util/Android.mk
index fc1bd83..df29c03 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/util/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/util/Android.mk
@@ -23,5 +23,7 @@
LOCAL_MODULE := cts-aia-util
+LOCAL_SDK_VERSION := current
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/util/src/com/android/cts/util/TestResult.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/util/src/com/android/cts/util/TestResult.java
index 9664823..0f52e80 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/util/src/com/android/cts/util/TestResult.java
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/util/src/com/android/cts/util/TestResult.java
@@ -119,7 +119,7 @@
mStatus = source.readString();
mException = source.readString();
mIntent = source.readParcelable(Object.class.getClassLoader());
- mInstantAppPackageInfoExposed = source.readBoolean();
+ mInstantAppPackageInfoExposed = source.readInt() != 0;
}
public static class Builder {
diff --git a/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.mk b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.mk
index cd3c04e..5945188 100644
--- a/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.mk
@@ -25,6 +25,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsEscalateToRuntimePermissions
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/appsecurity/test-apps/InstantCookieApp/Android.mk b/hostsidetests/appsecurity/test-apps/InstantCookieApp/Android.mk
index 1f9063c..78eb619 100644
--- a/hostsidetests/appsecurity/test-apps/InstantCookieApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/InstantCookieApp/Android.mk
@@ -25,6 +25,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
LOCAL_PACKAGE_NAME := CtsInstantCookieApp
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/appsecurity/test-apps/InstantCookieApp2/Android.mk b/hostsidetests/appsecurity/test-apps/InstantCookieApp2/Android.mk
index b154ae2..6385123 100644
--- a/hostsidetests/appsecurity/test-apps/InstantCookieApp2/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/InstantCookieApp2/Android.mk
@@ -25,6 +25,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
LOCAL_PACKAGE_NAME := CtsInstantCookieApp2
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_a/Android.mk b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_a/Android.mk
index dd76592..c089660 100644
--- a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_a/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_a/Android.mk
@@ -18,6 +18,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsIsolatedSplitAppFeatureA
+LOCAL_SDK_VERSION := current
LOCAL_USE_AAPT2 := true
LOCAL_MODULE_TAGS := tests
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_b/Android.mk b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_b/Android.mk
index 240fc2c..42fd4cc 100644
--- a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_b/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_b/Android.mk
@@ -18,6 +18,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsIsolatedSplitAppFeatureB
+LOCAL_SDK_VERSION := current
LOCAL_USE_AAPT2 := true
LOCAL_MODULE_TAGS := tests
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_c/Android.mk b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_c/Android.mk
index 35b3252..d7f6687 100644
--- a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_c/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/feature_c/Android.mk
@@ -18,6 +18,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsIsolatedSplitAppFeatureC
+LOCAL_SDK_VERSION := current
LOCAL_USE_AAPT2 := true
LOCAL_MODULE_TAGS := tests
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/Android.mk b/hostsidetests/appsecurity/test-apps/NoRestartApp/Android.mk
index 32f36d0..23db742 100644
--- a/hostsidetests/appsecurity/test-apps/NoRestartApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/Android.mk
@@ -21,6 +21,7 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := CtsNoRestartBase
+LOCAL_SDK_VERSION := current
LOCAL_MODULE_TAGS := tests
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/Android.mk b/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/Android.mk
index 626c0be..08fa1bd 100644
--- a/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/feature/Android.mk
@@ -21,6 +21,7 @@
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := CtsNoRestartFeature
+LOCAL_SDK_VERSION := current
LOCAL_MODULE_TAGS := tests
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.mk b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.mk
index 0d53ac8..a8d659b 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.mk
@@ -28,6 +28,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsPermissionPolicyTest25
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
index a248b71..06901d8 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
@@ -19,6 +19,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := CtsSplitAppFeature
+LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_SPLITS := v7
LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
index bad39fb..5337057 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
@@ -19,6 +19,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSplitApp_arm64-v8a
+LOCAL_SDK_VERSION := current
LOCAL_JAVA_RESOURCE_DIRS := raw
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
index 9951098..7fceede 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
@@ -19,6 +19,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSplitApp_armeabi-v7a
+LOCAL_SDK_VERSION := current
LOCAL_JAVA_RESOURCE_DIRS := raw
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
index f6efcd6..9149930 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
@@ -19,6 +19,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSplitApp_armeabi
+LOCAL_SDK_VERSION := current
LOCAL_JAVA_RESOURCE_DIRS := raw
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
index aa2de06..95d02d0 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
@@ -19,6 +19,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSplitApp_mips
+LOCAL_SDK_VERSION := current
LOCAL_JAVA_RESOURCE_DIRS := raw
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
index cd4eafc..ad10be0 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
@@ -19,6 +19,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSplitApp_mips64
+LOCAL_SDK_VERSION := current
LOCAL_JAVA_RESOURCE_DIRS := raw
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
index 2d7d008..f008564 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
@@ -19,6 +19,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSplitApp_x86
+LOCAL_SDK_VERSION := current
LOCAL_JAVA_RESOURCE_DIRS := raw
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
index 291a3c6..ded5b29 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
@@ -19,6 +19,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSplitApp_x86_64
+LOCAL_SDK_VERSION := current
LOCAL_JAVA_RESOURCE_DIRS := raw
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk
index e1395bb..7a62f09 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk
@@ -33,6 +33,7 @@
../UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
LOCAL_PACKAGE_NAME := CtsUsePermissionApp22
+LOCAL_PRIVATE_PLATFORM_APIS := true
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk
index 74f6e6c..58ee1c7 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk
@@ -31,6 +31,7 @@
../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
LOCAL_PACKAGE_NAME := CtsUsePermissionApp23
+LOCAL_PRIVATE_PLATFORM_APIS := true
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
index b9b652a..01f9c7d 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
@@ -51,6 +51,7 @@
}
@Ignore
+ @Test
public void testFail() throws Exception {
fail("Expected");
}
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp25/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp25/Android.mk
index 82d69ba..8528752 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp25/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp25/Android.mk
@@ -32,6 +32,7 @@
LOCAL_RESOURCE_DIR := cts/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res
LOCAL_PACKAGE_NAME := CtsUsePermissionApp25
+LOCAL_PRIVATE_PLATFORM_APIS := true
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp26/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/Android.mk
index 7064288..52c8ba4 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp26/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/Android.mk
@@ -31,6 +31,7 @@
LOCAL_RESOURCE_DIR := cts/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res
LOCAL_PACKAGE_NAME := CtsUsePermissionApp26
+LOCAL_PRIVATE_PLATFORM_APIS := true
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.mk b/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.mk
index 92e8cdf..3069bac 100644
--- a/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.mk
+++ b/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.mk
@@ -25,6 +25,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsSyncInvalidAccountAuthorityTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk
index 71aeff6..3032da7 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk
@@ -32,8 +32,6 @@
LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 compatibility-device-util ctstestrunner ub-uiautomator
-LOCAL_SDK_VERSION := test_current
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/../res
# tag this module as a cts test artifact
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api25/Android.mk b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api25/Android.mk
index 6e6227c..fd3705a 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api25/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api25/Android.mk
@@ -32,8 +32,6 @@
LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 compatibility-device-util ctstestrunner ub-uiautomator
-LOCAL_SDK_VERSION := test_current
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/../res
# tag this module as a cts test artifact
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk
index 4e2b51c..f8f1c1a 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk
@@ -32,8 +32,6 @@
LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 compatibility-device-util ctstestrunner ub-uiautomator
-LOCAL_SDK_VERSION := test_current
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/../res
# tag this module as a cts test artifact
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
index 835a0f2..66bc40f 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
@@ -41,8 +41,6 @@
android-support-test \
cts-security-test-support-library
-LOCAL_SDK_VERSION := test_current
-
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := arcts cts vts general-tests
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskTest.java
index 6ef2ba1..8874660 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskTest.java
@@ -20,7 +20,7 @@
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NONE;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS;
-import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_RECENTS;
+import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO;
import static junit.framework.Assert.assertEquals;
@@ -191,7 +191,7 @@
LOCK_TASK_FEATURE_SYSTEM_INFO,
LOCK_TASK_FEATURE_NOTIFICATIONS,
LOCK_TASK_FEATURE_HOME,
- LOCK_TASK_FEATURE_RECENTS,
+ LOCK_TASK_FEATURE_OVERVIEW,
LOCK_TASK_FEATURE_GLOBAL_ACTIONS,
LOCK_TASK_FEATURE_KEYGUARD
};
@@ -505,11 +505,11 @@
}
/**
- * Starts LockTaskUtilityActivity with {@link ActivityOptions#setLockTaskMode(boolean)}
+ * Starts LockTaskUtilityActivity with {@link ActivityOptions#setLockTaskEnabled(boolean)}
*/
private void startLockTaskWithOptions(String className) throws InterruptedException {
Intent intent = getLockTaskUtility(className);
- Bundle options = ActivityOptions.makeBasic().setLockTaskMode(true).toBundle();
+ Bundle options = ActivityOptions.makeBasic().setLockTaskEnabled(true).toBundle();
startAndWait(intent, options);
}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WipeDataTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WipeDataTest.java
index 26f627e..65c7724 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WipeDataTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WipeDataTest.java
@@ -44,7 +44,7 @@
* external storage should be allowed.
*/
public void testWipeDataWithReason() throws InterruptedException {
- mDevicePolicyManager.wipeDataWithReason(0, TEST_WIPE_DATA_REASON);
+ mDevicePolicyManager.wipeData(0, TEST_WIPE_DATA_REASON);
// The test that the profile will indeed be removed is done in the host.
// Notification verification is done in another test.
}
diff --git a/hostsidetests/devicepolicy/app/ProfileOwner/Android.mk b/hostsidetests/devicepolicy/app/ProfileOwner/Android.mk
index 1903ced..117558c 100644
--- a/hostsidetests/devicepolicy/app/ProfileOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/ProfileOwner/Android.mk
@@ -36,8 +36,6 @@
compatibility-device-util \
ub-uiautomator
-LOCAL_SDK_VERSION := test_current
-
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/Android.mk b/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/Android.mk
index d99fd39..5f3212f 100644
--- a/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/Android.mk
+++ b/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/Android.mk
@@ -24,7 +24,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs conscrypt cts-junit
+LOCAL_JAVA_LIBRARIES := android.test.runner.stubs cts-junit
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-v4 \
diff --git a/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/Android.mk b/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/Android.mk
index 5e3f6a9..71e2078 100644
--- a/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/Android.mk
+++ b/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/Android.mk
@@ -24,7 +24,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs conscrypt cts-junit
+LOCAL_JAVA_LIBRARIES := android.test.runner.stubs cts-junit
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-v4 \
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index ed2b193..6beff2a 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -20,6 +20,7 @@
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.TestResult.TestStatus;
import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.log.LogUtil.CLog;
@@ -54,6 +55,14 @@
*/
public class BaseDevicePolicyTest extends DeviceTestCase implements IBuildReceiver {
+ @Option(
+ name = "skip-device-admin-feature-check",
+ description = "Flag that allows to skip the check for android.software.device_admin "
+ + "and run the tests no matter what. This is useful for system that do not what "
+ + "to expose that feature publicly."
+ )
+ private boolean mSkipDeviceAdminFeatureCheck = false;
+
private static final String RUNNER = "android.support.test.runner.AndroidJUnitRunner";
protected static final int USER_SYSTEM = 0; // From the UserHandle class.
@@ -122,8 +131,10 @@
protected void setUp() throws Exception {
super.setUp();
assertNotNull(mCtsBuild); // ensure build has been set before test is run.
- mHasFeature = getDevice().getApiLevel() >= 21 /* Build.VERSION_CODES.L */
- && hasDeviceFeature("android.software.device_admin");
+ mHasFeature = getDevice().getApiLevel() >= 21; /* Build.VERSION_CODES.L */
+ if (!mSkipDeviceAdminFeatureCheck) {
+ mHasFeature = mHasFeature && hasDeviceFeature("android.software.device_admin");
+ }
mSupportsMultiUser = getMaxNumberOfUsersSupported() > 1;
mSupportsFbe = hasDeviceFeature("android.software.file_based_encryption");
mFixedPackages = getDevice().getInstalledPackageNames();
diff --git a/hostsidetests/gputools/apps/Android.mk b/hostsidetests/gputools/apps/Android.mk
index 2a2cdd9..c913837 100644
--- a/hostsidetests/gputools/apps/Android.mk
+++ b/hostsidetests/gputools/apps/Android.mk
@@ -30,6 +30,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := CtsGpuToolsRootlessGpuDebugApp-DEBUG
+LOCAL_SDK_VERSION := current
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
@@ -51,6 +52,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := CtsGpuToolsRootlessGpuDebugApp-RELEASE
+LOCAL_SDK_VERSION := current
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/gputools/layers/Android.mk b/hostsidetests/gputools/layers/Android.mk
index 69f6930..201fafd 100644
--- a/hostsidetests/gputools/layers/Android.mk
+++ b/hostsidetests/gputools/layers/Android.mk
@@ -54,6 +54,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := CtsGpuToolsRootlessGpuDebugApp-LAYERS
+LOCAL_SDK_VERSION := current
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/DeviceEventConstants.java b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/DeviceEventConstants.java
index 1f694d2..06a68f7 100644
--- a/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/DeviceEventConstants.java
+++ b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/DeviceEventConstants.java
@@ -76,6 +76,11 @@
ON_CREATE,
/**
+ * {@link android.inputmethodservice.InputMethodService#onBindInput()} callback.
+ */
+ ON_BIND_INPUT,
+
+ /**
* {@link android.inputmethodservice.InputMethodService#onStartInput(android.view.inputmethod.EditorInfo,boolean) onStartInput(EditorInfo,boolean}
* callback.
*/
@@ -87,6 +92,11 @@
ON_START_INPUT_VIEW,
/**
+ * {@link android.inputmethodservice.InputMethodService#onUnbindInput()} callback.
+ */
+ ON_UNBIND_INPUT,
+
+ /**
* {@link android.inputmethodservice.InputMethodService#onFinishInputView(boolean) onFinishInputView(boolean)}
* callback.
*/
diff --git a/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/EditTextAppConstants.java b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/EditTextAppConstants.java
new file mode 100644
index 0000000..f575c55
--- /dev/null
+++ b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/EditTextAppConstants.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.inputmethodservice.cts.common;
+
+public class EditTextAppConstants {
+ // This is constants holding class, can't instantiate.
+ private EditTextAppConstants() {}
+
+ public static final String PACKAGE = "android.inputmethodservice.cts.edittextapp";
+ public static final String CLASS = PACKAGE + ".MainActivity";
+ public static final String APK = "EditTextApp.apk";
+}
diff --git a/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/DeviceTestConstants.java b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/DeviceTestConstants.java
index 049f32e..dae6db5 100644
--- a/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/DeviceTestConstants.java
+++ b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/DeviceTestConstants.java
@@ -45,4 +45,6 @@
public static final String TEST_SET_INPUTMETHOD_AND_SUBTYPE = "testSetInputMethodAndSubtype";
public static final String TEST_SWITCH_NEXT_INPUT = "testSwitchToNextInputMethod";
public static final String TEST_SWITCH_LAST_INPUT = "testSwitchToLastInputMethod";
+ public static final String TEST_INPUT_UNBINDS_ON_IME_STOPPED = "testInputUnbindsOnImeStopped";
+ public static final String TEST_INPUT_UNBINDS_ON_APP_STOPPED = "testInputUnbindsOnAppStopped";
}
diff --git a/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/ShellCommandUtils.java b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/ShellCommandUtils.java
index 643eb52..3d46894 100644
--- a/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/ShellCommandUtils.java
+++ b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/ShellCommandUtils.java
@@ -61,6 +61,10 @@
return "content delete --uri " + contentUri;
}
+ public static String uninstallPackage(String packageName) {
+ return "pm uninstall " + packageName;
+ }
+
/**
* Command to send broadcast {@code Intent}.
*
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 0b43dd6..73410e4 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
@@ -19,9 +19,14 @@
import static android.inputmethodservice.cts.DeviceEvent.isFrom;
import static android.inputmethodservice.cts.DeviceEvent.isNewerThan;
import static android.inputmethodservice.cts.DeviceEvent.isType;
+import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType
+ .ON_BIND_INPUT;
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_UNBIND_INPUT;
import static android.inputmethodservice.cts.common.ImeCommandConstants.ACTION_IME_COMMAND;
import static android.inputmethodservice.cts.common.ImeCommandConstants
.COMMAND_SET_INPUT_METHOD_AND_SUBTYPE;
@@ -37,6 +42,7 @@
import android.inputmethodservice.cts.DeviceEvent;
import android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType;
+import android.inputmethodservice.cts.common.EditTextAppConstants;
import android.inputmethodservice.cts.common.Ime1Constants;
import android.inputmethodservice.cts.common.Ime2Constants;
import android.inputmethodservice.cts.common.test.DeviceTestConstants;
@@ -192,6 +198,62 @@
TIMEOUT, initialIme + " is current IME");
}
+ @Test
+ public void testInputUnbindsOnImeStopped() throws Throwable {
+ final TestHelper helper = new TestHelper(
+ getClass(), DeviceTestConstants.TEST_INPUT_UNBINDS_ON_IME_STOPPED);
+ final long startActivityTime = SystemClock.uptimeMillis();
+ helper.launchActivity(DeviceTestConstants.PACKAGE, DeviceTestConstants.TEST_ACTIVITY_CLASS);
+ helper.findUiObject(R.id.text_entry).click();
+
+ pollingCheck(() -> helper.queryAllEvents()
+ .filter(isNewerThan(startActivityTime))
+ .anyMatch(isFrom(Ime1Constants.CLASS).and(isType(ON_START_INPUT))),
+ TIMEOUT, "CtsInputMethod1.onStartInput is called");
+ pollingCheck(() -> helper.queryAllEvents()
+ .filter(isNewerThan(startActivityTime))
+ .anyMatch(isFrom(Ime1Constants.CLASS).and(isType(ON_BIND_INPUT))),
+ TIMEOUT, "CtsInputMethod1.onBindInput is called");
+
+ final long imeForceStopTime = SystemClock.uptimeMillis();
+ helper.shell(ShellCommandUtils.uninstallPackage(Ime1Constants.PACKAGE));
+
+ helper.shell(ShellCommandUtils.setCurrentIme(Ime2Constants.IME_ID));
+ helper.findUiObject(R.id.text_entry).click();
+ pollingCheck(() -> helper.queryAllEvents()
+ .filter(isNewerThan(imeForceStopTime))
+ .anyMatch(isFrom(Ime2Constants.CLASS).and(isType(ON_START_INPUT))),
+ TIMEOUT, "CtsInputMethod2.onStartInput is called");
+ pollingCheck(() -> helper.queryAllEvents()
+ .filter(isNewerThan(imeForceStopTime))
+ .anyMatch(isFrom(Ime2Constants.CLASS).and(isType(ON_BIND_INPUT))),
+ TIMEOUT, "CtsInputMethod2.onBindInput is called");
+ }
+
+ @Test
+ public void testInputUnbindsOnAppStopped() throws Throwable {
+ final TestHelper helper = new TestHelper(
+ getClass(), DeviceTestConstants.TEST_INPUT_UNBINDS_ON_APP_STOPPED);
+ final long startActivityTime = SystemClock.uptimeMillis();
+ helper.launchActivity(EditTextAppConstants.PACKAGE, EditTextAppConstants.CLASS);
+
+ pollingCheck(() -> helper.queryAllEvents()
+ .filter(isNewerThan(startActivityTime))
+ .anyMatch(isFrom(Ime1Constants.CLASS).and(isType(ON_START_INPUT))),
+ TIMEOUT, "CtsInputMethod1.onStartInput is called");
+ pollingCheck(() -> helper.queryAllEvents()
+ .filter(isNewerThan(startActivityTime))
+ .anyMatch(isFrom(Ime1Constants.CLASS).and(isType(ON_BIND_INPUT))),
+ TIMEOUT, "CtsInputMethod1.onBindInput is called");
+
+ helper.shell(ShellCommandUtils.uninstallPackage(EditTextAppConstants.PACKAGE));
+
+ pollingCheck(() -> helper.queryAllEvents()
+ .filter(isNewerThan(startActivityTime))
+ .anyMatch(isFrom(Ime1Constants.CLASS).and(isType(ON_UNBIND_INPUT))),
+ TIMEOUT, "CtsInputMethod1.onUnBindInput is called");
+ }
+
/**
* Build stream collector of {@link DeviceEvent} collecting sequence that elements have
* specified types.
diff --git a/hostsidetests/inputmethodservice/deviceside/edittextapp/Android.mk b/hostsidetests/inputmethodservice/deviceside/edittextapp/Android.mk
new file mode 100644
index 0000000..96e4e8c
--- /dev/null
+++ b/hostsidetests/inputmethodservice/deviceside/edittextapp/Android.mk
@@ -0,0 +1,41 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_JAVA_RESOURCE_DIR := res
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ CtsInputMethodServiceCommon \
+ CtsInputMethodServiceLib
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+LOCAL_PACKAGE_NAME := EditTextApp
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/inputmethodservice/deviceside/edittextapp/AndroidManifest.xml b/hostsidetests/inputmethodservice/deviceside/edittextapp/AndroidManifest.xml
new file mode 100755
index 0000000..e88ec8e
--- /dev/null
+++ b/hostsidetests/inputmethodservice/deviceside/edittextapp/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.inputmethodservice.cts.edittextapp">
+ <application
+ android:label="@string/app_name">
+ <activity
+ android:name=".MainActivity"
+ android:exported="true"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.inputmethodservice.cts.edittextapp" />
+</manifest>
diff --git a/hostsidetests/inputmethodservice/deviceside/edittextapp/res/layout/activity_inputmethod_test.xml b/hostsidetests/inputmethodservice/deviceside/edittextapp/res/layout/activity_inputmethod_test.xml
new file mode 100644
index 0000000..5c7091a
--- /dev/null
+++ b/hostsidetests/inputmethodservice/deviceside/edittextapp/res/layout/activity_inputmethod_test.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:padding="10px">
+
+ <EditText
+ android:id="@+id/edit_text_entry"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:background="@android:drawable/editbox_background">
+ <requestFocus />
+ </EditText>
+
+</RelativeLayout>
diff --git a/hostsidetests/inputmethodservice/deviceside/edittextapp/res/values/strings.xml b/hostsidetests/inputmethodservice/deviceside/edittextapp/res/values/strings.xml
new file mode 100644
index 0000000..091901d
--- /dev/null
+++ b/hostsidetests/inputmethodservice/deviceside/edittextapp/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="app_name" translatable="false">EditTextApp</string>
+</resources>
\ No newline at end of file
diff --git a/hostsidetests/inputmethodservice/deviceside/edittextapp/src/android/inputmethodservice/cts/edittextapp/MainActivity.java b/hostsidetests/inputmethodservice/deviceside/edittextapp/src/android/inputmethodservice/cts/edittextapp/MainActivity.java
new file mode 100644
index 0000000..86e9e0a
--- /dev/null
+++ b/hostsidetests/inputmethodservice/deviceside/edittextapp/src/android/inputmethodservice/cts/edittextapp/MainActivity.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package android.inputmethodservice.cts.edittextapp;
+
+import android.app.Activity;
+import android.content.Context;
+import android.widget.EditText;
+import android.os.Bundle;
+import android.view.inputmethod.InputMethodManager;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+
+public class MainActivity extends Activity {
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_inputmethod_test);
+ }
+}
\ No newline at end of file
diff --git a/hostsidetests/inputmethodservice/deviceside/lib/src/android/inputmethodservice/cts/ime/CtsBaseInputMethod.java b/hostsidetests/inputmethodservice/deviceside/lib/src/android/inputmethodservice/cts/ime/CtsBaseInputMethod.java
index 6ae3568..7896b6e 100644
--- a/hostsidetests/inputmethodservice/deviceside/lib/src/android/inputmethodservice/cts/ime/CtsBaseInputMethod.java
+++ b/hostsidetests/inputmethodservice/deviceside/lib/src/android/inputmethodservice/cts/ime/CtsBaseInputMethod.java
@@ -16,6 +16,8 @@
package android.inputmethodservice.cts.ime;
+import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType
+ .ON_BIND_INPUT;
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_FINISH_INPUT;
@@ -23,6 +25,10 @@
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.DeviceEventConstants.DeviceEventType
+ .ON_UNBIND_INPUT;
+
import android.content.Intent;
import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.cts.DeviceEvent;
@@ -44,7 +50,7 @@
@Override
public void onCreate() {
- mLogTag = getClass().getSimpleName();
+ mLogTag = "CtsBaseInputMethod";//getClass().getSimpleName();
if (DEBUG) {
Log.d(mLogTag, "onCreate:");
}
@@ -56,6 +62,15 @@
}
@Override
+ public void onBindInput() {
+ if (DEBUG) {
+ Log.d(mLogTag, "onBindInput");
+ }
+ sendEvent(ON_BIND_INPUT);
+ super.onBindInput();
+ }
+
+ @Override
public void onStartInput(EditorInfo editorInfo, boolean restarting) {
if (DEBUG) {
Log.d(mLogTag, "onStartInput:"
@@ -80,6 +95,15 @@
}
@Override
+ public void onUnbindInput() {
+ super.onUnbindInput();
+ if (DEBUG) {
+ Log.d(mLogTag, "onUnbindInput");
+ }
+ sendEvent(ON_UNBIND_INPUT);
+ }
+
+ @Override
public void onFinishInputView(boolean finishingInput) {
if (DEBUG) {
Log.d(mLogTag, "onFinishInputView: finishingInput=" + finishingInput);
diff --git a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java
index 2e8a8b0..8badded 100644
--- a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java
+++ b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java
@@ -25,6 +25,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
+import android.inputmethodservice.cts.common.EditTextAppConstants;
import android.inputmethodservice.cts.common.EventProviderConstants.EventTableConstants;
import android.inputmethodservice.cts.common.Ime1Constants;
import android.inputmethodservice.cts.common.Ime2Constants;
@@ -151,6 +152,35 @@
assertTrue(runDeviceTestMethod(testSwitchInputs));
}
+ @Test
+ public void testInputUnbindsOnImeStopped() throws Exception {
+ final TestInfo testUnbind = new TestInfo(
+ DeviceTestConstants.PACKAGE, DeviceTestConstants.TEST_CLASS,
+ DeviceTestConstants.TEST_INPUT_UNBINDS_ON_IME_STOPPED);
+ sendTestStartEvent(testUnbind);
+ installPackage(Ime1Constants.APK, "-r");
+ installPackage(Ime2Constants.APK, "-r");
+ shell(ShellCommandUtils.enableIme(Ime1Constants.IME_ID));
+ shell(ShellCommandUtils.enableIme(Ime2Constants.IME_ID));
+ shell(ShellCommandUtils.setCurrentIme(Ime1Constants.IME_ID));
+
+ assertTrue(runDeviceTestMethod(testUnbind));
+ }
+
+ @Test
+ public void testInputUnbindsOnAppStop() throws Exception {
+ final TestInfo testUnbind = new TestInfo(
+ DeviceTestConstants.PACKAGE, DeviceTestConstants.TEST_CLASS,
+ DeviceTestConstants.TEST_INPUT_UNBINDS_ON_APP_STOPPED);
+ sendTestStartEvent(testUnbind);
+ installPackage(Ime1Constants.APK, "-r");
+ installPackage(EditTextAppConstants.APK, "-r");
+ shell(ShellCommandUtils.enableIme(Ime1Constants.IME_ID));
+ shell(ShellCommandUtils.setCurrentIme(Ime1Constants.IME_ID));
+
+ assertTrue(runDeviceTestMethod(testUnbind));
+ }
+
private void sendTestStartEvent(final TestInfo deviceTest) throws Exception {
final String sender = deviceTest.getTestName();
// {@link EventType#EXTRA_EVENT_TIME} will be recorded at device side.
diff --git a/hostsidetests/jvmti/attaching/app/jni/Android.mk b/hostsidetests/jvmti/attaching/app/jni/Android.mk
index 554fccf..a2c1db6 100644
--- a/hostsidetests/jvmti/attaching/app/jni/Android.mk
+++ b/hostsidetests/jvmti/attaching/app/jni/Android.mk
@@ -27,14 +27,15 @@
LOCAL_HEADER_LIBRARIES := libopenjdkjvmti_headers
LOCAL_SHARED_LIBRARIES := liblog \
- libdl
+ libdl \
+ libz
# The test implementation. We get this provided by ART.
# Note: Needs to be "whole" as this exposes JNI functions.
LOCAL_WHOLE_STATIC_LIBRARIES := libctstiagent
# Platform libraries that may not be available to apps. Link in statically.
-LOCAL_STATIC_LIBRARIES += libbase libcutils libutils
+LOCAL_STATIC_LIBRARIES += libbase_ndk
LOCAL_STRIP_MODULE := keep_symbols
@@ -58,6 +59,7 @@
-g \
-O0 \
-LOCAL_CXX_STL := libc++_static
+LOCAL_SDK_VERSION := current
+LOCAL_NDK_STL_VARIANT := c++_static
include $(BUILD_SHARED_LIBRARY)
diff --git a/hostsidetests/jvmti/base/jni/Android.mk b/hostsidetests/jvmti/base/jni/Android.mk
index 0ed5327..8ecf315 100644
--- a/hostsidetests/jvmti/base/jni/Android.mk
+++ b/hostsidetests/jvmti/base/jni/Android.mk
@@ -36,14 +36,15 @@
LOCAL_HEADER_LIBRARIES := libopenjdkjvmti_headers
LOCAL_SHARED_LIBRARIES := liblog \
- libdl
+ libdl \
+ libz
# The test implementation. We get this provided by ART.
# Note: Needs to be "whole" as this exposes JNI functions.
LOCAL_WHOLE_STATIC_LIBRARIES := libctstiagent
# Platform libraries that may not be available to apps. Link in statically.
-LOCAL_STATIC_LIBRARIES += libbase libcutils libutils
+LOCAL_STATIC_LIBRARIES += libbase_ndk
LOCAL_STRIP_MODULE := keep_symbols
@@ -67,6 +68,7 @@
-g \
-O0 \
-LOCAL_CXX_STL := libc++_static
+LOCAL_SDK_VERSION := current
+LOCAL_NDK_STL_VARIANT := c++_static
include $(BUILD_SHARED_LIBRARY)
diff --git a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/Android.mk
index 9d0d001..e4189b1 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/Android.mk
@@ -29,6 +29,7 @@
LOCAL_RES_LIBRARIES := CtsStaticSharedLibProviderApp1
LOCAL_PACKAGE_NAME := CtsStaticSharedLibConsumerApp1
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp2/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp2/Android.mk
index 0c7351a..83bd2b0 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp2/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp2/Android.mk
@@ -26,6 +26,7 @@
LOCAL_RES_LIBRARIES := CtsStaticSharedLibProviderApp4
LOCAL_PACKAGE_NAME := CtsStaticSharedLibConsumerApp2
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp3/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp3/Android.mk
index 71f9e8c..8d3a6d2 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp3/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp3/Android.mk
@@ -26,6 +26,7 @@
LOCAL_RES_LIBRARIES := CtsStaticSharedLibProviderApp7
LOCAL_PACKAGE_NAME := CtsStaticSharedLibConsumerApp3
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/os/test-apps/StaticSharedLibProviderApp1/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibProviderApp1/Android.mk
index 2e2a5e4..38ccf69 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibProviderApp1/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibProviderApp1/Android.mk
@@ -23,6 +23,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsStaticSharedLibProviderApp1
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
diff --git a/hostsidetests/os/test-apps/StaticSharedLibProviderApp3/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibProviderApp3/Android.mk
index 61adc17..16af99a 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibProviderApp3/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibProviderApp3/Android.mk
@@ -20,6 +20,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := CtsStaticSharedLibProviderApp3
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
diff --git a/hostsidetests/os/test-apps/StaticSharedLibProviderApp4/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibProviderApp4/Android.mk
index 0205259..e2c69f2 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibProviderApp4/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibProviderApp4/Android.mk
@@ -22,6 +22,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsStaticSharedLibProviderApp4
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
diff --git a/hostsidetests/os/test-apps/StaticSharedLibProviderApp7/Android.mk b/hostsidetests/os/test-apps/StaticSharedLibProviderApp7/Android.mk
index 074cae3..4ed03f4 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibProviderApp7/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedLibProviderApp7/Android.mk
@@ -23,6 +23,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsStaticSharedLibProviderApp7
+LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
diff --git a/hostsidetests/os/test-apps/StaticSharedNativeLibConsumer/Android.mk b/hostsidetests/os/test-apps/StaticSharedNativeLibConsumer/Android.mk
index 54ebdd1..1aed785 100644
--- a/hostsidetests/os/test-apps/StaticSharedNativeLibConsumer/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedNativeLibConsumer/Android.mk
@@ -28,6 +28,7 @@
LOCAL_JNI_SHARED_LIBRARIES := libstaticsharednativelibconsumerjni
LOCAL_PACKAGE_NAME := CtsStaticSharedNativeLibConsumer
+LOCAL_SDK_VERSION := current
LOCAL_MULTILIB := both
diff --git a/hostsidetests/os/test-apps/StaticSharedNativeLibProvider/Android.mk b/hostsidetests/os/test-apps/StaticSharedNativeLibProvider/Android.mk
index 3d48af2..b469eac 100644
--- a/hostsidetests/os/test-apps/StaticSharedNativeLibProvider/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedNativeLibProvider/Android.mk
@@ -23,6 +23,7 @@
LOCAL_JNI_SHARED_LIBRARIES := libstaticsharednativelibprovider
LOCAL_PACKAGE_NAME := CtsStaticSharedNativeLibProvider
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/os/test-apps/StaticSharedNativeLibProvider1/Android.mk b/hostsidetests/os/test-apps/StaticSharedNativeLibProvider1/Android.mk
index fee38a7..ff8ef3a 100644
--- a/hostsidetests/os/test-apps/StaticSharedNativeLibProvider1/Android.mk
+++ b/hostsidetests/os/test-apps/StaticSharedNativeLibProvider1/Android.mk
@@ -23,6 +23,7 @@
LOCAL_JNI_SHARED_LIBRARIES := libstaticsharednativelibprovider
LOCAL_PACKAGE_NAME := CtsStaticSharedNativeLibProvider1
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/statsd/apps/statsdapp/Android.mk b/hostsidetests/statsd/apps/statsdapp/Android.mk
index 9e5890a..ec4b86a 100644
--- a/hostsidetests/statsd/apps/statsdapp/Android.mk
+++ b/hostsidetests/statsd/apps/statsdapp/Android.mk
@@ -16,7 +16,8 @@
include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsStatsdAtomsApp
+LOCAL_PACKAGE_NAME := CtsStatsdApp
+LOCAL_PRIVATE_PLATFORM_APIS := true
# don't include this package in any target
LOCAL_MODULE_TAGS := optional
diff --git a/hostsidetests/statsd/apps/statsdapp/AndroidManifest.xml b/hostsidetests/statsd/apps/statsdapp/AndroidManifest.xml
index 8f23cd9..04c8c08 100644
--- a/hostsidetests/statsd/apps/statsdapp/AndroidManifest.xml
+++ b/hostsidetests/statsd/apps/statsdapp/AndroidManifest.xml
@@ -43,6 +43,9 @@
<activity
android:name=".VideoPlayerActivity"
android:label="@string/app_name"
+ android:resizeableActivity="true"
+ android:supportsPictureInPicture="true"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/hostsidetests/statsd/apps/statsdapp/AndroidTest.xml b/hostsidetests/statsd/apps/statsdapp/AndroidTest.xml
deleted file mode 100644
index 402a73b..0000000
--- a/hostsidetests/statsd/apps/statsdapp/AndroidTest.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
--->
-<configuration description="Config for CTS Statsd test cases">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="misc" />
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="CtsStatsdAtomsApp.apk" />
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="pm grant com.android.server.cts.device.statsd android.permission.DUMP" />
- <option name="teardown-command" value="pm revoke com.android.server.cts.device.statsd android.permission.DUMP"/>
- </target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="com.android.server.cts.device.statsd" />
- <option name="runtime-hint" value="1m" />
- </test>
-</configuration>
\ No newline at end of file
diff --git a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/VideoPlayerActivity.java b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/VideoPlayerActivity.java
index b15ec35..ea1fcec 100644
--- a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/VideoPlayerActivity.java
+++ b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/VideoPlayerActivity.java
@@ -17,19 +17,71 @@
package com.android.server.cts.device.statsd;
import android.app.Activity;
+import android.content.Intent;
+import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.Log;
import android.widget.VideoView;
public class VideoPlayerActivity extends Activity {
- /** Called when the activity is first created. */
+ private static final String TAG = VideoPlayerActivity.class.getSimpleName();
+
+ public static final String KEY_ACTION = "action";
+ public static final String ACTION_PLAY_VIDEO = "action.play_video";
+ public static final String ACTION_PLAY_VIDEO_PICTURE_IN_PICTURE_MODE =
+ "action.play_video_picture_in_picture_mode";
+
+ public static final int DELAY_MILLIS = 2000;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ Intent intent = this.getIntent();
+ if (intent == null) {
+ Log.e(TAG, "Intent was null.");
+ finish();
+ }
+
+ String action = intent.getStringExtra(KEY_ACTION);
+ Log.i(TAG, "Starting " + action + " from foreground activity.");
+
+ switch (action) {
+ case ACTION_PLAY_VIDEO:
+ playVideo();
+ break;
+ case ACTION_PLAY_VIDEO_PICTURE_IN_PICTURE_MODE:
+ playVideo();
+ this.enterPictureInPictureMode();
+ break;
+ default:
+ Log.e(TAG, "Intent had invalid action " + action);
+ finish();
+ }
+ delay();
+ }
+
+ private void playVideo() {
setContentView(R.layout.activity_main);
VideoView videoView = (VideoView)findViewById(R.id.video_player_view);
videoView.setVideoPath("android.resource://" + getPackageName() + "/" + R.raw.colors_video);
videoView.start();
}
+
+ private void delay() {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ SystemClock.sleep(DELAY_MILLIS);
+ return null;
+ }
+ @Override
+ protected void onPostExecute(Void nothing) {
+ finish();
+ }
+ }.execute();
+ }
}
diff --git a/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java b/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java
index 25cb53d..dc2da39 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java
@@ -47,6 +47,8 @@
private static final boolean TESTS_ENABLED = false;
private static final boolean INCIDENTD_TESTS_ENABLED = true;
+ private static final int WAIT_AFTER_BREADCRUMB_MS = 2000;
+
// Config constants
private static final int APP_BREADCRUMB_REPORTED_MATCH_START_ID = 1;
private static final int APP_BREADCRUMB_REPORTED_MATCH_STOP_ID = 2;
@@ -109,7 +111,7 @@
if (INCIDENTD_TESTS_ENABLED) assertFalse("Incident", didIncidentdFireSince(markTime));
doAppBreadcrumbReportedStart(6); // count(label=6) -> 3 (anomaly, since "greater than 2"!)
- Thread.sleep(1000);
+ Thread.sleep(WAIT_AFTER_BREADCRUMB_MS);
List<EventMetricData> data = getEventMetricDataList();
assertEquals("Expected 1 anomaly", 1, data.size());
@@ -260,12 +262,12 @@
String markTime = getCurrentLogcatDate();
doAppBreadcrumbReportedStart(6); // value = 6, which is NOT > trigger
- Thread.sleep(2000);
+ Thread.sleep(WAIT_AFTER_BREADCRUMB_MS);
assertEquals("Premature anomaly", 0, getEventMetricDataList().size());
if (INCIDENTD_TESTS_ENABLED) assertFalse("Incident", didIncidentdFireSince(markTime));
doAppBreadcrumbReportedStart(14); // value = 14 > trigger
- Thread.sleep(2000);
+ Thread.sleep(WAIT_AFTER_BREADCRUMB_MS);
List<EventMetricData> data = getEventMetricDataList();
assertEquals("Expected 1 anomaly", 1, data.size());
@@ -274,42 +276,40 @@
if (INCIDENTD_TESTS_ENABLED) assertTrue("No incident", didIncidentdFireSince(markTime));
}
- // TODO: Removed until b/73091354 is solved, since it keeps crashing statsd. Update CTS later.
// Tests that anomaly detection for gauge works.
-// public void testGaugeAnomalyDetection() throws Exception {
-// if (!TESTS_ENABLED) return;
-// StatsdConfig.Builder config = getBaseConfig(1, 20, 6)
-// .addGaugeMetric(GaugeMetric.newBuilder()
-// .setId(METRIC_ID)
-// .setWhat(APP_BREADCRUMB_REPORTED_MATCH_START_ID)
-// .setBucket(TimeUnit.ONE_MINUTE)
-// // Get the label field's value into the gauge:
-// .setGaugeFieldsFilter(
-// FieldFilter.newBuilder().setFields(FieldMatcher.newBuilder()
-// .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
-// .addChild(FieldMatcher.newBuilder()
-// .setField(AppBreadcrumbReported
-// .LABEL_FIELD_NUMBER))
-// )
-// )
-// );
-// uploadConfig(config);
-//
-// String markTime = getCurrentLogcatDate();
-// doAppBreadcrumbReportedStart(6); // gauge = 6, which is NOT > trigger
-// Thread.sleep(2000);
-// assertEquals("Premature anomaly", 0, getEventMetricDataList().size());
-// if (INCIDENTD_TESTS_ENABLED) assertFalse("Incident", didIncidentdFireSince(markTime));
-//
-// doAppBreadcrumbReportedStart(14); // gauge = 6+1 > trigger
-// Thread.sleep(2000);
-//
-// List<EventMetricData> data = getEventMetricDataList();
-// assertEquals("Expected 1 anomaly", 1, data.size());
-// AnomalyDetected a = data.get(0).getAtom().getAnomalyDetected();
-// assertEquals("Wrong alert_id", ALERT_ID, a.getAlertId());
-// if (INCIDENTD_TESTS_ENABLED) assertTrue("No incident", didIncidentdFireSince(markTime));
-// }
+ public void testGaugeAnomalyDetection() throws Exception {
+ StatsdConfig.Builder config = getBaseConfig(1, 20, 6 /* threshold: value > 6 */)
+ .addGaugeMetric(GaugeMetric.newBuilder()
+ .setId(METRIC_ID)
+ .setWhat(APP_BREADCRUMB_REPORTED_MATCH_START_ID)
+ .setBucket(TimeUnit.CTS)
+ // Get the label field's value into the gauge:
+ .setGaugeFieldsFilter(
+ FieldFilter.newBuilder().setFields(FieldMatcher.newBuilder()
+ .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
+ .addChild(FieldMatcher.newBuilder()
+ .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER))
+ )
+ )
+ );
+ uploadConfig(config);
+
+ String markTime = getCurrentLogcatDate();
+ doAppBreadcrumbReportedStart(6); // gauge = 6, which is NOT > trigger
+ Thread.sleep(Math.max(WAIT_AFTER_BREADCRUMB_MS, 1_100)); // Must be >1s to push next bucket.
+ assertEquals("Premature anomaly", 0, getEventMetricDataList().size());
+ if (INCIDENTD_TESTS_ENABLED) assertFalse("Incident", didIncidentdFireSince(markTime));
+
+ // We waited for >1s above, so we are now in the next bucket (which is essential).
+ doAppBreadcrumbReportedStart(14); // gauge = 14 > trigger
+ Thread.sleep(WAIT_AFTER_BREADCRUMB_MS);
+
+ List<EventMetricData> data = getEventMetricDataList();
+ assertEquals("Expected 1 anomaly", 1, data.size());
+ AnomalyDetected a = data.get(0).getAtom().getAnomalyDetected();
+ assertEquals("Wrong alert_id", ALERT_ID, a.getAlertId());
+ if (INCIDENTD_TESTS_ENABLED) assertTrue("No incident", didIncidentdFireSince(markTime));
+ }
private final StatsdConfig.Builder getBaseConfig(int numBuckets,
int refractorySecs,
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
index 7f68c63..a067f9d 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
@@ -504,45 +504,6 @@
getDevice().rebootUntilOnline();
}
- protected void assertScreenOff() throws Exception {
- final long deadLine = System.currentTimeMillis() + SCREEN_STATE_CHANGE_TIMEOUT;
- boolean screenAwake = true;
- do {
- final String dumpsysPower = getDevice().executeShellCommand("dumpsys power").trim();
- for (String line : dumpsysPower.split("\n")) {
- if (line.contains("Display Power")) {
- screenAwake = line.trim().endsWith("ON");
- break;
- }
- }
- Thread.sleep(SCREEN_STATE_POLLING_INTERVAL);
- } while (screenAwake && System.currentTimeMillis() < deadLine);
- assertFalse("Screen could not be turned off", screenAwake);
- }
-
- protected void assertScreenOn() throws Exception {
- // this also checks that the keyguard is dismissed
- final long deadLine = System.currentTimeMillis() + SCREEN_STATE_CHANGE_TIMEOUT;
- boolean screenAwake;
- do {
- final String dumpsysWindowPolicy =
- getDevice().executeShellCommand("dumpsys window policy").trim();
- boolean keyguardStateLines = false;
- screenAwake = true;
- for (String line : dumpsysWindowPolicy.split("\n")) {
- if (line.contains("KeyguardServiceDelegate")) {
- keyguardStateLines = true;
- } else if (keyguardStateLines && line.contains("showing=")) {
- screenAwake &= line.trim().endsWith("false");
- } else if (keyguardStateLines && line.contains("screenState=")) {
- screenAwake &= line.trim().endsWith("SCREEN_STATE_ON");
- }
- }
- Thread.sleep(SCREEN_STATE_POLLING_INTERVAL);
- } while (!screenAwake && System.currentTimeMillis() < deadLine);
- assertTrue("Screen could not be turned on", screenAwake);
- }
-
/**
* Asserts that the two events are within the specified range of each other.
*
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/DeviceAtomTestCase.java b/hostsidetests/statsd/src/android/cts/statsd/atom/DeviceAtomTestCase.java
index 0ee2c0d..27a4bc6 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/DeviceAtomTestCase.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/DeviceAtomTestCase.java
@@ -30,7 +30,7 @@
*/
public class DeviceAtomTestCase extends AtomTestCase {
- protected static final String DEVICE_SIDE_TEST_APK = "CtsStatsdAtomsApp.apk";
+ protected static final String DEVICE_SIDE_TEST_APK = "CtsStatsdApp.apk";
protected static final String DEVICE_SIDE_TEST_PACKAGE
= "com.android.server.cts.device.statsd";
@@ -164,6 +164,7 @@
*/
protected void installTestApp() throws Exception {
installPackage(DEVICE_SIDE_TEST_APK, true);
+ LogUtil.CLog.i("Installing device-side test app with uid " + getUid());
allowBackgroundServices();
}
@@ -178,10 +179,21 @@
/**
* Runs the specified activity for WAIT_TME_LONG.
*/
- protected void runActivity(String activity) throws Exception {
+ protected void runActivity(String activity, String actionKey, String actionValue)
+ throws Exception {
+ String intentString = null;
+ if (actionKey != null && actionValue != null) {
+ intentString = actionKey + " " + actionValue;
+ }
turnScreenOn();
- getDevice().executeShellCommand(
- "am start -n " + DEVICE_SIDE_TEST_PACKAGE + "/." + activity);
+ if (intentString == null) {
+ getDevice().executeShellCommand(
+ "am start -n " + DEVICE_SIDE_TEST_PACKAGE + "/." + activity);
+ } else {
+ getDevice().executeShellCommand(
+ "am start -n " + DEVICE_SIDE_TEST_PACKAGE + "/." + activity + " -e " +
+ intentString);
+ }
Thread.sleep(WAIT_TIME_LONG);
getDevice().executeShellCommand(
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/ProcStateAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/ProcStateAtomTests.java
index 3052937..fdebaa5 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/ProcStateAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/ProcStateAtomTests.java
@@ -143,16 +143,14 @@
Thread.sleep(WAIT_TIME_FOR_CONFIG_UPDATE_MS);
turnScreenOn();
- assertScreenOn();
executeForegroundActivity(ACTION_SHOW_APPLICATION_OVERLAY);
- final int waitTime = 2 * EXTRA_WAIT_TIME_MS;
+ final int waitTime = EXTRA_WAIT_TIME_MS + 5_000; // Overlay may need to sit there a while.
Thread.sleep(waitTime + STATSD_REPORT_WAIT_TIME_MS);
+ turnScreenOff();
List<EventMetricData> data = getEventMetricDataList();
popUntilFind(data, onStates, PROC_STATE_FUNCTION); // clear out initial proc states.
assertStatesOccurred(stateSet, data, 0, PROC_STATE_FUNCTION);
-
- turnScreenOff();
}
public void testBackground() throws Exception {
@@ -184,10 +182,10 @@
Thread.sleep(WAIT_TIME_FOR_CONFIG_UPDATE_MS);
turnScreenOn();
- assertScreenOn();
executeForegroundActivity(ACTION_SLEEP_WHILE_TOP);
final int waitTime = SLEEP_OF_ACTION_SLEEP_WHILE_TOP + EXTRA_WAIT_TIME_MS;
Thread.sleep(waitTime + STATSD_REPORT_WAIT_TIME_MS);
+ turnScreenOff();
List<EventMetricData> data = getEventMetricDataList();
popUntilFind(data, onStates, PROC_STATE_FUNCTION); // clear out initial proc states.
@@ -205,11 +203,9 @@
Thread.sleep(WAIT_TIME_FOR_CONFIG_UPDATE_MS);
turnScreenOn();
- assertScreenOn();
executeForegroundActivity(ACTION_SLEEP_WHILE_TOP);
// ASAP, turn off the screen to make proc state -> top_sleeping.
turnScreenOff();
- assertScreenOff();
final int waitTime = SLEEP_OF_ACTION_SLEEP_WHILE_TOP + EXTRA_WAIT_TIME_MS;
Thread.sleep(waitTime + STATSD_REPORT_WAIT_TIME_MS);
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index 0a800f0..344ec44 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -15,6 +15,8 @@
*/
package android.cts.statsd.atom;
+import static org.junit.Assert.assertTrue;
+
import android.os.WakeLockLevelEnum;
import com.android.internal.os.StatsdConfigProto.FieldMatcher;
@@ -31,6 +33,7 @@
import com.android.os.AtomsProto.ForegroundServiceStateChanged;
import com.android.os.AtomsProto.GpsScanStateChanged;
import com.android.os.AtomsProto.MediaCodecActivityChanged;
+import com.android.os.AtomsProto.PictureInPictureStateChanged;
import com.android.os.AtomsProto.ScheduledJobStateChanged;
import com.android.os.AtomsProto.SyncStateChanged;
import com.android.os.AtomsProto.WakelockStateChanged;
@@ -45,6 +48,7 @@
import java.util.List;
import java.util.Set;
+
/**
* Statsd atom tests that are done via app, for atoms that report a uid.
*/
@@ -319,7 +323,7 @@
final int atomTag = Atom.DAVEY_OCCURRED_FIELD_NUMBER;
createAndUploadConfig(atomTag); // Does not have UID, but needs a device-side compnent.
- runActivity("DaveyActivity");
+ runActivity("DaveyActivity", null, null);
List<EventMetricData> data = getEventMetricDataList();
assertTrue(data.size() == 1);
@@ -548,7 +552,7 @@
createAndUploadConfig(atomTag, true); // True: uses attribution.
Thread.sleep(WAIT_TIME_SHORT);
- runActivity("VideoPlayerActivity");
+ runActivity("VideoPlayerActivity", "action", "action.play_video");
// Sorted list of events in order in which they occurred.
List<EventMetricData> data = getEventMetricDataList();
@@ -557,4 +561,26 @@
assertStatesOccurred(stateSet, data, WAIT_TIME_LONG,
atom -> atom.getMediaCodecActivityChanged().getState().getNumber());
}
+
+ public void testPictureInPictureState() throws Exception {
+ if (!TESTS_ENABLED) return;
+ final int atomTag = Atom.PICTURE_IN_PICTURE_STATE_CHANGED_FIELD_NUMBER;
+
+ Set<Integer> entered = new HashSet<>(
+ Arrays.asList(PictureInPictureStateChanged.State.ENTERED_VALUE));
+
+ // Add state sets to the list in order.
+ List<Set<Integer>> stateSet = Arrays.asList(entered);
+
+ createAndUploadConfig(atomTag, false);
+
+ runActivity("VideoPlayerActivity", "action", "action.play_video_picture_in_picture_mode");
+
+ // Sorted list of events in order in which they occurred.
+ List<EventMetricData> data = getEventMetricDataList();
+
+ // Assert that the events happened in the expected order.
+ assertStatesOccurred(stateSet, data, WAIT_TIME_LONG,
+ atom -> atom.getPictureInPictureStateChanged().getState().getNumber());
+ }
}
diff --git a/hostsidetests/statsd/src/android/cts/statsd/metric/DurationMetricsTests.java b/hostsidetests/statsd/src/android/cts/statsd/metric/DurationMetricsTests.java
index 0bb333f..1969e5b 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/metric/DurationMetricsTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/metric/DurationMetricsTests.java
@@ -44,8 +44,10 @@
public void testDurationMetric() throws Exception {
// Add AtomMatcher's.
- AtomMatcher startAtomMatcher = startAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID);
- AtomMatcher stopAtomMatcher = stopAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID);
+ AtomMatcher startAtomMatcher =
+ MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID);
+ AtomMatcher stopAtomMatcher =
+ MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID);
StatsdConfigProto.StatsdConfig.Builder builder = MetricsUtils.getEmptyConfig();
builder.addAtomMatcher(startAtomMatcher);
@@ -57,15 +59,16 @@
.setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID)
.build();
Predicate predicate = Predicate.newBuilder()
- .setId(StringToId("Predicate"))
- .setSimplePredicate(simplePredicate)
- .build();
+ .setId(MetricsUtils.StringToId("Predicate"))
+ .setSimplePredicate(simplePredicate)
+ .build();
builder.addPredicate(predicate);
// Add DurationMetric.
- builder.addDurationMetric(StatsdConfigProto.DurationMetric.newBuilder()
+ builder.addDurationMetric(
+ StatsdConfigProto.DurationMetric.newBuilder()
.setId(MetricsUtils.DURATION_METRIC_ID)
- .setWhat(StringToId("Predicate"))
+ .setWhat(predicate.getId())
.setAggregationType(StatsdConfigProto.DurationMetric.AggregationType.SUM)
.setBucket(StatsdConfigProto.TimeUnit.CTS));
@@ -92,10 +95,14 @@
public void testDurationMetricWithDimension() throws Exception {
// Add AtomMatcher's.
- AtomMatcher startAtomMatcherA = startAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID);
- AtomMatcher stopAtomMatcherA = stopAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID);
- AtomMatcher startAtomMatcherB = startAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID);
- AtomMatcher stopAtomMatcherB = stopAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID);
+ AtomMatcher startAtomMatcherA =
+ MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID);
+ AtomMatcher stopAtomMatcherA =
+ MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID);
+ AtomMatcher startAtomMatcherB =
+ MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID);
+ AtomMatcher stopAtomMatcherB =
+ MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID);
StatsdConfigProto.StatsdConfig.Builder builder = MetricsUtils.getEmptyConfig();
builder.addAtomMatcher(startAtomMatcherA);
@@ -109,9 +116,9 @@
.setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID)
.build();
Predicate predicateA = Predicate.newBuilder()
- .setId(StringToId("Predicate_A"))
- .setSimplePredicate(simplePredicateA)
- .build();
+ .setId(MetricsUtils.StringToId("Predicate_A"))
+ .setSimplePredicate(simplePredicateA)
+ .build();
builder.addPredicate(predicateA);
FieldMatcher.Builder dimensionsBuilder = FieldMatcher.newBuilder()
@@ -121,30 +128,33 @@
.setPosition(Position.FIRST)
.addChild(FieldMatcher.newBuilder().setField(
AppBreadcrumbReported.LABEL_FIELD_NUMBER)));
- Predicate predicateB = Predicate.newBuilder()
- .setId(StringToId("Predicate_B"))
+ Predicate predicateB =
+ Predicate.newBuilder()
+ .setId(MetricsUtils.StringToId("Predicate_B"))
.setSimplePredicate(SimplePredicate.newBuilder()
- .setStart(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
- .setStop(APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID)
- .setDimensions(dimensionsBuilder.build())
- .build())
+ .setStart(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
+ .setStop(APP_BREADCRUMB_REPORTED_B_MATCH_STOP_ID)
+ .setDimensions(dimensionsBuilder.build())
+ .build())
.build();
builder.addPredicate(predicateB);
// Add DurationMetric.
- builder.addDurationMetric(StatsdConfigProto.DurationMetric.newBuilder()
+ builder.addDurationMetric(
+ StatsdConfigProto.DurationMetric.newBuilder()
.setId(MetricsUtils.DURATION_METRIC_ID)
- .setWhat(StringToId("Predicate_B"))
- .setCondition(StringToId("Predicate_A"))
+ .setWhat(predicateB.getId())
+ .setCondition(predicateA.getId())
.setAggregationType(StatsdConfigProto.DurationMetric.AggregationType.SUM)
.setBucket(StatsdConfigProto.TimeUnit.CTS)
- .setDimensionsInWhat(FieldMatcher.newBuilder()
+ .setDimensionsInWhat(
+ FieldMatcher.newBuilder()
.setField(Atom.BATTERY_SAVER_MODE_STATE_CHANGED_FIELD_NUMBER)
.addChild(FieldMatcher.newBuilder()
- .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
- .setPosition(Position.FIRST)
- .addChild(FieldMatcher.newBuilder().setField(
- AppBreadcrumbReported.LABEL_FIELD_NUMBER)))));
+ .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
+ .setPosition(Position.FIRST)
+ .addChild(FieldMatcher.newBuilder().setField(
+ AppBreadcrumbReported.LABEL_FIELD_NUMBER)))));
// Upload config.
uploadConfig(builder);
@@ -173,30 +183,4 @@
assertTrue(bucketInfo.getDurationNanos() < 1e10);
}
}
-
- private AtomMatcher startAtomMatcher(int id) {
- return AtomMatcher.newBuilder()
- .setId(id)
- .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
- .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
- .addFieldValueMatcher(FieldValueMatcher.newBuilder()
- .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
- .setEqInt(AppBreadcrumbReported.State.START.ordinal())))
- .build();
- }
-
- private AtomMatcher stopAtomMatcher(int id) {
- return AtomMatcher.newBuilder()
- .setId(id)
- .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
- .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
- .addFieldValueMatcher(FieldValueMatcher.newBuilder()
- .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
- .setEqInt(AppBreadcrumbReported.State.STOP.ordinal())))
- .build();
- }
-
- private long StringToId(String str) {
- return str.hashCode();
- }
}
diff --git a/hostsidetests/statsd/src/android/cts/statsd/metric/GaugeMetricsTests.java b/hostsidetests/statsd/src/android/cts/statsd/metric/GaugeMetricsTests.java
new file mode 100644
index 0000000..92b840e
--- /dev/null
+++ b/hostsidetests/statsd/src/android/cts/statsd/metric/GaugeMetricsTests.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.cts.statsd.metric;
+
+import android.cts.statsd.atom.DeviceAtomTestCase;
+
+import com.android.internal.os.StatsdConfigProto;
+import com.android.internal.os.StatsdConfigProto.AtomMatcher;
+import com.android.internal.os.StatsdConfigProto.FieldFilter;
+import com.android.internal.os.StatsdConfigProto.FieldMatcher;
+import com.android.internal.os.StatsdConfigProto.FieldValueMatcher;
+import com.android.internal.os.StatsdConfigProto.Predicate;
+import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
+import com.android.internal.os.StatsdConfigProto.SimplePredicate;
+import com.android.os.AtomsProto.AppBreadcrumbReported;
+import com.android.os.AtomsProto.Atom;
+import com.android.os.StatsLog.GaugeMetricData;
+import com.android.os.StatsLog.StatsLogReport;
+
+public class GaugeMetricsTests extends DeviceAtomTestCase {
+
+ private static final int APP_BREADCRUMB_REPORTED_A_MATCH_START_ID = 0;
+ private static final int APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID = 1;
+ private static final int APP_BREADCRUMB_REPORTED_B_MATCH_START_ID = 2;
+
+ public void testGaugeMetric() throws Exception {
+ // Add AtomMatcher's.
+ AtomMatcher startAtomMatcher =
+ MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID);
+ AtomMatcher stopAtomMatcher =
+ MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID);
+ AtomMatcher atomMatcher =
+ MetricsUtils.simpleAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID);
+
+ StatsdConfigProto.StatsdConfig.Builder builder = MetricsUtils.getEmptyConfig();
+ builder.addAtomMatcher(startAtomMatcher);
+ builder.addAtomMatcher(stopAtomMatcher);
+ builder.addAtomMatcher(atomMatcher);
+
+ // Add Predicate's.
+ SimplePredicate simplePredicate = SimplePredicate.newBuilder()
+ .setStart(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID)
+ .setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID)
+ .build();
+ Predicate predicate = Predicate.newBuilder()
+ .setId(MetricsUtils.StringToId("Predicate"))
+ .setSimplePredicate(simplePredicate)
+ .build();
+ builder.addPredicate(predicate);
+
+ // Add GaugeMetric.
+ FieldMatcher fieldMatcher =
+ FieldMatcher.newBuilder().setField(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID).build();
+ builder.addGaugeMetric(
+ StatsdConfigProto.GaugeMetric.newBuilder()
+ .setId(MetricsUtils.GAUGE_METRIC_ID)
+ .setWhat(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
+ .setCondition(predicate.getId())
+ .setGaugeFieldsFilter(
+ FieldFilter.newBuilder().setIncludeAll(false).setFields(fieldMatcher).build())
+ .setDimensionsInWhat(
+ FieldMatcher.newBuilder()
+ .setField(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
+ .addChild(FieldMatcher.newBuilder()
+ .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
+ .build())
+ .build())
+ .setBucket(StatsdConfigProto.TimeUnit.CTS)
+ .build());
+
+ // Upload config.
+ uploadConfig(builder);
+
+ // Create AppBreadcrumbReported Start/Stop events.
+ doAppBreadcrumbReportedStart(0);
+ Thread.sleep(10);
+ doAppBreadcrumbReportedStart(1);
+ Thread.sleep(10);
+ doAppBreadcrumbReportedStart(2);
+ Thread.sleep(2000);
+ doAppBreadcrumbReportedStop(2);
+ Thread.sleep(10);
+ doAppBreadcrumbReportedStop(0);
+ Thread.sleep(10);
+ doAppBreadcrumbReportedStop(1);
+ doAppBreadcrumbReportedStart(2);
+ Thread.sleep(10);
+ doAppBreadcrumbReportedStart(1);
+ Thread.sleep(2000);
+ doAppBreadcrumbReportedStop(2);
+ Thread.sleep(10);
+ doAppBreadcrumbReportedStop(1);
+
+ // Wait for the metrics to propagate to statsd.
+ Thread.sleep(2000);
+
+ StatsLogReport metricReport = getStatsLogReport();
+ assertEquals(MetricsUtils.GAUGE_METRIC_ID, metricReport.getMetricId());
+ assertTrue(metricReport.hasGaugeMetrics());
+ StatsLogReport.GaugeMetricDataWrapper gaugeData = metricReport.getGaugeMetrics();
+ assertEquals(gaugeData.getDataCount(), 1);
+
+ int bucketCount = gaugeData.getData(0).getBucketInfoCount();
+ GaugeMetricData data = gaugeData.getData(0);
+ assertTrue(bucketCount > 2);
+ assertTrue(data.getBucketInfo(0).hasStartBucketNanos());
+ assertTrue(data.getBucketInfo(0).hasEndBucketNanos());
+ assertEquals(data.getBucketInfo(0).getAtomCount(), 1);
+ assertEquals(data.getBucketInfo(0).getAtom(0).getAppBreadcrumbReported().getLabel(), 0);
+ assertEquals(data.getBucketInfo(0).getAtom(0).getAppBreadcrumbReported().getState(),
+ AppBreadcrumbReported.State.START);
+
+ assertTrue(data.getBucketInfo(1).hasStartBucketNanos());
+ assertTrue(data.getBucketInfo(1).hasEndBucketNanos());
+ assertEquals(data.getBucketInfo(1).getAtomCount(), 1);
+
+ assertTrue(data.getBucketInfo(bucketCount - 1).hasStartBucketNanos());
+ assertTrue(data.getBucketInfo(bucketCount - 1).hasEndBucketNanos());
+ assertEquals(data.getBucketInfo(bucketCount - 1).getAtomCount(), 1);
+ assertEquals(
+ data.getBucketInfo(bucketCount - 1).getAtom(0).getAppBreadcrumbReported().getLabel(), 2);
+ assertEquals(
+ data.getBucketInfo(bucketCount - 1).getAtom(0).getAppBreadcrumbReported().getState(),
+ AppBreadcrumbReported.State.STOP);
+ }
+}
diff --git a/hostsidetests/statsd/src/android/cts/statsd/metric/MetricsUtils.java b/hostsidetests/statsd/src/android/cts/statsd/metric/MetricsUtils.java
index e7b21a6..c5ef40c 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/metric/MetricsUtils.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/metric/MetricsUtils.java
@@ -17,11 +17,16 @@
import com.android.internal.os.StatsdConfigProto;
import com.android.internal.os.StatsdConfigProto.AtomMatcher;
+import com.android.internal.os.StatsdConfigProto.FieldValueMatcher;
import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
+import com.android.os.AtomsProto.Atom;
+import com.android.os.AtomsProto.AppBreadcrumbReported;
public class MetricsUtils {
public static final long COUNT_METRIC_ID = 3333;
public static final long DURATION_METRIC_ID = 4444;
+ public static final long GAUGE_METRIC_ID = 5555;
+ public static final long VALUE_METRIC_ID = 6666;
public static StatsdConfigProto.StatsdConfig.Builder getEmptyConfig() {
StatsdConfigProto.StatsdConfig.Builder builder =
@@ -38,4 +43,40 @@
.setAtomId(atomId).build());
return builder;
}
+
+ public static AtomMatcher startAtomMatcher(int id) {
+ return AtomMatcher.newBuilder()
+ .setId(id)
+ .setSimpleAtomMatcher(
+ SimpleAtomMatcher.newBuilder()
+ .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
+ .addFieldValueMatcher(FieldValueMatcher.newBuilder()
+ .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
+ .setEqInt(AppBreadcrumbReported.State.START.ordinal())))
+ .build();
+ }
+
+ public static AtomMatcher stopAtomMatcher(int id) {
+ return AtomMatcher.newBuilder()
+ .setId(id)
+ .setSimpleAtomMatcher(
+ SimpleAtomMatcher.newBuilder()
+ .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
+ .addFieldValueMatcher(FieldValueMatcher.newBuilder()
+ .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
+ .setEqInt(AppBreadcrumbReported.State.STOP.ordinal())))
+ .build();
+ }
+
+ public static AtomMatcher simpleAtomMatcher(int id) {
+ return AtomMatcher.newBuilder()
+ .setId(id)
+ .setSimpleAtomMatcher(
+ SimpleAtomMatcher.newBuilder().setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER))
+ .build();
+ }
+
+ public static long StringToId(String str) {
+ return str.hashCode();
+ }
}
diff --git a/hostsidetests/statsd/src/android/cts/statsd/metric/ValueMetricsTests.java b/hostsidetests/statsd/src/android/cts/statsd/metric/ValueMetricsTests.java
new file mode 100644
index 0000000..44b3a48
--- /dev/null
+++ b/hostsidetests/statsd/src/android/cts/statsd/metric/ValueMetricsTests.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.cts.statsd.metric;
+
+import android.cts.statsd.atom.DeviceAtomTestCase;
+
+import com.android.internal.os.StatsdConfigProto;
+import com.android.internal.os.StatsdConfigProto.AtomMatcher;
+import com.android.internal.os.StatsdConfigProto.FieldMatcher;
+import com.android.internal.os.StatsdConfigProto.ValueMetric;
+import com.android.os.AtomsProto.AppBreadcrumbReported;
+import com.android.os.AtomsProto.Atom;
+import com.android.os.StatsLog.ValueBucketInfo;
+import com.android.os.StatsLog.ValueMetricData;
+import com.android.os.StatsLog.StatsLogReport;
+
+public class ValueMetricsTests extends DeviceAtomTestCase {
+ private static final int APP_BREADCRUMB_REPORTED_A_MATCH_START_ID = 0;
+ private static final int APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID = 1;
+ private static final int APP_BREADCRUMB_REPORTED_B_MATCH_START_ID = 2;
+
+ public void testValueMetric() throws Exception {
+ // Add AtomMatcher's.
+ AtomMatcher startAtomMatcher =
+ MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID);
+ AtomMatcher stopAtomMatcher =
+ MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID);
+ AtomMatcher atomMatcher =
+ MetricsUtils.simpleAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID);
+
+ StatsdConfigProto.StatsdConfig.Builder builder = MetricsUtils.getEmptyConfig();
+ builder.addAtomMatcher(startAtomMatcher);
+ builder.addAtomMatcher(stopAtomMatcher);
+ builder.addAtomMatcher(atomMatcher);
+
+ // Add ValueMetric.
+ FieldMatcher fieldMatcher =
+ FieldMatcher.newBuilder().setField(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID).build();
+ builder.addValueMetric(
+ ValueMetric.newBuilder()
+ .setId(MetricsUtils.VALUE_METRIC_ID)
+ .setWhat(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
+ .setBucket(StatsdConfigProto.TimeUnit.CTS)
+ .setValueField(FieldMatcher.newBuilder()
+ .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
+ .addChild(FieldMatcher.newBuilder().setField(
+ AppBreadcrumbReported.LABEL_FIELD_NUMBER)))
+ .setDimensionsInWhat(FieldMatcher.newBuilder()
+ .setField(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
+ .build())
+ .build());
+
+ // Upload config.
+ uploadConfig(builder);
+
+ // Create AppBreadcrumbReported Start/Stop events.
+ doAppBreadcrumbReportedStart(1);
+ Thread.sleep(1000);
+ doAppBreadcrumbReportedStop(1);
+ doAppBreadcrumbReportedStart(3);
+ doAppBreadcrumbReportedStop(3);
+
+ // Wait for the metrics to propagate to statsd.
+ Thread.sleep(2000);
+
+ StatsLogReport metricReport = getStatsLogReport();
+ assertEquals(MetricsUtils.VALUE_METRIC_ID, metricReport.getMetricId());
+ assertTrue(metricReport.hasValueMetrics());
+ StatsLogReport.ValueMetricDataWrapper valueData = metricReport.getValueMetrics();
+ assertEquals(valueData.getDataCount(), 1);
+
+ int bucketCount = valueData.getData(0).getBucketInfoCount();
+ assertTrue(bucketCount > 1);
+ ValueMetricData data = valueData.getData(0);
+ int totalValue = 0;
+ for (ValueBucketInfo bucketInfo : data.getBucketInfoList()) {
+ assertTrue(bucketInfo.hasStartBucketElapsedNanos());
+ assertTrue(bucketInfo.hasEndBucketElapsedNanos());
+ totalValue += (int) bucketInfo.getValue();
+ }
+ assertEquals(totalValue, 8);
+ }
+}
diff --git a/tests/JobScheduler/Android.mk b/tests/JobScheduler/Android.mk
index 0ea7527..622c06e 100755
--- a/tests/JobScheduler/Android.mk
+++ b/tests/JobScheduler/Android.mk
@@ -36,6 +36,7 @@
LOCAL_PACKAGE_NAME := CtsJobSchedulerTestCases
#LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/JobScheduler/JobTestApp/Android.mk b/tests/JobScheduler/JobTestApp/Android.mk
index f7b7a1d..61f7116 100644
--- a/tests/JobScheduler/JobTestApp/Android.mk
+++ b/tests/JobScheduler/JobTestApp/Android.mk
@@ -26,5 +26,6 @@
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
LOCAL_PACKAGE_NAME := CtsJobTestApp
+LOCAL_SDK_VERSION := current
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/JobScheduler/jobperm/Android.mk b/tests/JobScheduler/jobperm/Android.mk
index f54f8d6..af892d9 100644
--- a/tests/JobScheduler/jobperm/Android.mk
+++ b/tests/JobScheduler/jobperm/Android.mk
@@ -29,5 +29,6 @@
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
LOCAL_PACKAGE_NAME := CtsJobSchedulerJobPerm
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/JobScheduler/shareduid/Android.mk b/tests/JobScheduler/shareduid/Android.mk
index ac4d8b3f..98a9707 100644
--- a/tests/JobScheduler/shareduid/Android.mk
+++ b/tests/JobScheduler/shareduid/Android.mk
@@ -29,5 +29,6 @@
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
LOCAL_PACKAGE_NAME := CtsJobSchedulerSharedUid
+LOCAL_SDK_VERSION := current
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/ProcessTest/NoShareUidApp/Android.mk b/tests/ProcessTest/NoShareUidApp/Android.mk
index c667dbe..7645b5c 100644
--- a/tests/ProcessTest/NoShareUidApp/Android.mk
+++ b/tests/ProcessTest/NoShareUidApp/Android.mk
@@ -24,6 +24,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := NoShareUidApp
+LOCAL_SDK_VERSION := current
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_DEX_PREOPT := false
diff --git a/tests/ProcessTest/ShareUidApp/Android.mk b/tests/ProcessTest/ShareUidApp/Android.mk
index d79eda4..fdd3feb 100644
--- a/tests/ProcessTest/ShareUidApp/Android.mk
+++ b/tests/ProcessTest/ShareUidApp/Android.mk
@@ -24,6 +24,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := ShareUidApp
+LOCAL_SDK_VERSION := current
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_DEX_PREOPT := false
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
index 5348373..d123d8f 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
@@ -18,6 +18,7 @@
import android.os.Message;
import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.TextUtils;
import android.view.accessibility.AccessibilityEvent;
@@ -29,6 +30,7 @@
/**
* Class for testing {@link AccessibilityEvent}.
*/
+@Presubmit
public class AccessibilityEventTest extends TestCase {
/** The number of properties of the {@link AccessibilityEvent} class. */
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index 6a4efd8..ccb5a6d 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -46,8 +46,6 @@
private static final String MULTIPLE_FEEDBACK_TYPES_ACCESSIBILITY_SERVICE_NAME =
"android.view.accessibility.cts.SpeakingAndVibratingAccessibilityService";
- private static final long WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT = 3000; // 3s
-
private AccessibilityManager mAccessibilityManager;
private Context mTargetContext;
@@ -334,7 +332,8 @@
private void assertAtomicBooleanBecomes(AtomicBoolean atomicBoolean,
boolean expectedValue, Object waitObject, String message)
throws Exception {
- long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
+ long timeoutTime =
+ System.currentTimeMillis() + ServiceControlUtils.TIMEOUT_FOR_SERVICE_ENABLE;
synchronized (waitObject) {
while ((atomicBoolean.get() != expectedValue)
&& (System.currentTimeMillis() < timeoutTime)) {
@@ -353,7 +352,8 @@
}
};
mAccessibilityManager.addAccessibilityStateChangeListener(listener);
- long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
+ long timeoutTime =
+ System.currentTimeMillis() + ServiceControlUtils.TIMEOUT_FOR_SERVICE_ENABLE;
synchronized (waitObject) {
while (!mAccessibilityManager.isEnabled()
&& (System.currentTimeMillis() < timeoutTime)) {
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
index 2b5f6ae..458c0d3 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
@@ -18,6 +18,7 @@
import android.graphics.Rect;
import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.TextUtils;
@@ -33,6 +34,7 @@
/**
* Class for testing {@link AccessibilityNodeInfo}.
*/
+@Presubmit
public class AccessibilityNodeInfoTest extends AndroidTestCase {
/** The number of properties of the {@link AccessibilityNodeInfo} class that are marshalled. */
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_CollectionInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_CollectionInfoTest.java
index d64bd94..98b87fc 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_CollectionInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_CollectionInfoTest.java
@@ -16,6 +16,7 @@
package android.view.accessibility.cts;
+import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
@@ -23,6 +24,7 @@
/**
* Class for testing {@link CollectionInfo}.
*/
+@Presubmit
public class AccessibilityNodeInfo_CollectionInfoTest extends AndroidTestCase {
@SmallTest
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_RangeInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_RangeInfoTest.java
index 954d762..4b01129 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_RangeInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfo_RangeInfoTest.java
@@ -16,6 +16,7 @@
package android.view.accessibility.cts;
+import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -24,6 +25,7 @@
/**
* Class for testing {@link AccessibilityNodeInfo.RangeInfo}.
*/
+@Presubmit
public class AccessibilityNodeInfo_RangeInfoTest extends AndroidTestCase {
/** Allowed tolerance for floating point equality comparisons. */
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeProviderTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeProviderTest.java
index eeee235..0c2a2dd 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeProviderTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeProviderTest.java
@@ -16,6 +16,7 @@
package android.view.accessibility.cts;
+import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.accessibility.AccessibilityNodeProvider;
@@ -23,6 +24,7 @@
/**
* Class for testing {@link AccessibilityNodeProvider}.
*/
+@Presubmit
public class AccessibilityNodeProviderTest extends AndroidTestCase {
@SmallTest
public void testDefaultBehavior() {
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
index 5bf02c8..a12ccce 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
@@ -17,6 +17,7 @@
package android.view.accessibility.cts;
import android.os.Message;
+import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.accessibility.AccessibilityEvent;
@@ -32,6 +33,7 @@
/**
* Class for testing {@link AccessibilityRecord}.
*/
+@Presubmit
public class AccessibilityRecordTest extends AndroidTestCase {
/** The number of properties of the {@link AccessibilityEvent} class. */
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java
index ffbe833..760340d 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java
@@ -18,6 +18,7 @@
import android.graphics.Rect;
import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.TextUtils;
@@ -26,6 +27,7 @@
/**
* Class for testing {@link AccessibilityWindowInfo}.
*/
+@Presubmit
public class AccessibilityWindowInfoTest extends AndroidTestCase {
@SmallTest
diff --git a/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
index 86c6f41..d0db868 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
@@ -16,19 +16,6 @@
package android.view.accessibility.cts;
-import android.app.UiAutomation;
-import android.os.ParcelFileDescriptor;
-import android.test.InstrumentationTestCase;
-import android.view.accessibility.CaptioningManager;
-import android.view.accessibility.CaptioningManager.CaptionStyle;
-import android.view.accessibility.CaptioningManager.CaptioningChangeListener;
-import org.mockito.Mockito;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Locale;
-
import static org.mockito.Matchers.anyFloat;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.mock;
@@ -36,6 +23,20 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
+import android.app.UiAutomation;
+import android.os.ParcelFileDescriptor;
+import android.test.InstrumentationTestCase;
+import android.view.accessibility.CaptioningManager;
+import android.view.accessibility.CaptioningManager.CaptionStyle;
+import android.view.accessibility.CaptioningManager.CaptioningChangeListener;
+
+import org.mockito.Mockito;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
+
/**
* Tests whether the CaptioningManager APIs are functional.
*/
diff --git a/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java b/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java
index 01275f3..5e8755f 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java
@@ -16,6 +16,10 @@
package android.view.accessibility.cts;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
import android.app.Instrumentation;
import android.app.UiAutomation;
import android.content.ContentResolver;
@@ -28,12 +32,13 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Utility methods for enabling and disabling the services used in this package
*/
public class ServiceControlUtils {
- private static final int TIMEOUT_FOR_SERVICE_ENABLE = 10000; // millis; 10s
+ public static final int TIMEOUT_FOR_SERVICE_ENABLE = 10000; // millis; 10s
private static final String SETTING_ENABLE_SPEAKING_AND_VIBRATING_SERVICES =
"android.view.accessibility.cts/.SpeakingAccessibilityService:"
@@ -181,31 +186,32 @@
final Object waitLockForA11yOff = new Object();
AccessibilityManager manager = (AccessibilityManager) instrumentation
.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
- if (!manager.isEnabled()) {
- return;
- }
- manager.addAccessibilityStateChangeListener(
- new AccessibilityManager.AccessibilityStateChangeListener() {
- @Override
- public void onAccessibilityStateChanged(boolean b) {
- synchronized (waitLockForA11yOff) {
- waitLockForA11yOff.notifyAll();
- }
- }
- });
- long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_FOR_SERVICE_ENABLE;
- while (SystemClock.uptimeMillis() < timeoutTimeMillis) {
+ // Updates to manager.isEnabled() aren't synchronized
+ AtomicBoolean accessibilityEnabled = new AtomicBoolean(manager.isEnabled());
+ AccessibilityManager.AccessibilityStateChangeListener listener = (boolean b) -> {
synchronized (waitLockForA11yOff) {
- if (!manager.isEnabled()) {
- return;
- }
- try {
- waitLockForA11yOff.wait(timeoutTimeMillis - SystemClock.uptimeMillis());
- } catch (InterruptedException e) {
- // Ignored; loop again
+ waitLockForA11yOff.notifyAll();
+ accessibilityEnabled.set(b);
+ }
+ };
+ manager.addAccessibilityStateChangeListener(listener);
+ try {
+ long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_FOR_SERVICE_ENABLE;
+ while (SystemClock.uptimeMillis() < timeoutTimeMillis) {
+ synchronized (waitLockForA11yOff) {
+ if (!accessibilityEnabled.get()) {
+ return;
+ }
+ try {
+ waitLockForA11yOff.wait(timeoutTimeMillis - SystemClock.uptimeMillis());
+ } catch (InterruptedException e) {
+ // Ignored; loop again
+ }
}
}
+ } finally {
+ manager.removeAccessibilityStateChangeListener(listener);
}
- throw new RuntimeException("Unable to turn accessibility off");
+ assertThat("Unable to turn accessibility off", manager.isEnabled(), is(equalTo(false)));
}
}
diff --git a/tests/accessibilityservice/res/values/strings.xml b/tests/accessibilityservice/res/values/strings.xml
index 454102a..ad5d3fd 100644
--- a/tests/accessibilityservice/res/values/strings.xml
+++ b/tests/accessibilityservice/res/values/strings.xml
@@ -139,6 +139,8 @@
<string name="a_b">A B</string>
+ <string name="german_text_with_strong_s">ß</string>
+
<string name="android_wiki_search">Android is a Linux-based</string>
<string name="foo_bar_baz">Foo bar baz.</string>
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityButtonTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityButtonTest.java
index 8521a56..359c6ac 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityButtonTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityButtonTest.java
@@ -16,12 +16,11 @@
import android.accessibilityservice.AccessibilityButtonController;
import android.app.Instrumentation;
-import android.os.Looper;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
index 8202399..b24846c 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -16,13 +16,16 @@
package android.accessibilityservice.cts;
-import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterForEventType;
+import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils
+ .filterForEventType;
import static android.accessibilityservice.cts.utils.RunOnMainUtils.getOnMain;
-import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP;
-import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP;
+import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction
+ .ACTION_HIDE_TOOLTIP;
+import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction
+ .ACTION_SHOW_TOOLTIP;
import static org.hamcrest.Matchers.in;
-import static org.hamcrest.core.IsNot.not;
+import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import android.accessibilityservice.cts.activities.AccessibilityEndToEndActivity;
@@ -44,6 +47,7 @@
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.Process;
+import android.platform.test.annotations.Presubmit;
import android.test.suitebuilder.annotation.MediumTest;
import android.text.TextUtils;
import android.util.Log;
@@ -58,7 +62,6 @@
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
/**
* This class performs end-to-end testing of the accessibility feature by
@@ -86,6 +89,7 @@
}
@MediumTest
+ @Presubmit
public void testTypeViewSelectedAccessibilityEvent() throws Throwable {
// create and populate the expected event
final AccessibilityEvent expected = AccessibilityEvent.obtain();
@@ -127,6 +131,7 @@
}
@MediumTest
+ @Presubmit
public void testTypeViewClickedAccessibilityEvent() throws Throwable {
// create and populate the expected event
final AccessibilityEvent expected = AccessibilityEvent.obtain();
@@ -163,6 +168,7 @@
}
@MediumTest
+ @Presubmit
public void testTypeViewLongClickedAccessibilityEvent() throws Throwable {
// create and populate the expected event
final AccessibilityEvent expected = AccessibilityEvent.obtain();
@@ -199,6 +205,7 @@
}
@MediumTest
+ @Presubmit
public void testTypeViewFocusedAccessibilityEvent() throws Throwable {
// create and populate the expected event
final AccessibilityEvent expected = AccessibilityEvent.obtain();
@@ -237,6 +244,7 @@
}
@MediumTest
+ @Presubmit
public void testTypeViewTextChangedAccessibilityEvent() throws Throwable {
// focus the edit text
final EditText editText = (EditText) getActivity().findViewById(R.id.edittext);
@@ -305,6 +313,7 @@
}
@MediumTest
+ @Presubmit
public void testTypeWindowStateChangedAccessibilityEvent() throws Throwable {
// create and populate the expected event
final AccessibilityEvent expected = AccessibilityEvent.obtain();
@@ -342,6 +351,7 @@
@MediumTest
@SuppressWarnings("deprecation")
+ @Presubmit
public void testTypeNotificationStateChangedAccessibilityEvent() throws Throwable {
// No notification UI on televisions.
if ((getActivity().getResources().getConfiguration().uiMode
@@ -484,6 +494,7 @@
}
@MediumTest
+ @Presubmit
public void testPackageNameCannotBeFakedAppWidget() throws Exception {
if (!hasAppWidgets()) {
return;
@@ -561,6 +572,7 @@
}
@MediumTest
+ @Presubmit
public void testViewHeadingReportedToAccessibility() throws Exception {
final Instrumentation instrumentation = getInstrumentation();
final EditText editText = (EditText) getOnMain(instrumentation, () -> {
@@ -590,6 +602,7 @@
}
@MediumTest
+ @Presubmit
public void testTooltipTextReportedToAccessibility() {
final Instrumentation instrumentation = getInstrumentation();
final UiAutomation uiAutomation = instrumentation.getUiAutomation();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFingerprintGestureTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFingerprintGestureTest.java
index c9b0027..0e9c181 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFingerprintGestureTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFingerprintGestureTest.java
@@ -14,6 +14,15 @@
package android.accessibilityservice.cts;
+import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
import android.accessibilityservice.FingerprintGestureController;
import android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback;
import android.accessibilityservice.cts.activities.AccessibilityEndToEndActivity;
@@ -23,6 +32,7 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -31,17 +41,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-
/**
* Verify that a service listening for fingerprint gestures gets called back when apps
* use the fingerprint sensor to authenticate.
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java
index aad045f..7cb569c 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java
@@ -17,16 +17,16 @@
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+import android.accessibilityservice.cts.R;
import android.accessibilityservice.cts.activities.AccessibilityFocusAndInputFocusSyncActivity;
import android.app.Instrumentation;
import android.app.UiAutomation;
+import android.platform.test.annotations.Presubmit;
import android.test.suitebuilder.annotation.MediumTest;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.accessibilityservice.cts.R;
-
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -45,6 +45,7 @@
}
@MediumTest
+ @Presubmit
public void testFindAccessibilityFocus() throws Exception {
getInstrumentation().runOnMainSync(() -> {
getActivity().findViewById(R.id.firstEditText).requestFocus();
@@ -81,6 +82,7 @@
}
@MediumTest
+ @Presubmit
public void testInitialStateNoAccessibilityFocus() throws Exception {
// Get the root which is only accessibility focused.
AccessibilityNodeInfo focused = getInstrumentation().getUiAutomation()
@@ -118,6 +120,7 @@
}
@MediumTest
+ @Presubmit
public void testActionClearAccessibilityFocus() throws Exception {
// Get the root linear layout info.
final AccessibilityNodeInfo rootLinearLayout = getInstrumentation().getUiAutomation()
@@ -166,6 +169,7 @@
}
@MediumTest
+ @Presubmit
public void testOnlyOneNodeHasAccessibilityFocus() throws Exception {
// Get the first not focused edit text.
final AccessibilityNodeInfo firstEditText = getInstrumentation().getUiAutomation()
@@ -233,6 +237,7 @@
}
}
+ @Presubmit
public void testScreenReaderFocusableAttribute_reportedToAccessibility() {
final Instrumentation instrumentation = getInstrumentation();
final UiAutomation uiAutomation = instrumentation.getUiAutomation();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
index fd1a9fd..6ac693f 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
@@ -15,7 +15,6 @@
package android.accessibilityservice.cts;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
@@ -32,8 +31,7 @@
import android.support.test.runner.AndroidJUnit4;
import android.util.DisplayMetrics;
import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
-import java.util.ArrayList;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -41,6 +39,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+
/**
* Verify that motion events are recognized as accessibility gestures.
*/
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
index fc71a79..95e4753 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
@@ -18,6 +18,7 @@
import android.accessibilityservice.AccessibilityService;
import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.MediumTest;
@@ -26,6 +27,7 @@
/**
* Test global actions
*/
+@Presubmit
public class AccessibilityGlobalActionsTest extends InstrumentationTestCase {
/**
* Timeout required for pending Binder calls or event processing to
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityLoggingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityLoggingTest.java
index 4593d06..9299807 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityLoggingTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityLoggingTest.java
@@ -14,11 +14,13 @@
package android.accessibilityservice.cts;
import static android.app.AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE;
+
import static junit.framework.Assert.assertTrue;
import android.content.Context;
-import android.support.test.runner.AndroidJUnit4;
+import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.AppOpsUtils;
@@ -26,6 +28,7 @@
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
+@Presubmit
public class AccessibilityLoggingTest {
/**
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityMagnificationTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityMagnificationTest.java
index 1abb2ab..8446702 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityMagnificationTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityMagnificationTest.java
@@ -16,22 +16,25 @@
package android.accessibilityservice.cts;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyFloat;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
import android.accessibilityservice.AccessibilityService.MagnificationController;
import android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Instrumentation;
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.Region;
-import android.provider.Settings;
import android.test.InstrumentationTestCase;
import android.util.DisplayMetrics;
import android.view.WindowManager;
import java.util.concurrent.atomic.AtomicBoolean;
-import static org.mockito.Mockito.*;
-
/**
* Class for testing {@link AccessibilityServiceInfo}.
*/
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityPaneTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityPaneTest.java
index b07e3ca..a870dd9 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityPaneTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityPaneTest.java
@@ -16,10 +16,14 @@
package android.accessibilityservice.cts;
-import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.AccessibilityEventTypeMatcher;
-import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.ContentChangesMatcher;
-import static android.accessibilityservice.cts.AccessibilityActivityTestCase.TIMEOUT_ASYNC_PROCESSING;
-import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen;
+import static android.accessibilityservice.cts.AccessibilityActivityTestCase
+ .TIMEOUT_ASYNC_PROCESSING;
+import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils
+ .AccessibilityEventTypeMatcher;
+import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils
+ .ContentChangesMatcher;
+import static android.accessibilityservice.cts.utils.ActivityLaunchUtils
+ .launchActivityAndWaitForItToBeOnscreen;
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED;
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED;
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE;
@@ -33,6 +37,7 @@
import android.app.Instrumentation;
import android.app.UiAutomation;
import android.app.UiAutomation.AccessibilityEventFilter;
+import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
@@ -50,6 +55,7 @@
* Tests reporting of window-like views
*/
@RunWith(AndroidJUnit4.class)
+@Presubmit
public class AccessibilityPaneTest {
private static Instrumentation sInstrumentation;
private static UiAutomation sUiAutomation;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java
index 1761117..b27ceaf 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java
@@ -18,6 +18,7 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import android.view.accessibility.AccessibilityEvent;
@@ -25,6 +26,7 @@
/**
* Class for testing {@link AccessibilityServiceInfo}.
*/
+@Presubmit
public class AccessibilityServiceInfoTest extends AndroidTestCase {
@MediumTest
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySettingsTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySettingsTest.java
index ccbd1b5..6575034 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySettingsTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySettingsTest.java
@@ -19,6 +19,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
@@ -29,6 +30,7 @@
* This test case is responsible to verify that the intent for launching
* accessibility settings has an activity that handles it.
*/
+@Presubmit
public class AccessibilitySettingsTest extends AndroidTestCase {
@MediumTest
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
index fb396b4..c179409 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
@@ -14,8 +14,9 @@
package android.accessibilityservice.cts;
-import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.AccessibilityService.SoftKeyboardController;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.cts.R;
import android.accessibilityservice.cts.activities.AccessibilityTestActivity;
import android.app.Activity;
import android.app.Instrumentation;
@@ -28,8 +29,6 @@
import android.test.ActivityInstrumentationTestCase2;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
-
-import android.accessibilityservice.cts.R;
import android.view.accessibility.AccessibilityWindowInfo;
import android.view.inputmethod.InputMethodManager;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
index 38bb738..115eb5f 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
@@ -14,6 +14,19 @@
package android.accessibilityservice.cts;
+import static android.view.accessibility.AccessibilityNodeInfo
+ .EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH;
+import static android.view.accessibility.AccessibilityNodeInfo
+ .EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX;
+import static android.view.accessibility.AccessibilityNodeInfo
+ .EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.accessibilityservice.cts.R;
import android.accessibilityservice.cts.activities.AccessibilityTextTraversalActivity;
import android.app.UiAutomation;
import android.graphics.RectF;
@@ -33,26 +46,11 @@
import android.widget.EditText;
import android.widget.TextView;
-import android.accessibilityservice.cts.R;
-
import java.util.Arrays;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
-import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH;
-import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX;
-import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
/**
* Test cases for actions taken on text views.
*/
@@ -198,10 +196,14 @@
public void testTextLocations_textViewShouldProvideWhenRequested() {
final TextView textView = (TextView) getActivity().findViewById(R.id.text);
- makeTextViewVisibleAndSetText(textView, getString(R.string.a_b));
+ // Use text with a strong s, since that gets replaced with a double s for all caps.
+ // That replacement requires us to properly handle the length of the string changing.
+ String stringToSet = getString(R.string.german_text_with_strong_s);
+ makeTextViewVisibleAndSetText(textView, stringToSet);
+ getInstrumentation().runOnMainSync(() -> textView.setAllCaps(true));
final AccessibilityNodeInfo text = mUiAutomation.getRootInActiveWindow()
- .findAccessibilityNodeInfosByText(getString(R.string.a_b)).get(0);
+ .findAccessibilityNodeInfosByText(stringToSet).get(0);
List<String> textAvailableExtraData = text.getAvailableExtraData();
assertTrue("Text view should offer text location to accessibility",
textAvailableExtraData.contains(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY));
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
index 646d9c3..d0bab51 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
@@ -14,6 +14,7 @@
package android.accessibilityservice.cts;
+import android.accessibilityservice.cts.R;
import android.accessibilityservice.cts.activities.AccessibilityTextTraversalActivity;
import android.app.UiAutomation;
import android.content.pm.PackageManager;
@@ -27,8 +28,6 @@
import android.widget.EditText;
import android.widget.TextView;
-import android.accessibilityservice.cts.R;
-
/**
* Test cases for testing the accessibility APIs for traversing the text content of
* a View at several granularities.
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
index a76a027..720e23f 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
@@ -14,7 +14,8 @@
package android.accessibilityservice.cts;
-import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen;
+import static android.accessibilityservice.cts.utils.ActivityLaunchUtils
+ .launchActivityAndWaitForItToBeOnscreen;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -23,20 +24,19 @@
import static org.junit.Assert.assertTrue;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.cts.R;
import android.accessibilityservice.cts.activities.AccessibilityViewTreeReportingActivity;
import android.app.Instrumentation;
import android.app.UiAutomation;
import android.content.Context;
+import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.support.test.InstrumentationRegistry;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
-
-import android.accessibilityservice.cts.R;
import android.widget.Button;
import android.widget.LinearLayout;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java
index 8b1154e..c718718 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java
@@ -13,18 +13,21 @@
*/
package android.accessibilityservice.cts;
+import static android.content.Context.AUDIO_SERVICE;
+
+import static org.junit.Assert.assertEquals;
+
import android.app.Instrumentation;
import android.content.pm.PackageManager;
+import android.media.AudioManager;
+import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
-import android.media.AudioManager;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import static android.content.Context.AUDIO_SERVICE;
-import static org.junit.Assert.assertEquals;
-
/**
* Verify that accessibility services can control the accessibility volume.
*/
@@ -47,6 +50,7 @@
}
@Test
+ @Presubmit
public void testChangeAccessibilityVolume_outsideValidAccessibilityService_shouldFail() {
if (mSingleVolume) {
return;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
index 2977843..e9f3f52 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
@@ -29,7 +29,6 @@
import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_BOUNDS;
import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_CHILDREN;
import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_FOCUSED;
-import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_PIP;
import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_REMOVED;
import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_TITLE;
@@ -44,15 +43,12 @@
import android.app.Activity;
import android.app.Instrumentation;
import android.app.UiAutomation;
-import android.os.Debug;
+import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.support.test.InstrumentationRegistry;
-import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import android.widget.ArrayAdapter;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
index 3df8d0c..4c1d064 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
@@ -18,11 +18,13 @@
import android.accessibilityservice.GestureDescription.StrokeDescription;
import android.graphics.Path;
import android.graphics.PathMeasure;
+import android.platform.test.annotations.Presubmit;
import android.test.InstrumentationTestCase;
/**
* Tests for creating gesture descriptions.
*/
+@Presubmit
public class GestureDescriptionTest extends InstrumentationTestCase {
static final int NOMINAL_PATH_DURATION = 100;
private Path mNominalPath;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/MagnificationGestureHandlerTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/MagnificationGestureHandlerTest.java
index 5cc46ea1..a9bd769 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/MagnificationGestureHandlerTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/MagnificationGestureHandlerTest.java
@@ -34,8 +34,8 @@
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
-import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
@@ -53,9 +53,9 @@
import android.graphics.PointF;
import android.os.SystemClock;
import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.support.test.InstrumentationRegistry;
import android.view.MotionEvent;
import android.widget.TextView;
diff --git a/tests/app/CantSaveState1/Android.mk b/tests/app/CantSaveState1/Android.mk
index ad7e880..72c762d 100644
--- a/tests/app/CantSaveState1/Android.mk
+++ b/tests/app/CantSaveState1/Android.mk
@@ -28,5 +28,6 @@
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
LOCAL_PACKAGE_NAME := CtsCantSaveState1
+LOCAL_SDK_VERSION := current
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/app/CantSaveState2/Android.mk b/tests/app/CantSaveState2/Android.mk
index 05da3f6..40230633 100644
--- a/tests/app/CantSaveState2/Android.mk
+++ b/tests/app/CantSaveState2/Android.mk
@@ -28,5 +28,6 @@
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
LOCAL_PACKAGE_NAME := CtsCantSaveState2
+LOCAL_SDK_VERSION := current
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/app/app/Android.mk b/tests/app/app/Android.mk
index 5e22eb2..d157c41 100644
--- a/tests/app/app/Android.mk
+++ b/tests/app/app/Android.mk
@@ -45,5 +45,6 @@
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
LOCAL_PACKAGE_NAME := CtsAppTestStubs
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java b/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
index fefa546..0668ff8 100644
--- a/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
@@ -67,6 +67,7 @@
expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_360, 48);
expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_400, 56);
expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_420, 64);
+ expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_440, 88);
expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XXHIGH, 88);
expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_560, 112);
expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XXXHIGH, 154);
@@ -85,6 +86,7 @@
expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_360, 80);
expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_400, 96);
expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_420, 112);
+ expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_440, 128);
expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XXHIGH, 128);
expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_560, 192);
expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 256);
@@ -103,6 +105,7 @@
expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_360, 160);
expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_400, 192);
expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_420, 228);
+ expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_440, 256);
expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_XXHIGH, 256);
expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_560, 384);
expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 512);
@@ -121,6 +124,7 @@
expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_360, 240);
expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_400, 288);
expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_420, 336);
+ expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_440, 384);
expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XXHIGH, 384);
expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_560, 576);
expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 768);
diff --git a/tests/app/src/android/app/cts/DialogTest.java b/tests/app/src/android/app/cts/DialogTest.java
index ee1836a..b2749c7 100755
--- a/tests/app/src/android/app/cts/DialogTest.java
+++ b/tests/app/src/android/app/cts/DialogTest.java
@@ -746,6 +746,7 @@
assertFalse(d.isOnContextMenuClosedCalled);
}
+ @Test
public void testOnSearchRequested() {
}
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index eca5e24..070b2eb 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -97,58 +97,55 @@
}
}
- public void testPrePCannotDisallowAlarmsOrMediaTest() throws Exception {
+ public void testOnlyPostPCanToggleAlarmsAndMediaTest() throws Exception {
toggleNotificationPolicyAccess(mContext.getPackageName(),
InstrumentationRegistry.getInstrumentation(), true);
- mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.O;
- // toggle on alarms and media
- mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
- NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS
- | NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER, 0, 0));
+ if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
+ // Post-P can toggle alarms and media
+ // toggle on alarms and media:
+ mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
+ NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS
+ | NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER, 0, 0));
+ NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy();
+ assertTrue((policy.priorityCategories
+ & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS) != 0);
+ assertTrue((policy.priorityCategories
+ & NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER) != 0);
- NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy();
- assert((policy.priorityCategories & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS)
- != 0);
- assert((policy.priorityCategories &
- NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER) != 0);
+ // toggle off alarms and media
+ mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0));
+ policy = mNotificationManager.getNotificationPolicy();
+ assertTrue((policy.priorityCategories
+ & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS) == 0);
+ assertTrue((policy.priorityCategories &
+ NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER) == 0);
+ } else {
+ // Pre-P cannot toggle alarms and media
+ NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
+ int alarmBit = origPolicy.priorityCategories & NotificationManager.Policy
+ .PRIORITY_CATEGORY_ALARMS;
+ int mediaBit = origPolicy.priorityCategories & NotificationManager.Policy
+ .PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER;
- // attempt to toggle off alarms and media
- // toggle on alarms and media
- mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0));
+ // attempt to toggle off alarms and media:
+ mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0));
+ NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy();
+ assertEquals(alarmBit, policy.priorityCategories
+ & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS);
+ assertEquals(mediaBit, policy.priorityCategories
+ & NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER);
- policy = mNotificationManager.getNotificationPolicy();
- assert((policy.priorityCategories & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS)
- != 0);
- assert((policy.priorityCategories &
- NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER) != 0);
- }
-
- public void testPostPCanDisallowAlarmsOrMediaTest() throws Exception {
- toggleNotificationPolicyAccess(mContext.getPackageName(),
- InstrumentationRegistry.getInstrumentation(), true);
- mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.P;
-
- // toggle on alarms and media
- mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
- NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS
- | NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER, 0, 0));
-
- NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy();
- assert((policy.priorityCategories & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS)
- != 0);
- assert((policy.priorityCategories &
- NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER) != 0);
-
- // attempt to toggle off alarms and media
- // toggle on alarms and media
- mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0));
-
- policy = mNotificationManager.getNotificationPolicy();
- assert((policy.priorityCategories & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS)
- == 0);
- assert((policy.priorityCategories &
- NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER) == 0);
+ // attempt to toggle on alarms and media:
+ mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
+ NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS
+ | NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER, 0, 0));
+ policy = mNotificationManager.getNotificationPolicy();
+ assertEquals(alarmBit, policy.priorityCategories
+ & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS);
+ assertEquals(mediaBit, policy.priorityCategories
+ & NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER);
+ }
}
public void testCreateChannelGroup() throws Exception {
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index e63a752..a16086b 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -47,7 +47,14 @@
<activity android:name=".TimePickerClockActivity" />
<activity android:name=".TimePickerSpinnerActivity" />
<activity android:name=".FatActivity" />
- <activity android:name=".VirtualContainerActivity"/>
+ <activity android:name=".VirtualContainerActivity">
+ <intent-filter>
+ <!-- This intent filter is not really needed by CTS, but it maks easier to launch
+ this app during CTS development... -->
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
<activity android:name=".OptionalSaveActivity" />
<activity android:name=".AllAutofillableViewsActivity" />
<activity android:name=".GridActivity"/>
diff --git a/tests/autofillservice/AndroidTest.xml b/tests/autofillservice/AndroidTest.xml
index 73fffd2..e8cfc3c 100644
--- a/tests/autofillservice/AndroidTest.xml
+++ b/tests/autofillservice/AndroidTest.xml
@@ -15,7 +15,7 @@
-->
<configuration description="Config for AutoFill Framework CTS tests.">
<option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="framework" />
+ <option name="config-descriptor:metadata" key="component" value="autofill" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/autofillservice/res/layout/grid_activity.xml b/tests/autofillservice/res/layout/grid_activity.xml
index 2ad125c..7888720 100644
--- a/tests/autofillservice/res/layout/grid_activity.xml
+++ b/tests/autofillservice/res/layout/grid_activity.xml
@@ -24,6 +24,7 @@
android:orientation="vertical" >
<GridLayout
+ android:id="@+id/grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
diff --git a/tests/autofillservice/res/layout/virtual_container_activity.xml b/tests/autofillservice/res/layout/virtual_container_activity.xml
index 2596fbb..bc47819 100644
--- a/tests/autofillservice/res/layout/virtual_container_activity.xml
+++ b/tests/autofillservice/res/layout/virtual_container_activity.xml
@@ -15,8 +15,34 @@
* limitations under the License.
-->
-<android.autofillservice.cts.VirtualContainerView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/virtual_container_view"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
-/>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ android:id="@+id/username_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="URL" />
+
+ <EditText
+ android:id="@+id/my_url_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+
+ <android.autofillservice.cts.VirtualContainerView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/virtual_container_view"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ />
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/autofillservice/res/xml/autofill_service_compat_mode_config.xml b/tests/autofillservice/res/xml/autofill_service_compat_mode_config.xml
index 1314999..a340fc2 100644
--- a/tests/autofillservice/res/xml/autofill_service_compat_mode_config.xml
+++ b/tests/autofillservice/res/xml/autofill_service_compat_mode_config.xml
@@ -15,5 +15,8 @@
* limitations under the License.
-->
<autofill-service xmlns:android="http://schemas.android.com/apk/res/android">
- <compatibility-package android:name="android.autofillservice.cts" android:maxLongVersionCode="1000000000"/>
+ <compatibility-package
+ android:name="android.autofillservice.cts"
+ android:urlBarResourceId="my_url_bar"
+ android:maxLongVersionCode="1000000000" />
</autofill-service>
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AbstractLoginActivityTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AbstractLoginActivityTestCase.java
new file mode 100644
index 0000000..da684d6
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/AbstractLoginActivityTestCase.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts;
+
+import static android.autofillservice.cts.Helper.getContext;
+
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Rule;
+
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Base class for test cases using {@link LoginActivity}.
+ */
+abstract class AbstractLoginActivityTestCase extends AutoFillServiceTestCase {
+ @Rule
+ public final AutofillActivityTestRule<LoginActivity> mActivityRule =
+ new AutofillActivityTestRule<LoginActivity>(LoginActivity.class);
+
+ @Rule
+ public final AutofillActivityTestRule<CheckoutActivity> mCheckoutActivityRule =
+ new AutofillActivityTestRule<CheckoutActivity>(CheckoutActivity.class, false);
+
+ protected LoginActivity mActivity;
+ protected boolean mCanPassKeys;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ mCanPassKeys = !Helper.isAutofillWindowFullScreen(getContext());
+ }
+
+ /**
+ * Requests focus on username and expect Window event happens.
+ */
+ protected void requestFocusOnUsername() throws TimeoutException {
+ mUiBot.waitForWindowChange(() -> mActivity.onUsername(View::requestFocus),
+ Timeouts.UI_TIMEOUT.getMaxValue());
+ }
+
+ /**
+ * Requests focus on username and expect no Window event happens.
+ */
+ protected void requestFocusOnUsernameNoWindowChange() {
+ try {
+ // TODO: define a small value in Timeout
+ mUiBot.waitForWindowChange(() -> mActivity.onUsername(View::requestFocus),
+ Timeouts.UI_TIMEOUT.ms());
+ } catch (TimeoutException ex) {
+ // no window events! looking good
+ return;
+ }
+ throw new IllegalStateException("Expect no window event when focusing to"
+ + " username, but event happened");
+ }
+
+ /**
+ * Requests focus on password and expect Window event happens.
+ */
+ protected void requestFocusOnPassword() throws TimeoutException {
+ mUiBot.waitForWindowChange(() -> mActivity.onPassword(View::requestFocus),
+ Timeouts.UI_TIMEOUT.getMaxValue());
+ }
+
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AuthenticationTest.java b/tests/autofillservice/src/android/autofillservice/cts/AuthenticationTest.java
new file mode 100644
index 0000000..f47bac5
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/AuthenticationTest.java
@@ -0,0 +1,1154 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts;
+
+import static android.app.Activity.RESULT_CANCELED;
+import static android.app.Activity.RESULT_OK;
+import static android.autofillservice.cts.Helper.ID_PASSWORD;
+import static android.autofillservice.cts.Helper.ID_USERNAME;
+import static android.autofillservice.cts.Helper.UNUSED_AUTOFILL_VALUE;
+import static android.autofillservice.cts.LoginActivity.getWelcomeMessage;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_PASSWORD;
+import static android.view.View.IMPORTANT_FOR_AUTOFILL_NO;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.autofillservice.cts.CannedFillResponse.CannedDataset;
+import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
+import android.content.IntentSender;
+import android.os.Bundle;
+import android.support.test.uiautomator.UiObject2;
+import android.view.View;
+import android.view.autofill.AutofillValue;
+
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.regex.Pattern;
+
+public class AuthenticationTest extends AbstractLoginActivityTestCase {
+
+ @Test
+ public void testDatasetAuthTwoFields() throws Exception {
+ datasetAuthTwoFields(false);
+ }
+
+ @Test
+ public void testDatasetAuthTwoFieldsUserCancelsFirstAttempt() throws Exception {
+ datasetAuthTwoFields(true);
+ }
+
+ private void datasetAuthTwoFields(boolean cancelFirstAttempt) throws Exception {
+ // Set service.
+ enableService();
+ final MyAutofillCallback callback = mActivity.registerCallback();
+
+ // Prepare the authenticated response
+ final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .build());
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
+ .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
+ .setPresentation(createPresentation("Tap to auth dataset"))
+ .setAuthentication(authentication)
+ .build())
+ .build());
+
+ // Set expectation for the activity
+ mActivity.expectAutoFill("dude", "sweet");
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+
+ // Wait for onFill() before proceeding.
+ sReplier.getNextFillRequest();
+ final View username = mActivity.getUsername();
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth dataset");
+
+ // Make sure UI is show on 2nd field as well
+ final View password = mActivity.getPassword();
+ requestFocusOnPassword();
+ callback.assertUiHiddenEvent(username);
+ callback.assertUiShownEvent(password);
+ mUiBot.assertDatasets("Tap to auth dataset");
+
+ // Now tap on 1st field to show it again...
+ requestFocusOnUsername();
+ callback.assertUiHiddenEvent(password);
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth dataset");
+
+ if (cancelFirstAttempt) {
+ // Trigger the auth dialog, but emulate cancel.
+ AuthenticationActivity.setResultCode(RESULT_CANCELED);
+ mUiBot.selectDataset("Tap to auth dataset");
+ callback.assertUiHiddenEvent(username);
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth dataset");
+
+ // Make sure it's still shown on other fields...
+ requestFocusOnPassword();
+ callback.assertUiHiddenEvent(username);
+ callback.assertUiShownEvent(password);
+ mUiBot.assertDatasets("Tap to auth dataset");
+
+ // Tap on 1st field to show it again...
+ requestFocusOnUsername();
+ callback.assertUiHiddenEvent(password);
+ callback.assertUiShownEvent(username);
+ }
+
+ // ...and select it this time
+ AuthenticationActivity.setResultCode(RESULT_OK);
+ mUiBot.selectDataset("Tap to auth dataset");
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+ }
+
+ @Test
+ public void testDatasetAuthTwoFieldsReplaceResponse() throws Exception {
+ // Set service.
+ enableService();
+ final MyAutofillCallback callback = mActivity.registerCallback();
+
+ // Prepare the authenticated response
+ final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+ new CannedFillResponse.Builder().addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .setPresentation(createPresentation("Dataset"))
+ .build())
+ .build());
+
+ // Set up the authentication response client state
+ final Bundle authentionClientState = new Bundle();
+ authentionClientState.putCharSequence("clientStateKey1", "clientStateValue1");
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, (AutofillValue) null)
+ .setField(ID_PASSWORD, (AutofillValue) null)
+ .setPresentation(createPresentation("Tap to auth dataset"))
+ .setAuthentication(authentication)
+ .build())
+ .setExtras(authentionClientState)
+ .build());
+
+ // Set expectation for the activity
+ mActivity.expectAutoFill("dude", "sweet");
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+
+ // Wait for onFill() before proceeding.
+ sReplier.getNextFillRequest();
+ final View username = mActivity.getUsername();
+
+ // Authenticate
+ callback.assertUiShownEvent(username);
+ mUiBot.selectDataset("Tap to auth dataset");
+ callback.assertUiHiddenEvent(username);
+
+ // Select a dataset from the new response
+ callback.assertUiShownEvent(username);
+ mUiBot.selectDataset("Dataset");
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+
+ final Bundle data = AuthenticationActivity.getData();
+ assertThat(data).isNotNull();
+ final String extraValue = data.getString("clientStateKey1");
+ assertThat(extraValue).isEqualTo("clientStateValue1");
+ }
+
+ @Test
+ public void testDatasetAuthTwoFieldsNoValues() throws Exception {
+ // Set service.
+ enableService();
+ final MyAutofillCallback callback = mActivity.registerCallback();
+
+ // Create the authentication intent
+ final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .build());
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, (String) null)
+ .setField(ID_PASSWORD, (String) null)
+ .setPresentation(createPresentation("Tap to auth dataset"))
+ .setAuthentication(authentication)
+ .build())
+ .build());
+
+ // Set expectation for the activity
+ mActivity.expectAutoFill("dude", "sweet");
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+
+ // Wait for onFill() before proceeding.
+ sReplier.getNextFillRequest();
+ final View username = mActivity.getUsername();
+
+ // Authenticate
+ callback.assertUiShownEvent(username);
+ mUiBot.selectDataset("Tap to auth dataset");
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+ }
+
+ @Test
+ public void testDatasetAuthTwoDatasets() throws Exception {
+ // Set service.
+ enableService();
+ final MyAutofillCallback callback = mActivity.registerCallback();
+
+ // Create the authentication intents
+ final CannedDataset unlockedDataset = new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .build();
+ final IntentSender authentication1 = AuthenticationActivity.createSender(mContext, 1,
+ unlockedDataset);
+ final IntentSender authentication2 = AuthenticationActivity.createSender(mContext, 2,
+ unlockedDataset);
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
+ .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
+ .setPresentation(createPresentation("Tap to auth dataset 1"))
+ .setAuthentication(authentication1)
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
+ .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
+ .setPresentation(createPresentation("Tap to auth dataset 2"))
+ .setAuthentication(authentication2)
+ .build())
+ .build());
+
+ // Set expectation for the activity
+ mActivity.expectAutoFill("dude", "sweet");
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+
+ // Wait for onFill() before proceeding.
+ sReplier.getNextFillRequest();
+ final View username = mActivity.getUsername();
+
+ // Authenticate
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth dataset 1", "Tap to auth dataset 2");
+
+ mUiBot.selectDataset("Tap to auth dataset 1");
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+ }
+
+ @Test
+ public void testDatasetAuthMixedSelectAuth() throws Exception {
+ datasetAuthMixedTest(true);
+ }
+
+ @Test
+ public void testDatasetAuthMixedSelectNonAuth() throws Exception {
+ datasetAuthMixedTest(false);
+ }
+
+ private void datasetAuthMixedTest(boolean selectAuth) throws Exception {
+ // Set service.
+ enableService();
+ final MyAutofillCallback callback = mActivity.registerCallback();
+
+ // Prepare the authenticated response
+ final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .build());
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .setPresentation(createPresentation("Tap to auth dataset"))
+ .setAuthentication(authentication)
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "DUDE")
+ .setField(ID_PASSWORD, "SWEET")
+ .setPresentation(createPresentation("What, me auth?"))
+ .build())
+ .build());
+
+ // Set expectation for the activity
+ if (selectAuth) {
+ mActivity.expectAutoFill("dude", "sweet");
+ } else {
+ mActivity.expectAutoFill("DUDE", "SWEET");
+ }
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+
+ // Wait for onFill() before proceeding.
+ sReplier.getNextFillRequest();
+ final View username = mActivity.getUsername();
+
+ // Authenticate
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth dataset", "What, me auth?");
+
+ final String chosenOne = selectAuth ? "Tap to auth dataset" : "What, me auth?";
+ mUiBot.selectDataset(chosenOne);
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+ }
+
+ @Test
+ public void testDatasetAuthNoFiltering() throws Exception {
+ // Set service.
+ enableService();
+ final MyAutofillCallback callback = mActivity.registerCallback();
+
+ // Create the authentication intents
+ final CannedDataset unlockedDataset = new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .build();
+ final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+ unlockedDataset);
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
+ .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
+ .setPresentation(createPresentation("Tap to auth dataset"))
+ .setAuthentication(authentication)
+ .build())
+ .build());
+
+ // Set expectation for the activity
+ mActivity.expectAutoFill("dude", "sweet");
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+
+ // Wait for onFill() before proceeding.
+ sReplier.getNextFillRequest();
+ final View username = mActivity.getUsername();
+
+ // Make sure it's showing initially...
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth dataset");
+
+ // ..then type something to hide it.
+ mActivity.onUsername((v) -> v.setText("a"));
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Now delete the char and assert it's shown again...
+ mActivity.onUsername((v) -> v.setText(""));
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth dataset");
+
+ // ...and select it this time
+ mUiBot.selectDataset("Tap to auth dataset");
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+ }
+
+ @Test
+ public void testDatasetAuthFilteringUsingAutofillValue() throws Exception {
+ // Set service.
+ enableService();
+ final MyAutofillCallback callback = mActivity.registerCallback();
+
+ // Create the authentication intents
+ final CannedDataset unlockedDataset = new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .build();
+ final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+ unlockedDataset);
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .setPresentation(createPresentation("DS1"))
+ .setAuthentication(authentication)
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "DUDE,THE")
+ .setField(ID_PASSWORD, "SWEET")
+ .setPresentation(createPresentation("DS2"))
+ .setAuthentication(authentication)
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "ZzBottom")
+ .setField(ID_PASSWORD, "top")
+ .setPresentation(createPresentation("DS3"))
+ .setAuthentication(authentication)
+ .build())
+ .build());
+
+ // Set expectation for the activity
+ mActivity.expectAutoFill("dude", "sweet");
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+
+ // Wait for onFill() before proceeding.
+ sReplier.getNextFillRequest();
+ final View username = mActivity.getUsername();
+
+ // Make sure it's showing initially...
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("DS1", "DS2", "DS3");
+
+ // ...then type something to hide them.
+ mActivity.onUsername((v) -> v.setText("a"));
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Now delete the char and assert they're shown again...
+ mActivity.onUsername((v) -> v.setText(""));
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("DS1", "DS2", "DS3");
+
+ // ...then filter for 2
+ mActivity.onUsername((v) -> v.setText("d"));
+ mUiBot.assertDatasets("DS1", "DS2");
+
+ // ...up to 1
+ mActivity.onUsername((v) -> v.setText("du"));
+ mUiBot.assertDatasets("DS1", "DS2");
+ mActivity.onUsername((v) -> v.setText("dud"));
+ mUiBot.assertDatasets("DS1", "DS2");
+ mActivity.onUsername((v) -> v.setText("dude"));
+ mUiBot.assertDatasets("DS1", "DS2");
+ mActivity.onUsername((v) -> v.setText("dude,"));
+ mUiBot.assertDatasets("DS2");
+
+ // Now delete the char and assert 2 are shown again...
+ mActivity.onUsername((v) -> v.setText("dude"));
+ final UiObject2 picker = mUiBot.assertDatasets("DS1", "DS2");
+
+ // ...and select it this time
+ mUiBot.selectDataset(picker, "DS1");
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+ }
+
+ @Test
+ public void testDatasetAuthFilteringUsingRegex() throws Exception {
+ // Set service.
+ enableService();
+ final MyAutofillCallback callback = mActivity.registerCallback();
+
+ // Create the authentication intents
+ final CannedDataset unlockedDataset = new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .build();
+ final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+ unlockedDataset);
+
+ // Configure the service behavior
+
+ final Pattern min2Chars = Pattern.compile(".{2,}");
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE, min2Chars)
+ .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
+ .setPresentation(createPresentation("Tap to auth dataset"))
+ .setAuthentication(authentication)
+ .build())
+ .build());
+
+ // Set expectation for the activity
+ mActivity.expectAutoFill("dude", "sweet");
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+
+ // Wait for onFill() before proceeding.
+ sReplier.getNextFillRequest();
+ final View username = mActivity.getUsername();
+
+ // Make sure it's showing initially...
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth dataset");
+
+ // ...then type something to hide it.
+ mActivity.onUsername((v) -> v.setText("a"));
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // ...now type something again to show it, as the input will have 2 chars.
+ mActivity.onUsername((v) -> v.setText("aa"));
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth dataset");
+
+ // Delete the char and assert it's not shown again...
+ mActivity.onUsername((v) -> v.setText("a"));
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // ...then type something again to show it, as the input will have 2 chars.
+ mActivity.onUsername((v) -> v.setText("aa"));
+ callback.assertUiShownEvent(username);
+
+ // ...and select it this time
+ mUiBot.selectDataset("Tap to auth dataset");
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+ }
+
+ @Test
+ public void testDatasetAuthMixedFilteringSelectAuth() throws Exception {
+ datasetAuthMixedFilteringTest(true);
+ }
+
+ @Test
+ public void testDatasetAuthMixedFilteringSelectNonAuth() throws Exception {
+ datasetAuthMixedFilteringTest(false);
+ }
+
+ private void datasetAuthMixedFilteringTest(boolean selectAuth) throws Exception {
+ // Set service.
+ enableService();
+ final MyAutofillCallback callback = mActivity.registerCallback();
+
+ // Create the authentication intents
+ final CannedDataset unlockedDataset = new CannedDataset.Builder()
+ .setField(ID_USERNAME, "DUDE")
+ .setField(ID_PASSWORD, "SWEET")
+ .build();
+ final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+ unlockedDataset);
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
+ .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
+ .setPresentation(createPresentation("Tap to auth dataset"))
+ .setAuthentication(authentication)
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .setPresentation(createPresentation("What, me auth?"))
+ .build())
+ .build());
+
+ // Set expectation for the activity
+ if (selectAuth) {
+ mActivity.expectAutoFill("DUDE", "SWEET");
+ } else {
+ mActivity.expectAutoFill("dude", "sweet");
+ }
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+
+ // Wait for onFill() before proceeding.
+ sReplier.getNextFillRequest();
+ final View username = mActivity.getUsername();
+
+ // Make sure it's showing initially...
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth dataset", "What, me auth?");
+
+ // Filter the auth dataset.
+ mActivity.onUsername((v) -> v.setText("d"));
+ mUiBot.assertDatasets("What, me auth?");
+
+ // Filter all.
+ mActivity.onUsername((v) -> v.setText("dw"));
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Now delete the char and assert the non-auth is shown again.
+ mActivity.onUsername((v) -> v.setText("d"));
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("What, me auth?");
+
+ // Delete again and assert all dataset are shown.
+ mActivity.onUsername((v) -> v.setText(""));
+ mUiBot.assertDatasets("Tap to auth dataset", "What, me auth?");
+
+ // ...and select it this time
+ final String chosenOne = selectAuth ? "Tap to auth dataset" : "What, me auth?";
+ mUiBot.selectDataset(chosenOne);
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+ }
+
+ @Test
+ public void testDatasetAuthClientStateSetOnIntentOnly() throws Exception {
+ fillDatasetAuthWithClientState(ClientStateLocation.INTENT_ONLY);
+ }
+
+ @Test
+ public void testDatasetAuthClientStateSetOnFillResponseOnly() throws Exception {
+ fillDatasetAuthWithClientState(ClientStateLocation.FILL_RESPONSE_ONLY);
+ }
+
+ @Test
+ public void testDatasetAuthClientStateSetOnIntentAndFillResponse() throws Exception {
+ fillDatasetAuthWithClientState(ClientStateLocation.BOTH);
+ }
+
+ private void fillDatasetAuthWithClientState(ClientStateLocation where) throws Exception {
+ // Set service.
+ enableService();
+
+ // Prepare the authenticated response
+ final CannedDataset dataset = new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .build();
+ final IntentSender authentication = where == ClientStateLocation.FILL_RESPONSE_ONLY
+ ? AuthenticationActivity.createSender(mContext, 1,
+ dataset)
+ : AuthenticationActivity.createSender(mContext, 1,
+ dataset, newClientState("CSI", "FromIntent"));
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
+ .setExtras(newClientState("CSI", "FromResponse"))
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
+ .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
+ .setPresentation(createPresentation("Tap to auth dataset"))
+ .setAuthentication(authentication)
+ .build())
+ .build());
+
+ // Set expectation for the activity
+ mActivity.expectAutoFill("dude", "sweet");
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+ sReplier.getNextFillRequest();
+
+ // Tap authentication request.
+ mUiBot.selectDataset("Tap to auth dataset");
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+
+ // Now trigger save.
+ mActivity.onUsername((v) -> v.setText("malkovich"));
+ mActivity.onPassword((v) -> v.setText("malkovich"));
+ final String expectedMessage = getWelcomeMessage("malkovich");
+ final String actualMessage = mActivity.tapLogin();
+ assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
+ mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
+
+ // Assert client state on authentication activity.
+ assertClientState("auth activity", AuthenticationActivity.getData(), "CSI", "FromResponse");
+
+ // Assert client state on save request.
+ final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+ final String expectedValue = where == ClientStateLocation.FILL_RESPONSE_ONLY
+ ? "FromResponse" : "FromIntent";
+ assertClientState("on save", saveRequest.data, "CSI", expectedValue);
+ }
+
+ @Test
+ public void testFillResponseAuthBothFields() throws Exception {
+ fillResponseAuthBothFields(false);
+ }
+
+ @Test
+ public void testFillResponseAuthBothFieldsUserCancelsFirstAttempt() throws Exception {
+ fillResponseAuthBothFields(true);
+ }
+
+ private void fillResponseAuthBothFields(boolean cancelFirstAttempt) throws Exception {
+ // Set service.
+ enableService();
+ final MyAutofillCallback callback = mActivity.registerCallback();
+
+ // Prepare the authenticated response
+ final Bundle clientState = new Bundle();
+ clientState.putString("numbers", "4815162342");
+ final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+ new CannedFillResponse.Builder().addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .setId("name")
+ .setPresentation(createPresentation("Dataset"))
+ .build())
+ .setExtras(clientState).build());
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setAuthentication(authentication, ID_USERNAME, ID_PASSWORD)
+ .setPresentation(createPresentation("Tap to auth response"))
+ .setExtras(clientState)
+ .build());
+
+ // Set expectation for the activity
+ mActivity.expectAutoFill("dude", "sweet");
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+
+ // Wait for onFill() before proceeding.
+ sReplier.getNextFillRequest();
+ final View username = mActivity.getUsername();
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth response");
+
+ // Make sure UI is show on 2nd field as well
+ final View password = mActivity.getPassword();
+ requestFocusOnPassword();
+ callback.assertUiHiddenEvent(username);
+ callback.assertUiShownEvent(password);
+ mUiBot.assertDatasets("Tap to auth response");
+
+ // Now tap on 1st field to show it again...
+ requestFocusOnUsername();
+ callback.assertUiHiddenEvent(password);
+ callback.assertUiShownEvent(username);
+
+ if (cancelFirstAttempt) {
+ // Trigger the auth dialog, but emulate cancel.
+ AuthenticationActivity.setResultCode(RESULT_CANCELED);
+ mUiBot.selectDataset("Tap to auth response");
+ callback.assertUiHiddenEvent(username);
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth response");
+
+ // Make sure it's still shown on other fields...
+ requestFocusOnPassword();
+ callback.assertUiHiddenEvent(username);
+ callback.assertUiShownEvent(password);
+ mUiBot.assertDatasets("Tap to auth response");
+
+ // Tap on 1st field to show it again...
+ requestFocusOnUsername();
+ callback.assertUiHiddenEvent(password);
+ callback.assertUiShownEvent(username);
+ }
+
+ // ...and select it this time
+ AuthenticationActivity.setResultCode(RESULT_OK);
+ mUiBot.selectDataset("Tap to auth response");
+ callback.assertUiHiddenEvent(username);
+ callback.assertUiShownEvent(username);
+ final UiObject2 picker = mUiBot.assertDatasets("Dataset");
+ mUiBot.selectDataset(picker, "Dataset");
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+
+ final Bundle data = AuthenticationActivity.getData();
+ assertThat(data).isNotNull();
+ final String extraValue = data.getString("numbers");
+ assertThat(extraValue).isEqualTo("4815162342");
+ }
+
+ @Test
+ public void testFillResponseAuthJustOneField() throws Exception {
+ // Set service.
+ enableService();
+ final MyAutofillCallback callback = mActivity.registerCallback();
+
+ // Prepare the authenticated response
+ final Bundle clientState = new Bundle();
+ clientState.putString("numbers", "4815162342");
+ final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+ new CannedFillResponse.Builder().addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .setPresentation(createPresentation("Dataset"))
+ .build())
+ .build());
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setAuthentication(authentication, ID_USERNAME)
+ .setIgnoreFields(ID_PASSWORD)
+ .setPresentation(createPresentation("Tap to auth response"))
+ .setExtras(clientState)
+ .build());
+
+ // Set expectation for the activity
+ mActivity.expectAutoFill("dude", "sweet");
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+
+ // Wait for onFill() before proceeding.
+ sReplier.getNextFillRequest();
+ final View username = mActivity.getUsername();
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth response");
+
+ // Make sure UI is not show on 2nd field
+ requestFocusOnPassword();
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+ // Now tap on 1st field to show it again...
+ requestFocusOnUsername();
+ callback.assertUiShownEvent(username);
+
+ // ...and select it this time
+ mUiBot.selectDataset("Tap to auth response");
+ callback.assertUiHiddenEvent(username);
+ final UiObject2 picker = mUiBot.assertDatasets("Dataset");
+
+ callback.assertUiShownEvent(username);
+ mUiBot.selectDataset(picker, "Dataset");
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+ final Bundle data = AuthenticationActivity.getData();
+ assertThat(data).isNotNull();
+ final String extraValue = data.getString("numbers");
+ assertThat(extraValue).isEqualTo("4815162342");
+ }
+
+ @Test
+ public void testFillResponseAuthWhenAppCallsCancel() throws Exception {
+ // Set service.
+ enableService();
+ final MyAutofillCallback callback = mActivity.registerCallback();
+
+ // Prepare the authenticated response
+ final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+ new CannedFillResponse.Builder().addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .setId("name")
+ .setPresentation(createPresentation("Dataset"))
+ .build())
+ .build());
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setAuthentication(authentication, ID_USERNAME, ID_PASSWORD)
+ .setPresentation(createPresentation("Tap to auth response"))
+ .build());
+
+ // Trigger autofill.
+ requestFocusOnUsername();
+
+ // Wait for onFill() before proceeding.
+ sReplier.getNextFillRequest();
+ final View username = mActivity.getUsername();
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth response");
+
+ // Disables autofill so it's not triggered again after the auth activity is finished
+ // (and current session is canceled) and the login activity is resumed.
+ username.setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_NO);
+
+ // Autofill it.
+ final CountDownLatch latch = new CountDownLatch(1);
+ AuthenticationActivity.setResultCode(latch, RESULT_OK);
+
+ mUiBot.selectDataset("Tap to auth response");
+ callback.assertUiHiddenEvent(username);
+
+ // Cancel session...
+ mActivity.getAutofillManager().cancel();
+
+ // ...before finishing the Auth UI.
+ latch.countDown();
+
+ mUiBot.assertNoDatasets();
+ }
+
+ @Test
+ public void testFillResponseAuthServiceHasNoDataButCanSave() throws Exception {
+ fillResponseAuthServiceHasNoDataTest(true);
+ }
+
+ @Test
+ public void testFillResponseAuthServiceHasNoData() throws Exception {
+ fillResponseAuthServiceHasNoDataTest(false);
+ }
+
+ private void fillResponseAuthServiceHasNoDataTest(boolean canSave) throws Exception {
+ // Set service.
+ enableService();
+ final MyAutofillCallback callback = mActivity.registerCallback();
+
+ // Prepare the authenticated response
+ final CannedFillResponse response = canSave
+ ? new CannedFillResponse.Builder()
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
+ .build()
+ : CannedFillResponse.NO_RESPONSE;
+
+ final IntentSender authentication =
+ AuthenticationActivity.createSender(mContext, 1, response);
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setAuthentication(authentication, ID_USERNAME, ID_PASSWORD)
+ .setPresentation(createPresentation("Tap to auth response"))
+ .build());
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+
+ // Wait for onFill() before proceeding.
+ sReplier.getNextFillRequest();
+ final View username = mActivity.getUsername();
+ callback.assertUiShownEvent(username);
+
+ // Select the authentication dialog.
+ mUiBot.selectDataset("Tap to auth response");
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+ }
+
+ @Test
+ public void testFillResponseAuthClientStateSetOnIntentOnly() throws Exception {
+ fillResponseAuthWithClientState(ClientStateLocation.INTENT_ONLY);
+ }
+
+ @Test
+ public void testFillResponseAuthClientStateSetOnFillResponseOnly() throws Exception {
+ fillResponseAuthWithClientState(ClientStateLocation.FILL_RESPONSE_ONLY);
+ }
+
+ @Test
+ public void testFillResponseAuthClientStateSetOnIntentAndFillResponse() throws Exception {
+ fillResponseAuthWithClientState(ClientStateLocation.BOTH);
+ }
+
+ enum ClientStateLocation {
+ INTENT_ONLY,
+ FILL_RESPONSE_ONLY,
+ BOTH
+ }
+
+ private void fillResponseAuthWithClientState(ClientStateLocation where) throws Exception {
+ // Set service.
+ enableService();
+
+ // Prepare the authenticated response
+ final CannedFillResponse.Builder authenticatedResponseBuilder =
+ new CannedFillResponse.Builder()
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .setPresentation(createPresentation("Dataset"))
+ .build());
+
+ if (where == ClientStateLocation.FILL_RESPONSE_ONLY || where == ClientStateLocation.BOTH) {
+ authenticatedResponseBuilder.setExtras(newClientState("CSI", "FromAuthResponse"));
+ }
+
+ final IntentSender authentication = where == ClientStateLocation.FILL_RESPONSE_ONLY
+ ? AuthenticationActivity.createSender(mContext, 1,
+ authenticatedResponseBuilder.build())
+ : AuthenticationActivity.createSender(mContext, 1,
+ authenticatedResponseBuilder.build(), newClientState("CSI", "FromIntent"));
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setAuthentication(authentication, ID_USERNAME)
+ .setIgnoreFields(ID_PASSWORD)
+ .setPresentation(createPresentation("Tap to auth response"))
+ .setExtras(newClientState("CSI", "FromResponse"))
+ .build());
+
+ // Set expectation for the activity
+ mActivity.expectAutoFill("dude", "sweet");
+
+ // Trigger autofill.
+ requestFocusOnUsername();
+ sReplier.getNextFillRequest();
+
+ // Tap authentication request.
+ mUiBot.selectDataset("Tap to auth response");
+
+ // Tap dataset.
+ mUiBot.selectDataset("Dataset");
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+
+ // Now trigger save.
+ mActivity.onUsername((v) -> v.setText("malkovich"));
+ mActivity.onPassword((v) -> v.setText("malkovich"));
+ final String expectedMessage = getWelcomeMessage("malkovich");
+ final String actualMessage = mActivity.tapLogin();
+ assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
+ mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
+
+ // Assert client state on authentication activity.
+ assertClientState("auth activity", AuthenticationActivity.getData(), "CSI", "FromResponse");
+
+ // Assert client state on save request.
+ final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+ final String expectedValue = where == ClientStateLocation.FILL_RESPONSE_ONLY
+ ? "FromAuthResponse" : "FromIntent";
+ assertClientState("on save", saveRequest.data, "CSI", expectedValue);
+ }
+
+ // TODO(on master): move to helper / reuse in other places
+ private void assertClientState(String where, Bundle data, String expectedKey,
+ String expectedValue) {
+ assertWithMessage("no client state on %s", where).that(data).isNotNull();
+ final String extraValue = data.getString(expectedKey);
+ assertWithMessage("invalid value for %s on %s", expectedKey, where)
+ .that(extraValue).isEqualTo(expectedValue);
+ }
+
+ // TODO(on master): move to helper / reuse in other places
+ private Bundle newClientState(String key, String value) {
+ final Bundle clientState = new Bundle();
+ clientState.putString(key, value);
+ return clientState;
+ }
+
+ @Test
+ public void testFillResponseFiltering() throws Exception {
+ // Set service.
+ enableService();
+ final MyAutofillCallback callback = mActivity.registerCallback();
+
+ // Prepare the authenticated response
+ final Bundle clientState = new Bundle();
+ clientState.putString("numbers", "4815162342");
+ final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+ new CannedFillResponse.Builder().addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .setId("name")
+ .setPresentation(createPresentation("Dataset"))
+ .build())
+ .setExtras(clientState).build());
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setAuthentication(authentication, ID_USERNAME, ID_PASSWORD)
+ .setPresentation(createPresentation("Tap to auth response"))
+ .setExtras(clientState)
+ .build());
+
+ // Set expectation for the activity
+ mActivity.expectAutoFill("dude", "sweet");
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+
+ // Wait for onFill() before proceeding.
+ sReplier.getNextFillRequest();
+ final View username = mActivity.getUsername();
+
+ // Make sure it's showing initially...
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth response");
+
+ // ..then type something to hide it.
+ mActivity.onUsername((v) -> v.setText("a"));
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Now delete the char and assert it's shown again...
+ mActivity.onUsername((v) -> v.setText(""));
+ callback.assertUiShownEvent(username);
+ mUiBot.assertDatasets("Tap to auth response");
+
+ // ...and select it this time
+ AuthenticationActivity.setResultCode(RESULT_OK);
+ mUiBot.selectDataset("Tap to auth response");
+ callback.assertUiHiddenEvent(username);
+ callback.assertUiShownEvent(username);
+ final UiObject2 picker = mUiBot.assertDatasets("Dataset");
+ mUiBot.selectDataset(picker, "Dataset");
+ callback.assertUiHiddenEvent(username);
+ mUiBot.assertNoDatasets();
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+
+ final Bundle data = AuthenticationActivity.getData();
+ assertThat(data).isNotNull();
+ final String extraValue = data.getString("numbers");
+ assertThat(extraValue).isEqualTo("4815162342");
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
index 4d39cb1..53dba8b 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
@@ -33,6 +33,8 @@
import android.util.Log;
import android.widget.RemoteViews;
+import com.android.compatibility.common.util.RequiredFeatureRule;
+
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -74,7 +76,7 @@
};
@Rule
- public final RetryRule mRetryRule = new RetryRule(2);
+ public final RetryRule mRetryRule = new RetryRule(5);
@Rule
public final AutofillLoggingTestRule mLoggingRule = new AutofillLoggingTestRule(TAG);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java
index 9262808..d576ce4 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java
@@ -33,6 +33,7 @@
import android.widget.EditText;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
@@ -249,6 +250,7 @@
.getAutofillValue().getTextValue().toString()).isEqualTo("editText1-filled");
}
+ @Ignore("temporarily disabled because UI is shown - b/73736562")
@Test
public void removeViewInBackground() throws Exception {
activityToBackgroundShouldNotTriggerSave(
@@ -261,6 +263,7 @@
null);
}
+ @Ignore("temporarily disabled because UI is shown - b/73736562")
@Test
public void hideViewInBackground() throws Exception {
activityToBackgroundShouldNotTriggerSave(() -> {
@@ -272,12 +275,14 @@
null);
}
+ @Ignore("temporarily disabled because UI is shown - b/73736562")
@Test
public void hideParentInBackground() throws Exception {
activityToBackgroundShouldNotTriggerSave(() -> mParent.setVisibility(ViewGroup.INVISIBLE),
null);
}
+ @Ignore("temporarily disabled because UI is shown - b/73736562")
@Test
public void removeParentInBackground() throws Exception {
activityToBackgroundShouldNotTriggerSave(
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
index 78b6d9c..33aa025 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
@@ -69,6 +69,7 @@
private final Validator mValidator;
private final String[] mRequiredSavableIds;
private final String[] mOptionalSavableIds;
+ private final AutofillId[] mRequiredSavableAutofillIds;
private final String mSaveDescription;
private final CustomDescription mCustomDescription;
private final Bundle mExtras;
@@ -93,6 +94,7 @@
mFailureMessage = builder.mFailureMessage;
mValidator = builder.mValidator;
mRequiredSavableIds = builder.mRequiredSavableIds;
+ mRequiredSavableAutofillIds = builder.mRequiredSavableAutofillIds;
mOptionalSavableIds = builder.mOptionalSavableIds;
mSaveDescription = builder.mSaveDescription;
mCustomDescription = builder.mCustomDescription;
@@ -151,12 +153,16 @@
builder.addDataset(dataset);
}
}
- if (mRequiredSavableIds != null) {
- final SaveInfo.Builder saveInfo =
- mRequiredSavableIds == null || mRequiredSavableIds.length == 0
+ if (mRequiredSavableIds != null || mRequiredSavableAutofillIds != null) {
+ final SaveInfo.Builder saveInfo;
+ if (mRequiredSavableAutofillIds != null) {
+ saveInfo = new SaveInfo.Builder(mSaveType, mRequiredSavableAutofillIds);
+ } else {
+ saveInfo = mRequiredSavableIds == null || mRequiredSavableIds.length == 0
? new SaveInfo.Builder(mSaveType)
: new SaveInfo.Builder(mSaveType,
getAutofillIds(nodeResolver, mRequiredSavableIds));
+ }
saveInfo.setFlags(mSaveInfoFlags);
@@ -222,6 +228,7 @@
+ ",datasets=" + mDatasets
+ ", requiredSavableIds=" + Arrays.toString(mRequiredSavableIds)
+ ", optionalSavableIds=" + Arrays.toString(mOptionalSavableIds)
+ + ", requiredSavableAutofillIds=" + Arrays.toString(mRequiredSavableAutofillIds)
+ ", saveInfoFlags=" + mSaveInfoFlags
+ ", fillResponseFlags=" + mFillResponseFlags
+ ", failureMessage=" + mFailureMessage
@@ -255,6 +262,7 @@
private Validator mValidator;
private String[] mRequiredSavableIds;
private String[] mOptionalSavableIds;
+ private AutofillId[] mRequiredSavableAutofillIds;
private String mSaveDescription;
public CustomDescription mCustomDescription;
public int mSaveType = -1;
@@ -297,14 +305,31 @@
}
/**
- * Sets the required savable ids based on they {@code resourceId}.
+ * Sets the required savable ids based on their {@code resourceId}.
*/
public Builder setRequiredSavableIds(int type, String... ids) {
+ if (mRequiredSavableAutofillIds != null) {
+ throw new IllegalStateException("Already set required autofill ids: "
+ + Arrays.toString(mRequiredSavableAutofillIds));
+ }
mSaveType = type;
mRequiredSavableIds = ids;
return this;
}
+ /**
+ * Sets the required savable ids based on their {@code autofillId}.
+ */
+ public Builder setRequiredSavableAutofillIds(int type, AutofillId... ids) {
+ if (mRequiredSavableIds != null) {
+ throw new IllegalStateException("Already set required resource ids: "
+ + Arrays.toString(mRequiredSavableIds));
+ }
+ mSaveType = type;
+ mRequiredSavableAutofillIds = ids;
+ return this;
+ }
+
public Builder setSaveInfoFlags(int flags) {
mSaveInfoFlags = flags;
return this;
@@ -465,6 +490,8 @@
*/
static class CannedDataset {
private final Map<String, AutofillValue> mFieldValues;
+ private final Map<AutofillId, AutofillValue> mFieldValuesById;
+ private final Map<AutofillId, RemoteViews> mFieldPresentationsById;
private final Map<String, RemoteViews> mFieldPresentations;
private final Map<String, Pair<Boolean, Pattern>> mFieldFilters;
private final RemoteViews mPresentation;
@@ -473,6 +500,8 @@
private CannedDataset(Builder builder) {
mFieldValues = builder.mFieldValues;
+ mFieldValuesById = builder.mFieldValuesById;
+ mFieldPresentationsById = builder.mFieldPresentationsById;
mFieldPresentations = builder.mFieldPresentations;
mFieldFilters = builder.mFieldFilters;
mPresentation = builder.mPresentation;
@@ -495,25 +524,39 @@
if (node == null) {
throw new AssertionError("No node with resource id " + id);
}
- final AutofillId autofillid = node.getAutofillId();
+ final AutofillId autofillId = node.getAutofillId();
final AutofillValue value = entry.getValue();
final RemoteViews presentation = mFieldPresentations.get(id);
final Pair<Boolean, Pattern> filter = mFieldFilters.get(id);
if (presentation != null) {
if (filter == null) {
- builder.setValue(autofillid, value, presentation);
+ builder.setValue(autofillId, value, presentation);
} else {
- builder.setValue(autofillid, value, filter.second, presentation);
+ builder.setValue(autofillId, value, filter.second, presentation);
}
} else {
if (filter == null) {
- builder.setValue(autofillid, value);
+ builder.setValue(autofillId, value);
} else {
- builder.setValue(autofillid, value, filter.second);
+ builder.setValue(autofillId, value, filter.second);
}
}
}
}
+ if (mFieldValuesById != null) {
+ // NOTE: filter is not yet supported when calling methods that explicitly pass
+ // autofill id
+ for (Map.Entry<AutofillId, AutofillValue> entry : mFieldValuesById.entrySet()) {
+ final AutofillId autofillId = entry.getKey();
+ final AutofillValue value = entry.getValue();
+ final RemoteViews presentation = mFieldPresentationsById.get(autofillId);
+ if (presentation != null) {
+ builder.setValue(autofillId, value, presentation);
+ } else {
+ builder.setValue(autofillId, value);
+ }
+ }
+ }
builder.setId(mId).setAuthentication(mAuthentication);
return builder.build();
}
@@ -522,14 +565,18 @@
public String toString() {
return "CannedDataset " + mId + " : [hasPresentation=" + (mPresentation != null)
+ ", fieldPresentations=" + (mFieldPresentations)
+ + ", fieldPresentationsById=" + (mFieldPresentationsById)
+ ", hasAuthentication=" + (mAuthentication != null)
+ ", fieldValues=" + mFieldValues
+ + ", fieldValuesById=" + mFieldValuesById
+ ", fieldFilters=" + mFieldFilters + "]";
}
static class Builder {
private final Map<String, AutofillValue> mFieldValues = new HashMap<>();
+ private final Map<AutofillId, AutofillValue> mFieldValuesById = new HashMap<>();
private final Map<String, RemoteViews> mFieldPresentations = new HashMap<>();
+ private final Map<AutofillId, RemoteViews> mFieldPresentationsById = new HashMap<>();
private final Map<String, Pair<Boolean, Pattern>> mFieldFilters = new HashMap<>();
private RemoteViews mPresentation;
@@ -616,6 +663,14 @@
}
/**
+ * Sets the canned value of a date field based on its {@code autofillId}.
+ */
+ public Builder setField(AutofillId autofillId, AutofillValue value) {
+ mFieldValuesById.put(autofillId, value);
+ return this;
+ }
+
+ /**
* Sets the canned value of a date field based on its {@code id}.
*
* <p>The meaning of the id is defined by the object using the canned dataset.
@@ -643,6 +698,15 @@
}
/**
+ * Sets the canned value of a date field based on its {@code autofillId}.
+ */
+ public Builder setField(AutofillId autofillId, String text, RemoteViews presentation) {
+ setField(autofillId, AutofillValue.forText(text));
+ mFieldPresentationsById.put(autofillId, presentation);
+ return this;
+ }
+
+ /**
* Sets the canned value of a field based on its {@code id}.
*
* <p>The meaning of the id is defined by the object using the canned dataset.
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatasetFilteringTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatasetFilteringTest.java
new file mode 100644
index 0000000..91595a2
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatasetFilteringTest.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts;
+
+import static android.autofillservice.cts.Helper.ID_USERNAME;
+import static android.autofillservice.cts.common.ShellHelper.runShellCommand;
+
+import android.autofillservice.cts.CannedFillResponse.CannedDataset;
+
+import org.junit.Test;
+
+import java.util.regex.Pattern;
+
+public class DatasetFilteringTest extends AbstractLoginActivityTestCase {
+
+ @Test
+ public void testFilter() throws Exception {
+ final String aa = "Two A's";
+ final String ab = "A and B";
+ final String b = "Only B";
+
+ enableService();
+
+ // Set expectations.
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "aa")
+ .setPresentation(createPresentation(aa))
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "ab")
+ .setPresentation(createPresentation(ab))
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "b")
+ .setPresentation(createPresentation(b))
+ .build())
+ .build());
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+ sReplier.getNextFillRequest();
+
+ // With no filter text all datasets should be shown
+ mUiBot.assertDatasets(aa, ab, b);
+
+ // Only two datasets start with 'a'
+ mActivity.onUsername((v) -> v.setText("a"));
+ mUiBot.assertDatasets(aa, ab);
+
+ // Only one dataset start with 'aa'
+ mActivity.onUsername((v) -> v.setText("aa"));
+ mUiBot.assertDatasets(aa);
+
+ // Only two datasets start with 'a'
+ mActivity.onUsername((v) -> v.setText("a"));
+ mUiBot.assertDatasets(aa, ab);
+
+ // With no filter text all datasets should be shown
+ mActivity.onUsername((v) -> v.setText(""));
+ mUiBot.assertDatasets(aa, ab, b);
+
+ // No dataset start with 'aaa'
+ final MyAutofillCallback callback = mActivity.registerCallback();
+ mActivity.onUsername((v) -> v.setText("aaa"));
+ callback.assertUiHiddenEvent(mActivity.getUsername());
+ mUiBot.assertNoDatasets();
+ }
+
+ @Test
+ public void testFilter_usingKeyboard() throws Exception {
+ if (!mCanPassKeys) {
+ return;
+ }
+
+ final String aa = "Two A's";
+ final String ab = "A and B";
+ final String b = "Only B";
+
+ enableService();
+
+ // Set expectations.
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "aa")
+ .setPresentation(createPresentation(aa))
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "ab")
+ .setPresentation(createPresentation(ab))
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "b")
+ .setPresentation(createPresentation(b))
+ .build())
+ .build());
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+ sReplier.getNextFillRequest();
+
+ // With no filter text all datasets should be shown
+ mUiBot.assertDatasets(aa, ab, b);
+
+ // Only two datasets start with 'a'
+ runShellCommand("input keyevent KEYCODE_A");
+ mUiBot.assertDatasets(aa, ab);
+
+ // Only one dataset start with 'aa'
+ runShellCommand("input keyevent KEYCODE_A");
+ mUiBot.assertDatasets(aa);
+
+ // Only two datasets start with 'a'
+ runShellCommand("input keyevent KEYCODE_DEL");
+ mUiBot.assertDatasets(aa, ab);
+
+ // With no filter text all datasets should be shown
+ runShellCommand("input keyevent KEYCODE_DEL");
+ mUiBot.assertDatasets(aa, ab, b);
+
+ // No dataset start with 'aaa'
+ final MyAutofillCallback callback = mActivity.registerCallback();
+ runShellCommand("input keyevent KEYCODE_A");
+ runShellCommand("input keyevent KEYCODE_A");
+ runShellCommand("input keyevent KEYCODE_A");
+ callback.assertUiHiddenEvent(mActivity.getUsername());
+ mUiBot.assertNoDatasets();
+ }
+
+ @Test
+ public void testFilter_nullValuesAlwaysMatched() throws Exception {
+ final String aa = "Two A's";
+ final String ab = "A and B";
+ final String b = "Only B";
+
+ enableService();
+
+ // Set expectations.
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "aa")
+ .setPresentation(createPresentation(aa))
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "ab")
+ .setPresentation(createPresentation(ab))
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, (String) null)
+ .setPresentation(createPresentation(b))
+ .build())
+ .build());
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+ sReplier.getNextFillRequest();
+
+ // With no filter text all datasets should be shown
+ mUiBot.assertDatasets(aa, ab, b);
+
+ // Two datasets start with 'a' and one with null value always shown
+ mActivity.onUsername((v) -> v.setText("a"));
+ mUiBot.assertDatasets(aa, ab, b);
+
+ // One dataset start with 'aa' and one with null value always shown
+ mActivity.onUsername((v) -> v.setText("aa"));
+ mUiBot.assertDatasets(aa, b);
+
+ // Two datasets start with 'a' and one with null value always shown
+ mActivity.onUsername((v) -> v.setText("a"));
+ mUiBot.assertDatasets(aa, ab, b);
+
+ // With no filter text all datasets should be shown
+ mActivity.onUsername((v) -> v.setText(""));
+ mUiBot.assertDatasets(aa, ab, b);
+
+ // No dataset start with 'aaa' and one with null value always shown
+ mActivity.onUsername((v) -> v.setText("aaa"));
+ mUiBot.assertDatasets(b);
+ }
+
+ @Test
+ public void testFilter_differentPrefixes() throws Exception {
+ final String a = "aaa";
+ final String b = "bra";
+ final String c = "cadabra";
+
+ enableService();
+
+ // Set expectations.
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, a)
+ .setPresentation(createPresentation(a))
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, b)
+ .setPresentation(createPresentation(b))
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, c)
+ .setPresentation(createPresentation(c))
+ .build())
+ .build());
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+ sReplier.getNextFillRequest();
+
+ // With no filter text all datasets should be shown
+ mUiBot.assertDatasets(a, b, c);
+
+ mActivity.onUsername((v) -> v.setText("a"));
+ mUiBot.assertDatasets(a);
+
+ mActivity.onUsername((v) -> v.setText("b"));
+ mUiBot.assertDatasets(b);
+
+ mActivity.onUsername((v) -> v.setText("c"));
+ mUiBot.assertDatasets(c);
+ }
+
+ @Test
+ public void testFilter_usingRegex() throws Exception {
+ // Dataset presentations.
+ final String aa = "Two A's";
+ final String ab = "A and B";
+ final String b = "Only B";
+
+ enableService();
+
+ // Set expectations.
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "whatever", Pattern.compile("a|aa"))
+ .setPresentation(createPresentation(aa))
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "whatsoever", createPresentation(ab),
+ Pattern.compile("a|ab"))
+ .build())
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, (String) null, Pattern.compile("b"))
+ .setPresentation(createPresentation(b))
+ .build())
+ .build());
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+ sReplier.getNextFillRequest();
+
+ // With no filter text all datasets should be shown
+ mUiBot.assertDatasets(aa, ab, b);
+
+ // Only two datasets start with 'a'
+ mActivity.onUsername((v) -> v.setText("a"));
+ mUiBot.assertDatasets(aa, ab);
+
+ // Only one dataset start with 'aa'
+ mActivity.onUsername((v) -> v.setText("aa"));
+ mUiBot.assertDatasets(aa);
+
+ // Only two datasets start with 'a'
+ mActivity.onUsername((v) -> v.setText("a"));
+ mUiBot.assertDatasets(aa, ab);
+
+ // With no filter text all datasets should be shown
+ mActivity.onUsername((v) -> v.setText(""));
+ mUiBot.assertDatasets(aa, ab, b);
+
+ // No dataset start with 'aaa'
+ final MyAutofillCallback callback = mActivity.registerCallback();
+ mActivity.onUsername((v) -> v.setText("aaa"));
+ callback.assertUiHiddenEvent(mActivity.getUsername());
+ mUiBot.assertNoDatasets();
+ }
+
+ @Test
+ public void testFilter_disabledUsingNullRegex() throws Exception {
+ // Dataset presentations.
+ final String unfilterable = "Unfilterabled";
+ final String aOrW = "A or W";
+ final String w = "Wazzup";
+
+ enableService();
+
+ // Set expectations.
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ // This dataset has a value but filter is disabled
+ .addDataset(new CannedDataset.Builder()
+ .setUnfilterableField(ID_USERNAME, "a am I")
+ .setPresentation(createPresentation(unfilterable))
+ .build())
+ // This dataset uses pattern to filter
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "whatsoever", createPresentation(aOrW),
+ Pattern.compile("a|aw"))
+ .build())
+ // This dataset uses value to filter
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "wazzup")
+ .setPresentation(createPresentation(w))
+ .build())
+ .build());
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+ sReplier.getNextFillRequest();
+
+ // With no filter text all datasets should be shown
+ mUiBot.assertDatasets(unfilterable, aOrW, w);
+
+ // Only one dataset start with 'a'
+ mActivity.onUsername((v) -> v.setText("a"));
+ mUiBot.assertDatasets(aOrW);
+
+ // No dataset starts with 'aa'
+ mActivity.onUsername((v) -> v.setText("aa"));
+ mUiBot.assertNoDatasets();
+
+ // Only one datasets start with 'a'
+ mActivity.onUsername((v) -> v.setText("a"));
+ mUiBot.assertDatasets(aOrW);
+
+ // With no filter text all datasets should be shown
+ mActivity.onUsername((v) -> v.setText(""));
+ mUiBot.assertDatasets(unfilterable, aOrW, w);
+
+ // Only one datasets start with 'w'
+ mActivity.onUsername((v) -> v.setText("w"));
+ mUiBot.assertDatasets(w);
+
+ // No dataset start with 'aaa'
+ final MyAutofillCallback callback = mActivity.registerCallback();
+ mActivity.onUsername((v) -> v.setText("aaa"));
+ callback.assertUiHiddenEvent(mActivity.getUsername());
+ mUiBot.assertNoDatasets();
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java b/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java
index 29af4a2..65deff56 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java
@@ -20,6 +20,7 @@
import android.view.autofill.AutofillManager;
import android.widget.Button;
import android.widget.EditText;
+import android.widget.GridLayout;
import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;
@@ -45,6 +46,7 @@
public static final String ID_L4C1 = getResourceId(4, 1);
public static final String ID_L4C2 = getResourceId(4, 2);
+ private GridLayout mGrid;
private final EditText[][] mCells = new EditText[4][2];
private Button mSaveButton;
private Button mClearButton;
@@ -55,16 +57,17 @@
setContentView(R.layout.grid_activity);
- mCells[0][0] = (EditText) findViewById(R.id.l1c1);
- mCells[0][1] = (EditText) findViewById(R.id.l1c2);
- mCells[1][0] = (EditText) findViewById(R.id.l2c1);
- mCells[1][1] = (EditText) findViewById(R.id.l2c2);
- mCells[2][0] = (EditText) findViewById(R.id.l3c1);
- mCells[2][1] = (EditText) findViewById(R.id.l3c2);
- mCells[3][0] = (EditText) findViewById(R.id.l4c1);
- mCells[3][1] = (EditText) findViewById(R.id.l4c2);
- mSaveButton = (Button) findViewById(R.id.save);
- mClearButton = (Button) findViewById(R.id.clear);
+ mGrid = findViewById(R.id.grid);
+ mCells[0][0] = findViewById(R.id.l1c1);
+ mCells[0][1] = findViewById(R.id.l1c2);
+ mCells[1][0] = findViewById(R.id.l2c1);
+ mCells[1][1] = findViewById(R.id.l2c2);
+ mCells[2][0] = findViewById(R.id.l3c1);
+ mCells[2][1] = findViewById(R.id.l3c2);
+ mCells[3][0] = findViewById(R.id.l4c1);
+ mCells[3][1] = findViewById(R.id.l4c2);
+ mSaveButton = findViewById(R.id.save);
+ mClearButton = findViewById(R.id.clear);
mSaveButton.setOnClickListener((v) -> save());
mClearButton.setOnClickListener((v) -> resetFields());
@@ -112,6 +115,16 @@
onCell(row, column, (c) -> getAutofillManager().requestAutofill(c));
}
+ public void removeCell(int row, int column) {
+ onCell(row, column, (c) -> mGrid.removeView(c));
+ }
+
+ public void addCell(int row, int column, EditText cell) {
+ mCells[row - 1][column - 1] = cell;
+ // TODO: ideally it should be added in the right place...
+ syncRunOnUiThread(() -> mGrid.addView(cell));
+ }
+
public void triggerAutofill(boolean manually, int row, int column) {
if (manually) {
forceAutofill(row, column);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index 4d11050..7030ace 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -58,6 +58,8 @@
import android.view.autofill.AutofillValue;
import android.webkit.WebView;
+import com.android.compatibility.common.util.RequiredFeatureRule;
+
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
@@ -104,13 +106,17 @@
/**
* Returns whether the node passes the filter for such given id.
*/
- boolean matches(T node, String id);
+ boolean matches(T node, Object id);
}
private static final NodeFilter<ViewNode> RESOURCE_ID_FILTER = (node, id) -> {
return id.equals(node.getIdEntry());
};
+ private static final NodeFilter<ViewNode> AUTOFILL_ID_FILTER = (node, id) -> {
+ return id.equals(node.getAutofillId());
+ };
+
private static final NodeFilter<ViewNode> HTML_NAME_FILTER = (node, id) -> {
return id.equals(getHtmlName(node));
};
@@ -209,7 +215,7 @@
/**
* Gets a node if it matches the filter criteria for the given id.
*/
- static ViewNode findNodeByFilter(@NonNull AssistStructure structure, @NonNull String id,
+ static ViewNode findNodeByFilter(@NonNull AssistStructure structure, @NonNull Object id,
@NonNull NodeFilter<ViewNode> filter) {
Log.v(TAG, "Parsing request for activity " + structure.getActivityComponent());
final int nodes = structure.getWindowNodeCount();
@@ -227,7 +233,7 @@
/**
* Gets a node if it matches the filter criteria for the given id.
*/
- static ViewNode findNodeByFilter(@NonNull List<FillContext> contexts, @NonNull String id,
+ static ViewNode findNodeByFilter(@NonNull List<FillContext> contexts, @NonNull Object id,
@NonNull NodeFilter<ViewNode> filter) {
for (FillContext context : contexts) {
ViewNode node = findNodeByFilter(context.getStructure(), id, filter);
@@ -241,7 +247,7 @@
/**
* Gets a node if it matches the filter criteria for the given id.
*/
- static ViewNode findNodeByFilter(@NonNull ViewNode node, @NonNull String id,
+ static ViewNode findNodeByFilter(@NonNull ViewNode node, @NonNull Object id,
@NonNull NodeFilter<ViewNode> filter) {
if (filter.matches(node, id)) {
return node;
@@ -370,6 +376,14 @@
}
/**
+ * Gets a view (or a descendant of it) that has the given {@code id}, or {@code null} if
+ * not found.
+ */
+ static ViewNode findNodeByAutofillId(AssistStructure structure, AutofillId id) {
+ return findNodeByFilter(structure, id, AUTOFILL_ID_FILTER);
+ }
+
+ /**
* Asserts a text-based node is sanitized.
*/
static void assertTextIsSanitized(ViewNode node) {
@@ -730,6 +744,13 @@
}
/**
+ * Check if autofill window is fullscreen, see com.android.server.autofill.ui.FillUi
+ */
+ public static boolean isAutofillWindowFullScreen(Context context) {
+ return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ }
+
+ /**
* Uses Shell command to get the Autofill logging level.
*/
public static String getLoggingLevel() {
@@ -1160,7 +1181,7 @@
}
}
- public static boolean hasHint(@Nullable String[] hints, @Nullable String expectedHint) {
+ public static boolean hasHint(@Nullable String[] hints, @Nullable Object expectedHint) {
if (hints == null || expectedHint == null) return false;
for (String actualHint : hints) {
if (expectedHint.equals(actualHint)) return true;
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 6137b4b..e0b0aa7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -16,15 +16,12 @@
package android.autofillservice.cts;
-import static android.app.Activity.RESULT_CANCELED;
-import static android.app.Activity.RESULT_OK;
import static android.autofillservice.cts.CannedFillResponse.DO_NOT_REPLY_RESPONSE;
import static android.autofillservice.cts.CannedFillResponse.NO_RESPONSE;
import static android.autofillservice.cts.Helper.ID_PASSWORD;
import static android.autofillservice.cts.Helper.ID_PASSWORD_LABEL;
import static android.autofillservice.cts.Helper.ID_USERNAME;
import static android.autofillservice.cts.Helper.ID_USERNAME_LABEL;
-import static android.autofillservice.cts.Helper.UNUSED_AUTOFILL_VALUE;
import static android.autofillservice.cts.Helper.assertHasFlags;
import static android.autofillservice.cts.Helper.assertNumberOfChildren;
import static android.autofillservice.cts.Helper.assertTextAndValue;
@@ -82,75 +79,23 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.autofill.AutofillManager;
-import android.view.autofill.AutofillValue;
import android.widget.RemoteViews;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.regex.Pattern;
/**
* This is the test case covering most scenarios - other test cases will cover characteristics
* specific to that test's activity (for example, custom views).
*/
-public class LoginActivityTest extends AutoFillServiceTestCase {
+public class LoginActivityTest extends AbstractLoginActivityTestCase {
private static final String TAG = "LoginActivityTest";
- @Rule
- public final AutofillActivityTestRule<LoginActivity> mActivityRule =
- new AutofillActivityTestRule<LoginActivity>(LoginActivity.class);
-
- @Rule
- public final AutofillActivityTestRule<CheckoutActivity> mCheckoutActivityRule =
- new AutofillActivityTestRule<CheckoutActivity>(CheckoutActivity.class, false);
-
- private LoginActivity mActivity;
-
- @Before
- public void setActivity() {
- mActivity = mActivityRule.getActivity();
- }
-
- /**
- * Request focus on username and expect Window event happens.
- */
- void requestFocusOnUsername() throws TimeoutException {
- mUiBot.waitForWindowChange(() -> mActivity.onUsername(View::requestFocus),
- Timeouts.UI_TIMEOUT.getMaxValue());
- }
-
- /**
- * Request focus on username and expect no Window event happens.
- */
- void requestFocusOnUsernameNoWindowChange() {
- try {
- // TODO: define a small value in Timeout
- mUiBot.waitForWindowChange(() -> mActivity.onUsername(View::requestFocus),
- Timeouts.UI_TIMEOUT.ms());
- } catch (TimeoutException ex) {
- // no window events! looking good
- return;
- }
- throw new IllegalStateException("Expect no window event when focusing to"
- + " username, but event happened");
- }
-
- /**
- * Request focus on password and expect Window event happens.
- */
- void requestFocusOnPassword() throws TimeoutException {
- mUiBot.waitForWindowChange(() -> mActivity.onPassword(View::requestFocus),
- Timeouts.UI_TIMEOUT.getMaxValue());
- }
-
@Test
public void testAutoFillNoDatasets() throws Exception {
// Set service.
@@ -1184,270 +1129,6 @@
}
@Test
- public void filterText() throws Exception {
- final String AA = "Two A's";
- final String AB = "A and B";
- final String B = "Only B";
-
- enableService();
-
- // Set expectations.
- sReplier.addResponse(new CannedFillResponse.Builder()
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "aa")
- .setPresentation(createPresentation(AA))
- .build())
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "ab")
- .setPresentation(createPresentation(AB))
- .build())
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "b")
- .setPresentation(createPresentation(B))
- .build())
- .build());
-
- // Trigger auto-fill.
- requestFocusOnUsername();
- sReplier.getNextFillRequest();
-
- // With no filter text all datasets should be shown
- mUiBot.assertDatasets(AA, AB, B);
-
- // Only two datasets start with 'a'
- mActivity.onUsername((v) -> v.setText("a"));
- mUiBot.assertDatasets(AA, AB);
-
- // Only one dataset start with 'aa'
- mActivity.onUsername((v) -> v.setText("aa"));
- mUiBot.assertDatasets(AA);
-
- // Only two datasets start with 'a'
- mActivity.onUsername((v) -> v.setText("a"));
- mUiBot.assertDatasets(AA, AB);
-
- // With no filter text all datasets should be shown
- mActivity.onUsername((v) -> v.setText(""));
- mUiBot.assertDatasets(AA, AB, B);
-
- // No dataset start with 'aaa'
- final MyAutofillCallback callback = mActivity.registerCallback();
- mActivity.onUsername((v) -> v.setText("aaa"));
- callback.assertUiHiddenEvent(mActivity.getUsername());
- mUiBot.assertNoDatasets();
- }
-
- @Test
- public void filterTextNullValuesAlwaysMatched() throws Exception {
- final String AA = "Two A's";
- final String AB = "A and B";
- final String B = "Only B";
-
- enableService();
-
- // Set expectations.
- sReplier.addResponse(new CannedFillResponse.Builder()
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "aa")
- .setPresentation(createPresentation(AA))
- .build())
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "ab")
- .setPresentation(createPresentation(AB))
- .build())
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, (String) null)
- .setPresentation(createPresentation(B))
- .build())
- .build());
-
- // Trigger auto-fill.
- requestFocusOnUsername();
- sReplier.getNextFillRequest();
-
- // With no filter text all datasets should be shown
- mUiBot.assertDatasets(AA, AB, B);
-
- // Two datasets start with 'a' and one with null value always shown
- mActivity.onUsername((v) -> v.setText("a"));
- mUiBot.assertDatasets(AA, AB, B);
-
- // One dataset start with 'aa' and one with null value always shown
- mActivity.onUsername((v) -> v.setText("aa"));
- mUiBot.assertDatasets(AA, B);
-
- // Two datasets start with 'a' and one with null value always shown
- mActivity.onUsername((v) -> v.setText("a"));
- mUiBot.assertDatasets(AA, AB, B);
-
- // With no filter text all datasets should be shown
- mActivity.onUsername((v) -> v.setText(""));
- mUiBot.assertDatasets(AA, AB, B);
-
- // No dataset start with 'aaa' and one with null value always shown
- mActivity.onUsername((v) -> v.setText("aaa"));
- mUiBot.assertDatasets(B);
- }
-
- @Test
- public void filterTextDifferentPrefixes() throws Exception {
- final String A = "aaa";
- final String B = "bra";
- final String C = "cadabra";
-
- enableService();
-
- // Set expectations.
- sReplier.addResponse(new CannedFillResponse.Builder()
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, A)
- .setPresentation(createPresentation(A))
- .build())
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, B)
- .setPresentation(createPresentation(B))
- .build())
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, C)
- .setPresentation(createPresentation(C))
- .build())
- .build());
-
- // Trigger auto-fill.
- requestFocusOnUsername();
- sReplier.getNextFillRequest();
-
- // With no filter text all datasets should be shown
- mUiBot.assertDatasets(A, B, C);
-
- mActivity.onUsername((v) -> v.setText("a"));
- mUiBot.assertDatasets(A);
-
- mActivity.onUsername((v) -> v.setText("b"));
- mUiBot.assertDatasets(B);
-
- mActivity.onUsername((v) -> v.setText("c"));
- mUiBot.assertDatasets(C);
- }
-
- @Test
- public void filterTextUsingRegex() throws Exception {
- // Dataset presentations.
- final String aa = "Two A's";
- final String ab = "A and B";
- final String b = "Only B";
-
- enableService();
-
- // Set expectations.
- sReplier.addResponse(new CannedFillResponse.Builder()
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "whatever", Pattern.compile("a|aa"))
- .setPresentation(createPresentation(aa))
- .build())
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "whatsoever", createPresentation(ab),
- Pattern.compile("a|ab"))
- .build())
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, (String) null, Pattern.compile("b"))
- .setPresentation(createPresentation(b))
- .build())
- .build());
-
- // Trigger auto-fill.
- requestFocusOnUsername();
- sReplier.getNextFillRequest();
-
- // With no filter text all datasets should be shown
- mUiBot.assertDatasets(aa, ab, b);
-
- // Only two datasets start with 'a'
- mActivity.onUsername((v) -> v.setText("a"));
- mUiBot.assertDatasets(aa, ab);
-
- // Only one dataset start with 'aa'
- mActivity.onUsername((v) -> v.setText("aa"));
- mUiBot.assertDatasets(aa);
-
- // Only two datasets start with 'a'
- mActivity.onUsername((v) -> v.setText("a"));
- mUiBot.assertDatasets(aa, ab);
-
- // With no filter text all datasets should be shown
- mActivity.onUsername((v) -> v.setText(""));
- mUiBot.assertDatasets(aa, ab, b);
-
- // No dataset start with 'aaa'
- final MyAutofillCallback callback = mActivity.registerCallback();
- mActivity.onUsername((v) -> v.setText("aaa"));
- callback.assertUiHiddenEvent(mActivity.getUsername());
- mUiBot.assertNoDatasets();
- }
-
- @Test
- public void filterTextDisabledUsingNullRegex() throws Exception {
- // Dataset presentations.
- final String unfilterable = "Unfilterabled";
- final String aOrW = "A or W";
- final String w = "Wazzup";
-
- enableService();
-
- // Set expectations.
- sReplier.addResponse(new CannedFillResponse.Builder()
- // This dataset has a value but filter is disabled
- .addDataset(new CannedDataset.Builder()
- .setUnfilterableField(ID_USERNAME, "a am I")
- .setPresentation(createPresentation(unfilterable))
- .build())
- // This dataset uses pattern to filter
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "whatsoever", createPresentation(aOrW),
- Pattern.compile("a|aw"))
- .build())
- // This dataset uses value to filter
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "wazzup")
- .setPresentation(createPresentation(w))
- .build())
- .build());
-
- // Trigger auto-fill.
- requestFocusOnUsername();
- sReplier.getNextFillRequest();
-
- // With no filter text all datasets should be shown
- mUiBot.assertDatasets(unfilterable, aOrW, w);
-
- // Only one dataset start with 'a'
- mActivity.onUsername((v) -> v.setText("a"));
- mUiBot.assertDatasets(aOrW);
-
- // No dataset starts with 'aa'
- mActivity.onUsername((v) -> v.setText("aa"));
- mUiBot.assertNoDatasets();
-
- // Only one datasets start with 'a'
- mActivity.onUsername((v) -> v.setText("a"));
- mUiBot.assertDatasets(aOrW);
-
- // With no filter text all datasets should be shown
- mActivity.onUsername((v) -> v.setText(""));
- mUiBot.assertDatasets(unfilterable, aOrW, w);
-
- // Only one datasets start with 'w'
- mActivity.onUsername((v) -> v.setText("w"));
- mUiBot.assertDatasets(w);
-
- // No dataset start with 'aaa'
- final MyAutofillCallback callback = mActivity.registerCallback();
- mActivity.onUsername((v) -> v.setText("aaa"));
- callback.assertUiHiddenEvent(mActivity.getUsername());
- mUiBot.assertNoDatasets();
- }
-
- @Test
public void testSaveOnly() throws Exception {
saveOnlyTest(false);
}
@@ -1939,1115 +1620,6 @@
}
@Test
- public void testFillResponseAuthBothFields() throws Exception {
- fillResponseAuthBothFields(false);
- }
-
- @Test
- public void testFillResponseAuthBothFieldsUserCancelsFirstAttempt() throws Exception {
- fillResponseAuthBothFields(true);
- }
-
- private void fillResponseAuthBothFields(boolean cancelFirstAttempt) throws Exception {
- // Set service.
- enableService();
- final MyAutofillCallback callback = mActivity.registerCallback();
-
- // Prepare the authenticated response
- final Bundle clientState = new Bundle();
- clientState.putString("numbers", "4815162342");
- final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
- new CannedFillResponse.Builder().addDataset(
- new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .setId("name")
- .setPresentation(createPresentation("Dataset"))
- .build())
- .setExtras(clientState).build());
-
- // Configure the service behavior
- sReplier.addResponse(new CannedFillResponse.Builder()
- .setAuthentication(authentication, ID_USERNAME, ID_PASSWORD)
- .setPresentation(createPresentation("Tap to auth response"))
- .setExtras(clientState)
- .build());
-
- // Set expectation for the activity
- mActivity.expectAutoFill("dude", "sweet");
-
- // Trigger auto-fill.
- requestFocusOnUsername();
-
- // Wait for onFill() before proceeding.
- sReplier.getNextFillRequest();
- final View username = mActivity.getUsername();
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth response");
-
- // Make sure UI is show on 2nd field as well
- final View password = mActivity.getPassword();
- requestFocusOnPassword();
- callback.assertUiHiddenEvent(username);
- callback.assertUiShownEvent(password);
- mUiBot.assertDatasets("Tap to auth response");
-
- // Now tap on 1st field to show it again...
- requestFocusOnUsername();
- callback.assertUiHiddenEvent(password);
- callback.assertUiShownEvent(username);
-
- if (cancelFirstAttempt) {
- // Trigger the auth dialog, but emulate cancel.
- AuthenticationActivity.setResultCode(RESULT_CANCELED);
- mUiBot.selectDataset("Tap to auth response");
- callback.assertUiHiddenEvent(username);
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth response");
-
- // Make sure it's still shown on other fields...
- requestFocusOnPassword();
- callback.assertUiHiddenEvent(username);
- callback.assertUiShownEvent(password);
- mUiBot.assertDatasets("Tap to auth response");
-
- // Tap on 1st field to show it again...
- requestFocusOnUsername();
- callback.assertUiHiddenEvent(password);
- callback.assertUiShownEvent(username);
- }
-
- // ...and select it this time
- AuthenticationActivity.setResultCode(RESULT_OK);
- mUiBot.selectDataset("Tap to auth response");
- callback.assertUiHiddenEvent(username);
- callback.assertUiShownEvent(username);
- final UiObject2 picker = mUiBot.assertDatasets("Dataset");
- mUiBot.selectDataset(picker, "Dataset");
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Check the results.
- mActivity.assertAutoFilled();
-
- final Bundle data = AuthenticationActivity.getData();
- assertThat(data).isNotNull();
- final String extraValue = data.getString("numbers");
- assertThat(extraValue).isEqualTo("4815162342");
- }
-
- @Test
- public void testFillResponseAuthJustOneField() throws Exception {
- // Set service.
- enableService();
- final MyAutofillCallback callback = mActivity.registerCallback();
-
- // Prepare the authenticated response
- final Bundle clientState = new Bundle();
- clientState.putString("numbers", "4815162342");
- final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
- new CannedFillResponse.Builder().addDataset(
- new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .setPresentation(createPresentation("Dataset"))
- .build())
- .build());
-
- // Configure the service behavior
- sReplier.addResponse(new CannedFillResponse.Builder()
- .setAuthentication(authentication, ID_USERNAME)
- .setIgnoreFields(ID_PASSWORD)
- .setPresentation(createPresentation("Tap to auth response"))
- .setExtras(clientState)
- .build());
-
- // Set expectation for the activity
- mActivity.expectAutoFill("dude", "sweet");
-
- // Trigger auto-fill.
- requestFocusOnUsername();
-
- // Wait for onFill() before proceeding.
- sReplier.getNextFillRequest();
- final View username = mActivity.getUsername();
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth response");
-
- // Make sure UI is not show on 2nd field
- requestFocusOnPassword();
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
- // Now tap on 1st field to show it again...
- requestFocusOnUsername();
- callback.assertUiShownEvent(username);
-
- // ...and select it this time
- mUiBot.selectDataset("Tap to auth response");
- callback.assertUiHiddenEvent(username);
- final UiObject2 picker = mUiBot.assertDatasets("Dataset");
-
- callback.assertUiShownEvent(username);
- mUiBot.selectDataset(picker, "Dataset");
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Check the results.
- mActivity.assertAutoFilled();
- final Bundle data = AuthenticationActivity.getData();
- assertThat(data).isNotNull();
- final String extraValue = data.getString("numbers");
- assertThat(extraValue).isEqualTo("4815162342");
- }
-
- @Test
- public void testFillResponseAuthWhenAppCallsCancel() throws Exception {
- // Set service.
- enableService();
- final MyAutofillCallback callback = mActivity.registerCallback();
-
- // Prepare the authenticated response
- final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
- new CannedFillResponse.Builder().addDataset(
- new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .setId("name")
- .setPresentation(createPresentation("Dataset"))
- .build())
- .build());
-
- // Configure the service behavior
- sReplier.addResponse(new CannedFillResponse.Builder()
- .setAuthentication(authentication, ID_USERNAME, ID_PASSWORD)
- .setPresentation(createPresentation("Tap to auth response"))
- .build());
-
- // Trigger autofill.
- requestFocusOnUsername();
-
- // Wait for onFill() before proceeding.
- sReplier.getNextFillRequest();
- final View username = mActivity.getUsername();
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth response");
-
- // Disables autofill so it's not triggered again after the auth activity is finished
- // (and current session is canceled) and the login activity is resumed.
- username.setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_NO);
-
- // Autofill it.
- final CountDownLatch latch = new CountDownLatch(1);
- AuthenticationActivity.setResultCode(latch, RESULT_OK);
-
- mUiBot.selectDataset("Tap to auth response");
- callback.assertUiHiddenEvent(username);
-
- // Cancel session...
- mActivity.getAutofillManager().cancel();
-
- // ...before finishing the Auth UI.
- latch.countDown();
-
- mUiBot.assertNoDatasets();
- }
-
- @Test
- public void testFillResponseAuthServiceHasNoDataButCanSave() throws Exception {
- fillResponseAuthServiceHasNoDataTest(true);
- }
-
- @Test
- public void testFillResponseAuthServiceHasNoData() throws Exception {
- fillResponseAuthServiceHasNoDataTest(false);
- }
-
- private void fillResponseAuthServiceHasNoDataTest(boolean canSave) throws Exception {
- // Set service.
- enableService();
- final MyAutofillCallback callback = mActivity.registerCallback();
-
- // Prepare the authenticated response
- final CannedFillResponse response = canSave
- ? new CannedFillResponse.Builder()
- .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
- .build()
- : CannedFillResponse.NO_RESPONSE;
-
- final IntentSender authentication =
- AuthenticationActivity.createSender(mContext, 1, response);
-
- // Configure the service behavior
- sReplier.addResponse(new CannedFillResponse.Builder()
- .setAuthentication(authentication, ID_USERNAME, ID_PASSWORD)
- .setPresentation(createPresentation("Tap to auth response"))
- .build());
-
- // Trigger auto-fill.
- requestFocusOnUsername();
-
- // Wait for onFill() before proceeding.
- sReplier.getNextFillRequest();
- final View username = mActivity.getUsername();
- callback.assertUiShownEvent(username);
-
- // Select the authentication dialog.
- mUiBot.selectDataset("Tap to auth response");
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
- }
-
- @Test
- public void testFillResponseAuthClientStateSetOnIntentOnly() throws Exception {
- fillResponseAuthWithClientState(ClientStateLocation.INTENT_ONLY);
- }
-
- @Test
- public void testFillResponseAuthClientStateSetOnFillResponseOnly() throws Exception {
- fillResponseAuthWithClientState(ClientStateLocation.FILL_RESPONSE_ONLY);
- }
-
- @Test
- public void testFillResponseAuthClientStateSetOnIntentAndFillResponse() throws Exception {
- fillResponseAuthWithClientState(ClientStateLocation.BOTH);
- }
-
- enum ClientStateLocation {
- INTENT_ONLY,
- FILL_RESPONSE_ONLY,
- BOTH
- }
-
- private void fillResponseAuthWithClientState(ClientStateLocation where) throws Exception {
- // Set service.
- enableService();
-
- // Prepare the authenticated response
- final CannedFillResponse.Builder authenticatedResponseBuilder =
- new CannedFillResponse.Builder()
- .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .setPresentation(createPresentation("Dataset"))
- .build());
-
- if (where == ClientStateLocation.FILL_RESPONSE_ONLY || where == ClientStateLocation.BOTH) {
- authenticatedResponseBuilder.setExtras(newClientState("CSI", "FromAuthResponse"));
- }
-
- final IntentSender authentication = where == ClientStateLocation.FILL_RESPONSE_ONLY
- ? AuthenticationActivity.createSender(mContext, 1,
- authenticatedResponseBuilder.build())
- : AuthenticationActivity.createSender(mContext, 1,
- authenticatedResponseBuilder.build(), newClientState("CSI", "FromIntent"));
-
- // Configure the service behavior
- sReplier.addResponse(new CannedFillResponse.Builder()
- .setAuthentication(authentication, ID_USERNAME)
- .setIgnoreFields(ID_PASSWORD)
- .setPresentation(createPresentation("Tap to auth response"))
- .setExtras(newClientState("CSI", "FromResponse"))
- .build());
-
- // Set expectation for the activity
- mActivity.expectAutoFill("dude", "sweet");
-
- // Trigger autofill.
- requestFocusOnUsername();
- sReplier.getNextFillRequest();
-
- // Tap authentication request.
- mUiBot.selectDataset("Tap to auth response");
-
- // Tap dataset.
- mUiBot.selectDataset("Dataset");
-
- // Check the results.
- mActivity.assertAutoFilled();
-
- // Now trigger save.
- mActivity.onUsername((v) -> v.setText("malkovich"));
- mActivity.onPassword((v) -> v.setText("malkovich"));
- final String expectedMessage = getWelcomeMessage("malkovich");
- final String actualMessage = mActivity.tapLogin();
- assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
- mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
-
- // Assert client state on authentication activity.
- assertClientState("auth activity", AuthenticationActivity.getData(), "CSI", "FromResponse");
-
- // Assert client state on save request.
- final SaveRequest saveRequest = sReplier.getNextSaveRequest();
- final String expectedValue = where == ClientStateLocation.FILL_RESPONSE_ONLY
- ? "FromAuthResponse" : "FromIntent";
- assertClientState("on save", saveRequest.data, "CSI", expectedValue);
- }
-
- // TODO(on master): move to helper / reuse in other places
- private void assertClientState(String where, Bundle data, String expectedKey,
- String expectedValue) {
- assertWithMessage("no client state on %s", where).that(data).isNotNull();
- final String extraValue = data.getString(expectedKey);
- assertWithMessage("invalid value for %s on %s", expectedKey, where)
- .that(extraValue).isEqualTo(expectedValue);
- }
-
- // TODO(on master): move to helper / reuse in other places
- private Bundle newClientState(String key, String value) {
- final Bundle clientState = new Bundle();
- clientState.putString(key, value);
- return clientState;
- }
-
- @Test
- public void testFillResponseFiltering() throws Exception {
- // Set service.
- enableService();
- final MyAutofillCallback callback = mActivity.registerCallback();
-
- // Prepare the authenticated response
- final Bundle clientState = new Bundle();
- clientState.putString("numbers", "4815162342");
- final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
- new CannedFillResponse.Builder().addDataset(
- new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .setId("name")
- .setPresentation(createPresentation("Dataset"))
- .build())
- .setExtras(clientState).build());
-
- // Configure the service behavior
- sReplier.addResponse(new CannedFillResponse.Builder()
- .setAuthentication(authentication, ID_USERNAME, ID_PASSWORD)
- .setPresentation(createPresentation("Tap to auth response"))
- .setExtras(clientState)
- .build());
-
- // Set expectation for the activity
- mActivity.expectAutoFill("dude", "sweet");
-
- // Trigger auto-fill.
- requestFocusOnUsername();
-
- // Wait for onFill() before proceeding.
- sReplier.getNextFillRequest();
- final View username = mActivity.getUsername();
-
- // Make sure it's showing initially...
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth response");
-
- // ..then type something to hide it.
- mActivity.onUsername((v) -> v.setText("a"));
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Now delete the char and assert it's shown again...
- mActivity.onUsername((v) -> v.setText(""));
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth response");
-
- // ...and select it this time
- AuthenticationActivity.setResultCode(RESULT_OK);
- mUiBot.selectDataset("Tap to auth response");
- callback.assertUiHiddenEvent(username);
- callback.assertUiShownEvent(username);
- final UiObject2 picker = mUiBot.assertDatasets("Dataset");
- mUiBot.selectDataset(picker, "Dataset");
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Check the results.
- mActivity.assertAutoFilled();
-
- final Bundle data = AuthenticationActivity.getData();
- assertThat(data).isNotNull();
- final String extraValue = data.getString("numbers");
- assertThat(extraValue).isEqualTo("4815162342");
- }
-
- @Test
- public void testDatasetAuthTwoFields() throws Exception {
- datasetAuthTwoFields(false);
- }
-
- @Test
- public void testDatasetAuthTwoFieldsUserCancelsFirstAttempt() throws Exception {
- datasetAuthTwoFields(true);
- }
-
- private void datasetAuthTwoFields(boolean cancelFirstAttempt) throws Exception {
- // Set service.
- enableService();
- final MyAutofillCallback callback = mActivity.registerCallback();
-
- // Prepare the authenticated response
- final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
- new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .build());
-
- // Configure the service behavior
- sReplier.addResponse(new CannedFillResponse.Builder()
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
- .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
- .setPresentation(createPresentation("Tap to auth dataset"))
- .setAuthentication(authentication)
- .build())
- .build());
-
- // Set expectation for the activity
- mActivity.expectAutoFill("dude", "sweet");
-
- // Trigger auto-fill.
- requestFocusOnUsername();
-
- // Wait for onFill() before proceeding.
- sReplier.getNextFillRequest();
- final View username = mActivity.getUsername();
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth dataset");
-
- // Make sure UI is show on 2nd field as well
- final View password = mActivity.getPassword();
- requestFocusOnPassword();
- callback.assertUiHiddenEvent(username);
- callback.assertUiShownEvent(password);
- mUiBot.assertDatasets("Tap to auth dataset");
-
- // Now tap on 1st field to show it again...
- requestFocusOnUsername();
- callback.assertUiHiddenEvent(password);
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth dataset");
-
- if (cancelFirstAttempt) {
- // Trigger the auth dialog, but emulate cancel.
- AuthenticationActivity.setResultCode(RESULT_CANCELED);
- mUiBot.selectDataset("Tap to auth dataset");
- callback.assertUiHiddenEvent(username);
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth dataset");
-
- // Make sure it's still shown on other fields...
- requestFocusOnPassword();
- callback.assertUiHiddenEvent(username);
- callback.assertUiShownEvent(password);
- mUiBot.assertDatasets("Tap to auth dataset");
-
- // Tap on 1st field to show it again...
- requestFocusOnUsername();
- callback.assertUiHiddenEvent(password);
- callback.assertUiShownEvent(username);
- }
-
- // ...and select it this time
- AuthenticationActivity.setResultCode(RESULT_OK);
- mUiBot.selectDataset("Tap to auth dataset");
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Check the results.
- mActivity.assertAutoFilled();
- }
-
- @Test
- public void testDatasetAuthTwoFieldsReplaceResponse() throws Exception {
- // Set service.
- enableService();
- final MyAutofillCallback callback = mActivity.registerCallback();
-
- // Prepare the authenticated response
- final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
- new CannedFillResponse.Builder().addDataset(
- new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .setPresentation(createPresentation("Dataset"))
- .build())
- .build());
-
- // Set up the authentication response client state
- final Bundle authentionClientState = new Bundle();
- authentionClientState.putCharSequence("clientStateKey1", "clientStateValue1");
-
- // Configure the service behavior
- sReplier.addResponse(new CannedFillResponse.Builder()
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, (AutofillValue) null)
- .setField(ID_PASSWORD, (AutofillValue) null)
- .setPresentation(createPresentation("Tap to auth dataset"))
- .setAuthentication(authentication)
- .build())
- .setExtras(authentionClientState)
- .build());
-
- // Set expectation for the activity
- mActivity.expectAutoFill("dude", "sweet");
-
- // Trigger auto-fill.
- requestFocusOnUsername();
-
- // Wait for onFill() before proceeding.
- sReplier.getNextFillRequest();
- final View username = mActivity.getUsername();
-
- // Authenticate
- callback.assertUiShownEvent(username);
- mUiBot.selectDataset("Tap to auth dataset");
- callback.assertUiHiddenEvent(username);
-
- // Select a dataset from the new response
- callback.assertUiShownEvent(username);
- mUiBot.selectDataset("Dataset");
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Check the results.
- mActivity.assertAutoFilled();
-
- final Bundle data = AuthenticationActivity.getData();
- assertThat(data).isNotNull();
- final String extraValue = data.getString("clientStateKey1");
- assertThat(extraValue).isEqualTo("clientStateValue1");
- }
-
- @Test
- public void testDatasetAuthTwoFieldsNoValues() throws Exception {
- // Set service.
- enableService();
- final MyAutofillCallback callback = mActivity.registerCallback();
-
- // Create the authentication intent
- final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
- new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .build());
-
- // Configure the service behavior
- sReplier.addResponse(new CannedFillResponse.Builder()
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, (String) null)
- .setField(ID_PASSWORD, (String) null)
- .setPresentation(createPresentation("Tap to auth dataset"))
- .setAuthentication(authentication)
- .build())
- .build());
-
- // Set expectation for the activity
- mActivity.expectAutoFill("dude", "sweet");
-
- // Trigger auto-fill.
- requestFocusOnUsername();
-
- // Wait for onFill() before proceeding.
- sReplier.getNextFillRequest();
- final View username = mActivity.getUsername();
-
- // Authenticate
- callback.assertUiShownEvent(username);
- mUiBot.selectDataset("Tap to auth dataset");
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Check the results.
- mActivity.assertAutoFilled();
- }
-
- @Test
- public void testDatasetAuthTwoDatasets() throws Exception {
- // Set service.
- enableService();
- final MyAutofillCallback callback = mActivity.registerCallback();
-
- // Create the authentication intents
- final CannedDataset unlockedDataset = new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .build();
- final IntentSender authentication1 = AuthenticationActivity.createSender(mContext, 1,
- unlockedDataset);
- final IntentSender authentication2 = AuthenticationActivity.createSender(mContext, 2,
- unlockedDataset);
-
- // Configure the service behavior
- sReplier.addResponse(new CannedFillResponse.Builder()
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
- .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
- .setPresentation(createPresentation("Tap to auth dataset 1"))
- .setAuthentication(authentication1)
- .build())
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
- .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
- .setPresentation(createPresentation("Tap to auth dataset 2"))
- .setAuthentication(authentication2)
- .build())
- .build());
-
- // Set expectation for the activity
- mActivity.expectAutoFill("dude", "sweet");
-
- // Trigger auto-fill.
- requestFocusOnUsername();
-
- // Wait for onFill() before proceeding.
- sReplier.getNextFillRequest();
- final View username = mActivity.getUsername();
-
- // Authenticate
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth dataset 1", "Tap to auth dataset 2");
-
- mUiBot.selectDataset("Tap to auth dataset 1");
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Check the results.
- mActivity.assertAutoFilled();
- }
-
- @Test
- public void testDatasetAuthMixedSelectAuth() throws Exception {
- datasetAuthMixedTest(true);
- }
-
- @Test
- public void testDatasetAuthMixedSelectNonAuth() throws Exception {
- datasetAuthMixedTest(false);
- }
-
- private void datasetAuthMixedTest(boolean selectAuth) throws Exception {
- // Set service.
- enableService();
- final MyAutofillCallback callback = mActivity.registerCallback();
-
- // Prepare the authenticated response
- final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
- new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .build());
-
- // Configure the service behavior
- sReplier.addResponse(new CannedFillResponse.Builder()
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .setPresentation(createPresentation("Tap to auth dataset"))
- .setAuthentication(authentication)
- .build())
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "DUDE")
- .setField(ID_PASSWORD, "SWEET")
- .setPresentation(createPresentation("What, me auth?"))
- .build())
- .build());
-
- // Set expectation for the activity
- if (selectAuth) {
- mActivity.expectAutoFill("dude", "sweet");
- } else {
- mActivity.expectAutoFill("DUDE", "SWEET");
- }
-
- // Trigger auto-fill.
- requestFocusOnUsername();
-
- // Wait for onFill() before proceeding.
- sReplier.getNextFillRequest();
- final View username = mActivity.getUsername();
-
- // Authenticate
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth dataset", "What, me auth?");
-
- final String chosenOne = selectAuth ? "Tap to auth dataset" : "What, me auth?";
- mUiBot.selectDataset(chosenOne);
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Check the results.
- mActivity.assertAutoFilled();
- }
-
- @Test
- public void testDatasetAuthNoFiltering() throws Exception {
- // Set service.
- enableService();
- final MyAutofillCallback callback = mActivity.registerCallback();
-
- // Create the authentication intents
- final CannedDataset unlockedDataset = new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .build();
- final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
- unlockedDataset);
-
- // Configure the service behavior
- sReplier.addResponse(new CannedFillResponse.Builder()
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
- .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
- .setPresentation(createPresentation("Tap to auth dataset"))
- .setAuthentication(authentication)
- .build())
- .build());
-
- // Set expectation for the activity
- mActivity.expectAutoFill("dude", "sweet");
-
- // Trigger auto-fill.
- requestFocusOnUsername();
-
- // Wait for onFill() before proceeding.
- sReplier.getNextFillRequest();
- final View username = mActivity.getUsername();
-
- // Make sure it's showing initially...
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth dataset");
-
- // ..then type something to hide it.
- mActivity.onUsername((v) -> v.setText("a"));
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Now delete the char and assert it's shown again...
- mActivity.onUsername((v) -> v.setText(""));
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth dataset");
-
- // ...and select it this time
- mUiBot.selectDataset("Tap to auth dataset");
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Check the results.
- mActivity.assertAutoFilled();
- }
-
- @Test
- public void testDatasetAuthFilteringUsingAutofillValue() throws Exception {
- // Set service.
- enableService();
- final MyAutofillCallback callback = mActivity.registerCallback();
-
- // Create the authentication intents
- final CannedDataset unlockedDataset = new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .build();
- final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
- unlockedDataset);
-
- // Configure the service behavior
- sReplier.addResponse(new CannedFillResponse.Builder()
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .setPresentation(createPresentation("DS1"))
- .setAuthentication(authentication)
- .build())
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "DUDE,THE")
- .setField(ID_PASSWORD, "SWEET")
- .setPresentation(createPresentation("DS2"))
- .setAuthentication(authentication)
- .build())
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "ZzBottom")
- .setField(ID_PASSWORD, "top")
- .setPresentation(createPresentation("DS3"))
- .setAuthentication(authentication)
- .build())
- .build());
-
- // Set expectation for the activity
- mActivity.expectAutoFill("dude", "sweet");
-
- // Trigger auto-fill.
- requestFocusOnUsername();
-
- // Wait for onFill() before proceeding.
- sReplier.getNextFillRequest();
- final View username = mActivity.getUsername();
-
- // Make sure it's showing initially...
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("DS1", "DS2", "DS3");
-
- // ...then type something to hide them.
- mActivity.onUsername((v) -> v.setText("a"));
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Now delete the char and assert they're shown again...
- mActivity.onUsername((v) -> v.setText(""));
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("DS1", "DS2", "DS3");
-
- // ...then filter for 2
- mActivity.onUsername((v) -> v.setText("d"));
- mUiBot.assertDatasets("DS1", "DS2");
-
- // ...up to 1
- mActivity.onUsername((v) -> v.setText("du"));
- mUiBot.assertDatasets("DS1", "DS2");
- mActivity.onUsername((v) -> v.setText("dud"));
- mUiBot.assertDatasets("DS1", "DS2");
- mActivity.onUsername((v) -> v.setText("dude"));
- mUiBot.assertDatasets("DS1", "DS2");
- mActivity.onUsername((v) -> v.setText("dude,"));
- mUiBot.assertDatasets("DS2");
-
- // Now delete the char and assert 2 are shown again...
- mActivity.onUsername((v) -> v.setText("dude"));
- final UiObject2 picker = mUiBot.assertDatasets("DS1", "DS2");
-
- // ...and select it this time
- mUiBot.selectDataset(picker, "DS1");
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Check the results.
- mActivity.assertAutoFilled();
- }
-
- @Test
- public void testDatasetAuthFilteringUsingRegex() throws Exception {
- // Set service.
- enableService();
- final MyAutofillCallback callback = mActivity.registerCallback();
-
- // Create the authentication intents
- final CannedDataset unlockedDataset = new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .build();
- final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
- unlockedDataset);
-
- // Configure the service behavior
-
- final Pattern min2Chars = Pattern.compile(".{2,}");
- sReplier.addResponse(new CannedFillResponse.Builder()
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE, min2Chars)
- .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
- .setPresentation(createPresentation("Tap to auth dataset"))
- .setAuthentication(authentication)
- .build())
- .build());
-
- // Set expectation for the activity
- mActivity.expectAutoFill("dude", "sweet");
-
- // Trigger auto-fill.
- requestFocusOnUsername();
-
- // Wait for onFill() before proceeding.
- sReplier.getNextFillRequest();
- final View username = mActivity.getUsername();
-
- // Make sure it's showing initially...
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth dataset");
-
- // ...then type something to hide it.
- mActivity.onUsername((v) -> v.setText("a"));
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // ...now type something again to show it, as the input will have 2 chars.
- mActivity.onUsername((v) -> v.setText("aa"));
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth dataset");
-
- // Delete the char and assert it's not shown again...
- mActivity.onUsername((v) -> v.setText("a"));
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // ...then type something again to show it, as the input will have 2 chars.
- mActivity.onUsername((v) -> v.setText("aa"));
- callback.assertUiShownEvent(username);
-
- // ...and select it this time
- mUiBot.selectDataset("Tap to auth dataset");
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Check the results.
- mActivity.assertAutoFilled();
- }
-
- @Test
- public void testDatasetAuthMixedFilteringSelectAuth() throws Exception {
- datasetAuthMixedFilteringTest(true);
- }
-
- @Test
- public void testDatasetAuthMixedFilteringSelectNonAuth() throws Exception {
- datasetAuthMixedFilteringTest(false);
- }
-
- private void datasetAuthMixedFilteringTest(boolean selectAuth) throws Exception {
- // Set service.
- enableService();
- final MyAutofillCallback callback = mActivity.registerCallback();
-
- // Create the authentication intents
- final CannedDataset unlockedDataset = new CannedDataset.Builder()
- .setField(ID_USERNAME, "DUDE")
- .setField(ID_PASSWORD, "SWEET")
- .build();
- final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
- unlockedDataset);
-
- // Configure the service behavior
- sReplier.addResponse(new CannedFillResponse.Builder()
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
- .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
- .setPresentation(createPresentation("Tap to auth dataset"))
- .setAuthentication(authentication)
- .build())
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .setPresentation(createPresentation("What, me auth?"))
- .build())
- .build());
-
- // Set expectation for the activity
- if (selectAuth) {
- mActivity.expectAutoFill("DUDE", "SWEET");
- } else {
- mActivity.expectAutoFill("dude", "sweet");
- }
-
- // Trigger auto-fill.
- requestFocusOnUsername();
-
- // Wait for onFill() before proceeding.
- sReplier.getNextFillRequest();
- final View username = mActivity.getUsername();
-
- // Make sure it's showing initially...
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("Tap to auth dataset", "What, me auth?");
-
- // Filter the auth dataset.
- mActivity.onUsername((v) -> v.setText("d"));
- mUiBot.assertDatasets("What, me auth?");
-
- // Filter all.
- mActivity.onUsername((v) -> v.setText("dw"));
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Now delete the char and assert the non-auth is shown again.
- mActivity.onUsername((v) -> v.setText("d"));
- callback.assertUiShownEvent(username);
- mUiBot.assertDatasets("What, me auth?");
-
- // Delete again and assert all dataset are shown.
- mActivity.onUsername((v) -> v.setText(""));
- mUiBot.assertDatasets("Tap to auth dataset", "What, me auth?");
-
- // ...and select it this time
- final String chosenOne = selectAuth ? "Tap to auth dataset" : "What, me auth?";
- mUiBot.selectDataset(chosenOne);
- callback.assertUiHiddenEvent(username);
- mUiBot.assertNoDatasets();
-
- // Check the results.
- mActivity.assertAutoFilled();
- }
-
- @Test
- public void testDatasetAuthClientStateSetOnIntentOnly() throws Exception {
- fillDatasetAuthWithClientState(ClientStateLocation.INTENT_ONLY);
- }
-
- @Test
- public void testDatasetAuthClientStateSetOnFillResponseOnly() throws Exception {
- fillDatasetAuthWithClientState(ClientStateLocation.FILL_RESPONSE_ONLY);
- }
-
- @Test
- public void testDatasetAuthClientStateSetOnIntentAndFillResponse() throws Exception {
- fillDatasetAuthWithClientState(ClientStateLocation.BOTH);
- }
-
- private void fillDatasetAuthWithClientState(ClientStateLocation where) throws Exception {
- // Set service.
- enableService();
-
- // Prepare the authenticated response
- final CannedDataset dataset = new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
- .build();
- final IntentSender authentication = where == ClientStateLocation.FILL_RESPONSE_ONLY
- ? AuthenticationActivity.createSender(mContext, 1,
- dataset)
- : AuthenticationActivity.createSender(mContext, 1,
- dataset, newClientState("CSI", "FromIntent"));
-
- // Configure the service behavior
- sReplier.addResponse(new CannedFillResponse.Builder()
- .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
- .setExtras(newClientState("CSI", "FromResponse"))
- .addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
- .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
- .setPresentation(createPresentation("Tap to auth dataset"))
- .setAuthentication(authentication)
- .build())
- .build());
-
- // Set expectation for the activity
- mActivity.expectAutoFill("dude", "sweet");
-
- // Trigger auto-fill.
- requestFocusOnUsername();
- sReplier.getNextFillRequest();
-
- // Tap authentication request.
- mUiBot.selectDataset("Tap to auth dataset");
-
- // Check the results.
- mActivity.assertAutoFilled();
-
- // Now trigger save.
- mActivity.onUsername((v) -> v.setText("malkovich"));
- mActivity.onPassword((v) -> v.setText("malkovich"));
- final String expectedMessage = getWelcomeMessage("malkovich");
- final String actualMessage = mActivity.tapLogin();
- assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
- mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
-
- // Assert client state on authentication activity.
- assertClientState("auth activity", AuthenticationActivity.getData(), "CSI", "FromResponse");
-
- // Assert client state on save request.
- final SaveRequest saveRequest = sReplier.getNextSaveRequest();
- final String expectedValue = where == ClientStateLocation.FILL_RESPONSE_ONLY
- ? "FromResponse" : "FromIntent";
- assertClientState("on save", saveRequest.data, "CSI", expectedValue);
- }
-
- @Test
public void testDisableSelf() throws Exception {
enableService();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/MutableAutofillIdTest.java b/tests/autofillservice/src/android/autofillservice/cts/MutableAutofillIdTest.java
new file mode 100644
index 0000000..3c9969f
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/MutableAutofillIdTest.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.autofillservice.cts;
+
+import static android.autofillservice.cts.GridActivity.ID_L1C1;
+import static android.autofillservice.cts.GridActivity.ID_L1C2;
+import static android.autofillservice.cts.Helper.assertTextIsSanitized;
+import static android.autofillservice.cts.Helper.findNodeByAutofillId;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.app.assist.AssistStructure;
+import android.app.assist.AssistStructure.ViewNode;
+import android.autofillservice.cts.CannedFillResponse.CannedDataset;
+import android.autofillservice.cts.GridActivity.FillExpectation;
+import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
+import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
+import android.service.autofill.FillContext;
+import android.support.test.uiautomator.UiObject2;
+import android.util.Log;
+import android.view.autofill.AutofillId;
+import android.widget.EditText;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Test cases for the cases where the autofill id of a view is changed by the app.
+ */
+public class MutableAutofillIdTest extends AutoFillServiceTestCase {
+
+ private static final String TAG = "MutableAutofillIdTest";
+
+ @Rule
+ public final AutofillActivityTestRule<GridActivity> mActivityRule =
+ new AutofillActivityTestRule<GridActivity>(GridActivity.class);
+
+ private GridActivity mActivity;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @Test
+ public void testDatasetPickerIsNotShownAfterViewIsSwappedOut() throws Exception {
+ enableService();
+
+ final EditText field1 = mActivity.getCell(1, 1);
+ final AutofillId oldIdField1 = field1.getAutofillId();
+ final EditText field2 = mActivity.getCell(1, 2);
+ final AutofillId idField2 = field2.getAutofillId();
+
+ // Prepare response
+ final CannedFillResponse response1 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(oldIdField1, "l1c1", createPresentation("l1c1"))
+ .setField(idField2, "l1c2", createPresentation("l1c2"))
+ .build())
+ .build();
+ sReplier.addResponse(response1);
+
+ // Trigger autofill on 1st view.
+ focusCell(1, 1);
+ final FillRequest fillRequest1 = sReplier.getNextFillRequest();
+ final ViewNode node1Request1 = assertTextIsSanitized(fillRequest1.structure, ID_L1C1);
+ assertThat(node1Request1.getAutofillId()).isEqualTo(oldIdField1);
+ mUiBot.assertDatasets("l1c1");
+
+ // Make sure 2nd field shows picker
+ focusCell(1, 2);
+ mUiBot.assertDatasets("l1c2");
+
+ // Now change id of 1st view
+ final AutofillId newIdField1 = mActivity.getAutofillManager().getNextAutofillId();
+
+ // TODO: move to an autofill unit test class for View
+ // Make sure view has to be detached first
+ assertThrows(IllegalStateException.class, () -> field1.setAutofillId(newIdField1));
+
+ // Change id
+ mActivity.removeCell(1, 1);
+
+ // TODO: move to an autofill unit test class for View
+ // Also assert it does not accept virtual ids
+ assertThrows(IllegalStateException.class,
+ () -> field1.setAutofillId(new AutofillId(newIdField1, 42)));
+
+ field1.setAutofillId(newIdField1);
+ assertThat(field1.getAutofillId()).isEqualTo(newIdField1);
+
+ Log.d(TAG, "Changed id of " + ID_L1C1 + " from " + oldIdField1 + " to " + newIdField1);
+
+ // Trigger another request because 1st view has a different id. Service will ignore it now.
+ final CannedFillResponse response2 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(idField2, "l1c2", createPresentation("l1c2"))
+ .build())
+ .build();
+ sReplier.addResponse(response2);
+
+ // Re-add the cell before triggering autofill on it
+ mActivity.addCell(1, 1, field1);
+ mActivity.focusCell(1, 1);
+
+ final FillRequest fillRequest2 = sReplier.getNextFillRequest();
+ final ViewNode node1Request2 = assertTextIsSanitized(fillRequest2.structure, ID_L1C1);
+ // Make sure node has new id.
+ assertThat(node1Request2.getAutofillId()).isEqualTo(newIdField1);
+ mUiBot.assertNoDatasets();
+
+ // Make sure 2nd field shows picker
+ focusCell(1, 2);
+ final UiObject2 datasetPicker = mUiBot.assertDatasets("l1c2");
+
+ // Now autofill
+ final FillExpectation expectation = mActivity.expectAutofill()
+ .onCell(1, 2, "l1c2");
+ mUiBot.selectDataset(datasetPicker, "l1c2");
+ expectation.assertAutoFilled();
+ }
+
+ @Test
+ public void testSave_serviceIgnoresNewId() throws Exception {
+ saveWhenIdChanged(true);
+ }
+
+ @Test
+ public void testSave_serviceExpectingOldId() throws Exception {
+ saveWhenIdChanged(false);
+ }
+
+ private void saveWhenIdChanged(boolean serviceIgnoresNewId) throws Exception {
+ enableService();
+
+ final EditText field1 = mActivity.getCell(1, 1);
+ final AutofillId oldIdField1 = field1.getAutofillId();
+ final EditText field2 = mActivity.getCell(1, 2);
+ final AutofillId idField2 = field2.getAutofillId();
+
+ // Prepare response
+ final CannedFillResponse response1 = new CannedFillResponse.Builder()
+ .setRequiredSavableAutofillIds(SAVE_DATA_TYPE_GENERIC, oldIdField1, idField2)
+ .build();
+ sReplier.addResponse(response1);
+
+ // Trigger autofill on 1st view.
+ mActivity.focusCell(1, 1); // No window change because it's not showing dataset picker.
+ final FillRequest fillRequest1 = sReplier.getNextFillRequest();
+ final ViewNode node1Request1 = assertTextIsSanitized(fillRequest1.structure, ID_L1C1);
+ assertThat(node1Request1.getAutofillId()).isEqualTo(oldIdField1);
+ mUiBot.assertNoDatasets();
+
+ // Make sure 2nd field doesn't trigger a new request
+ mActivity.focusCell(1, 2); // No window change because it's not showing dataset picker.
+ mUiBot.assertNoDatasets();
+
+ // Now change 1st view value...
+ mActivity.setText(1, 1, "OLD");
+ // ...and its id
+ final AutofillId newIdField1 = mActivity.getAutofillManager().getNextAutofillId();
+ mActivity.removeCell(1, 1);
+ field1.setAutofillId(newIdField1);
+ assertThat(field1.getAutofillId()).isEqualTo(newIdField1);
+ Log.d(TAG, "Changed id of " + ID_L1C1 + " from " + oldIdField1 + " to " + newIdField1);
+
+ // Trigger another request because 1st view has a different id...
+ final CannedFillResponse.Builder response2 = new CannedFillResponse.Builder();
+ if (serviceIgnoresNewId) {
+ // ... and service will ignore it now.
+ response2.setRequiredSavableAutofillIds(SAVE_DATA_TYPE_GENERIC, idField2);
+ } else {
+ // ..but service is still expecting the old id.
+ response2.setRequiredSavableAutofillIds(SAVE_DATA_TYPE_GENERIC, oldIdField1, idField2);
+ }
+ sReplier.addResponse(response2.build());
+
+ mActivity.addCell(1, 1, field1);
+ mActivity.focusCell(1, 1); // No window change because it's not showing dataset picker.
+ final FillRequest fillRequest2 = sReplier.getNextFillRequest();
+ final ViewNode node1Request2 = assertTextIsSanitized(fillRequest2.structure, ID_L1C1);
+ // Make sure node has new id.
+ assertThat(node1Request2.getAutofillId()).isEqualTo(newIdField1);
+ mUiBot.assertNoDatasets();
+
+ // Now triggers save
+ mActivity.setText(1, 1, "NEW");
+ mActivity.setText(1, 2, "NOD2");
+ mActivity.save();
+
+ mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_GENERIC);
+ final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+ final List<FillContext> contexts = saveRequest.contexts;
+ assertThat(contexts).hasSize(2);
+
+ // Assert 1st context
+ final AssistStructure structure1 = contexts.get(0).getStructure();
+
+ final ViewNode oldNode1Context1 = findNodeByAutofillId(structure1, oldIdField1);
+ assertThat(oldNode1Context1).isNotNull();
+ assertThat(oldNode1Context1.getIdEntry()).isEqualTo(ID_L1C1);
+ assertThat(oldNode1Context1.getText().toString()).isEqualTo("OLD");
+
+ final ViewNode newNode1Context1 = findNodeByAutofillId(structure1, newIdField1);
+ assertThat(newNode1Context1).isNull();
+
+ final ViewNode node2Context1 = findNodeByAutofillId(structure1, idField2);
+ assertThat(node2Context1).isNotNull();
+ assertThat(node2Context1.getIdEntry()).isEqualTo(ID_L1C2);
+ assertThat(node2Context1.getText().toString()).isEqualTo("NOD2");
+
+ // Assert 2nd context
+ final AssistStructure structure2 = contexts.get(1).getStructure();
+
+ final ViewNode oldNode1Context2 = findNodeByAutofillId(structure2, oldIdField1);
+ assertThat(oldNode1Context2).isNull();
+
+ final ViewNode newNode1Context2 = findNodeByAutofillId(structure2, newIdField1);
+ assertThat(newNode1Context2).isNotNull();
+ assertThat(newNode1Context2.getIdEntry()).isEqualTo(ID_L1C1);
+ assertThat(newNode1Context2.getText().toString()).isEqualTo("NEW");
+
+ final ViewNode node2Context2 = findNodeByAutofillId(structure2, idField2);
+ assertThat(node2Context2).isNotNull();
+ assertThat(node2Context2.getIdEntry()).isEqualTo(ID_L1C2);
+ assertThat(node2Context2.getText().toString()).isEqualTo("NOD2");
+ }
+
+ /**
+ * Focus to a cell and expect window event
+ */
+ void focusCell(int row, int column) throws TimeoutException {
+ mUiBot.waitForWindowChange(() -> mActivity.focusCell(row, column),
+ Timeouts.UI_TIMEOUT.getMaxValue());
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/RetryRule.java b/tests/autofillservice/src/android/autofillservice/cts/RetryRule.java
index 2de94f8..0eda6be 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/RetryRule.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/RetryRule.java
@@ -50,19 +50,29 @@
for (int i = 1; i <= mMaxAttempts; i++) {
try {
base.evaluate();
+ if (i == 1) {
+ Log.v(TAG, "Good News, Everyone! " + name + " passed right away");
+ } else {
+ Log.d(TAG,
+ "Better late than never: " + name + "passed at attempt #" + i);
+ }
return;
} catch (RetryableException e) {
final Timeout timeout = e.getTimeout();
if (timeout != null) {
+ long before = timeout.ms();
timeout.increase();
+ Log.d(TAG, "Increased " + timeout.getName() + " from " + before + "ms "
+ + " to " + timeout.ms() + "ms");
}
caught = e;
} catch (StaleObjectException e) {
caught = e;
}
- Log.w(TAG, name + ": attempt " + i + " failed: " + caught);
+ Log.w(TAG, "Arrrr! " + name + " failed at attempt " + i + "/" + mMaxAttempts
+ + ": " + caught);
}
- Log.e(TAG, name + ": giving up after " + mMaxAttempts + " attempts");
+ Log.e(TAG, "D'OH! " + name + ": giving up after " + mMaxAttempts + " attempts");
throw caught;
}
};
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java b/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java
index 81cf81e..81265e3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java
@@ -24,7 +24,7 @@
/**
* Timeout until framework binds / unbinds from service.
*/
- static final Timeout CONNECTION_TIMEOUT = new Timeout("CONNECTION_TIMEOUT", 1000, 2F, 2000);
+ static final Timeout CONNECTION_TIMEOUT = new Timeout("CONNECTION_TIMEOUT", 1000, 2F, 10000);
/**
* Timeout until framework unbinds from a service.
@@ -39,17 +39,23 @@
/**
* Timeout for expected autofill requests.
*/
- static final Timeout FILL_TIMEOUT = new Timeout("FILL_TIMEOUT", 1000, 2F, 2000);
+ static final Timeout FILL_TIMEOUT = new Timeout("FILL_TIMEOUT", 500, 2F, 10000);
/**
* Timeout for expected save requests.
*/
- static final Timeout SAVE_TIMEOUT = new Timeout("SAVE_TIMEOUT", 2000, 3F, 5000);
+ static final Timeout SAVE_TIMEOUT = new Timeout("SAVE_TIMEOUT", 1000, 2F, 10000);
+
+ /**
+ * Timeout used when save is not expected to be shown - test will sleep for that amount of time
+ * as there is no callback that be received to assert it's not shown.
+ */
+ static final long SAVE_NOT_SHOWN_NAPTIME_MS = 5000;
/**
* Timeout for UI operations. Typically used by {@link UiBot}.
*/
- static final Timeout UI_TIMEOUT = new Timeout("UI_TIMEOUT", 1000, 2F, 2000);
+ static final Timeout UI_TIMEOUT = new Timeout("UI_TIMEOUT", 500, 2F, 10000);
/**
* Timeout for webview operations. Typically used by {@link UiBot}.
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
index bf64dc0..47720d1 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
@@ -16,6 +16,7 @@
package android.autofillservice.cts;
+import static android.autofillservice.cts.Timeouts.SAVE_NOT_SHOWN_NAPTIME_MS;
import static android.autofillservice.cts.Timeouts.SAVE_TIMEOUT;
import static android.autofillservice.cts.Timeouts.UI_DATASET_PICKER_TIMEOUT;
import static android.autofillservice.cts.Timeouts.UI_RECENTS_SWITCH_TIMEOUT;
@@ -399,8 +400,7 @@
* Asserts the save snackbar is not showing and returns it.
*/
void assertSaveNotShowing(int type) throws Exception {
- // TODO: need a better mechanism to wait undefinitely than using getMaxValue()
- assertNeverShown("save UI for type " + type, SAVE_UI_SELECTOR, SAVE_TIMEOUT.getMaxValue());
+ assertNeverShown("save UI for type " + type, SAVE_UI_SELECTOR, SAVE_NOT_SHOWN_NAPTIME_MS);
}
private String getSaveTypeString(int type) {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivity.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivity.java
index 9e8bf57..888201a 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivity.java
@@ -28,6 +28,7 @@
import android.os.Bundle;
import android.util.Log;
import android.view.autofill.AutofillId;
+import android.widget.EditText;
/**
* A custom activity that uses {@link Canvas} to draw the following fields:
@@ -44,6 +45,7 @@
static final String BLANK_VALUE = " ";
+ EditText mUrlBar;
VirtualContainerView mCustomView;
Line mUsername;
@@ -59,8 +61,10 @@
setContentView(R.layout.virtual_container_activity);
+ mUrlBar = findViewById(R.id.my_url_bar);
mCustomView = findViewById(R.id.virtual_container_view);
+ mUrlBar.setText("ftp://dev.null/4/8/15/16/23/42");
mUsername = mCustomView.addLine(ID_USERNAME_LABEL, "Username", ID_USERNAME, BLANK_VALUE);
mPassword = mCustomView.addLine(ID_PASSWORD_LABEL, "Password", ID_PASSWORD, BLANK_VALUE);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java
index b6fb279..54ac252 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityCompatModeTest.java
@@ -15,6 +15,7 @@
*/
package android.autofillservice.cts;
+import static android.autofillservice.cts.Helper.assertTextIsSanitized;
import static android.autofillservice.cts.Helper.getContext;
import static android.autofillservice.cts.Helper.hasAutofillFeature;
import static android.autofillservice.cts.InstrumentedAutoFillServiceCompatMode.SERVICE_NAME;
@@ -22,12 +23,14 @@
import static android.autofillservice.cts.common.SettingsHelper.NAMESPACE_GLOBAL;
import static android.provider.Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES;
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.assist.AssistStructure.ViewNode;
import android.autofillservice.cts.common.SettingsStateChangerRule;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import org.junit.After;
-import org.junit.Before;
import org.junit.ClassRule;
/**
@@ -76,8 +79,15 @@
InstrumentedAutoFillServiceCompatMode.setIgnoreUnexpectedRequests(true);
}
+ @Override
+ protected void assertUrlBarIsSanitized(ViewNode urlBar) {
+ assertTextIsSanitized(urlBar);
+ assertThat(urlBar.getWebDomain()).isEqualTo("dev.null");
+ assertThat(urlBar.getWebScheme()).isEqualTo("ftp");
+ }
+
// TODO(b/72811561): currently only one test pass at time; remove once they all pass
- @Before
+ @After
public void thereCanBeOnlyOne() {
sRanAlready = true;
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
index 72d8d17..ef9f8f0 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
@@ -25,6 +25,7 @@
import static android.autofillservice.cts.Helper.assertTextOnly;
import static android.autofillservice.cts.Helper.dumpStructure;
import static android.autofillservice.cts.Helper.findNodeByResourceId;
+import static android.autofillservice.cts.VirtualContainerView.ID_URL_BAR;
import static android.autofillservice.cts.VirtualContainerView.LABEL_CLASS;
import static android.autofillservice.cts.VirtualContainerView.TEXT_CLASS;
import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_PASSWORD;
@@ -37,7 +38,6 @@
import android.autofillservice.cts.CannedFillResponse.CannedDataset;
import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
-import android.autofillservice.cts.VirtualContainerActivityTest.CommitType;
import android.autofillservice.cts.VirtualContainerView.Line;
import android.content.ComponentName;
import android.graphics.Rect;
@@ -162,11 +162,13 @@
// Make sure input was sanitized.
final FillRequest request = sReplier.getNextFillRequest();
+ final ViewNode urlBar = findNodeByResourceId(request.structure, ID_URL_BAR);
final ViewNode usernameLabel = findNodeByResourceId(request.structure, ID_USERNAME_LABEL);
final ViewNode username = findNodeByResourceId(request.structure, ID_USERNAME);
final ViewNode passwordLabel = findNodeByResourceId(request.structure, ID_PASSWORD_LABEL);
final ViewNode password = findNodeByResourceId(request.structure, ID_PASSWORD);
+ assertUrlBarIsSanitized(urlBar);
assertTextIsSanitized(username);
assertTextIsSanitized(password);
assertLabel(usernameLabel, "Username");
@@ -604,6 +606,12 @@
}
}
+ protected void assertUrlBarIsSanitized(ViewNode urlBar) {
+ assertTextIsSanitized(urlBar);
+ assertThat(urlBar.getWebDomain()).isNull();
+ assertThat(urlBar.getWebScheme()).isNull();
+ }
+
// TODO(b/72811561): currently only one test pass at time
protected static boolean sRanAlready = false;
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerView.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerView.java
index d1e4749..f36328c 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerView.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerView.java
@@ -61,6 +61,7 @@
static final String LABEL_CLASS = "my.readonly.view";
static final String TEXT_CLASS = "my.editable.view";
+ static final String ID_URL_BAR = "my_url_bar";
private final ArrayList<Line> mLines = new ArrayList<>();
private final SparseArray<Item> mItems = new SparseArray<>();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Visitor.java b/tests/autofillservice/src/android/autofillservice/cts/Visitor.java
index 96ee370..a8e0314 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Visitor.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Visitor.java
@@ -28,7 +28,7 @@
* }
* </code></pre>
*/
-interface Visitor<T>{
+interface Visitor<T> {
void visit(T view);
}
\ No newline at end of file
diff --git a/tests/backup/app/fullbackup/Android.mk b/tests/backup/app/fullbackup/Android.mk
index ac53252..68bf8f1 100644
--- a/tests/backup/app/fullbackup/Android.mk
+++ b/tests/backup/app/fullbackup/Android.mk
@@ -23,6 +23,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
LOCAL_PACKAGE_NAME := CtsFullBackupApp
+LOCAL_SDK_VERSION := current
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/tests/backup/app/keyvalue/Android.mk b/tests/backup/app/keyvalue/Android.mk
index 3c36f50..f9034db0 100644
--- a/tests/backup/app/keyvalue/Android.mk
+++ b/tests/backup/app/keyvalue/Android.mk
@@ -23,6 +23,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
LOCAL_PACKAGE_NAME := CtsKeyValueBackupApp
+LOCAL_SDK_VERSION := current
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
index 1f6737f..d653f25 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
@@ -576,9 +576,7 @@
if (!staticInfo.isOisDataModeSupported()) {
waiverKeys.add(CaptureResult.STATISTICS_OIS_DATA_MODE);
- waiverKeys.add(CaptureResult.STATISTICS_OIS_TIMESTAMPS);
- waiverKeys.add(CaptureResult.STATISTICS_OIS_X_SHIFTS);
- waiverKeys.add(CaptureResult.STATISTICS_OIS_Y_SHIFTS);
+ waiverKeys.add(CaptureResult.STATISTICS_OIS_SAMPLES);
}
if (staticInfo.isHardwareLevelAtLeastFull()) {
@@ -861,9 +859,7 @@
resultKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP);
resultKeys.add(CaptureResult.STATISTICS_LENS_SHADING_MAP_MODE);
resultKeys.add(CaptureResult.STATISTICS_OIS_DATA_MODE);
- resultKeys.add(CaptureResult.STATISTICS_OIS_TIMESTAMPS);
- resultKeys.add(CaptureResult.STATISTICS_OIS_X_SHIFTS);
- resultKeys.add(CaptureResult.STATISTICS_OIS_Y_SHIFTS);
+ resultKeys.add(CaptureResult.STATISTICS_OIS_SAMPLES);
resultKeys.add(CaptureResult.TONEMAP_CURVE);
resultKeys.add(CaptureResult.TONEMAP_MODE);
resultKeys.add(CaptureResult.TONEMAP_GAMMA);
diff --git a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
index 1d5e911..4361a56 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -33,6 +33,7 @@
import android.hardware.camera2.cts.helpers.StaticMetadata;
import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
import android.hardware.camera2.params.InputConfiguration;
+import android.hardware.camera2.params.OisSample;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.CamcorderProfile;
@@ -1051,33 +1052,21 @@
TotalCaptureResult result =
previewListener.getTotalCaptureResult(CAPTURE_TIMEOUT);
- long[] oisTimestamps = result.get(CaptureResult.STATISTICS_OIS_TIMESTAMPS);
- float[] oisXShifts = result.get(CaptureResult.STATISTICS_OIS_X_SHIFTS);
- float[] oisYShifts = result.get(CaptureResult.STATISTICS_OIS_Y_SHIFTS);
+ OisSample[] oisSamples = result.get(CaptureResult.STATISTICS_OIS_SAMPLES);
if (oisMode == CameraCharacteristics.STATISTICS_OIS_DATA_MODE_OFF) {
mCollector.expectKeyValueEquals(result,
CaptureResult.STATISTICS_OIS_DATA_MODE,
CaptureResult.STATISTICS_OIS_DATA_MODE_OFF);
- mCollector.expectTrue("OIS timestamps reported in OIS_DATA_MODE_OFF",
- oisTimestamps == null || oisTimestamps.length == 0);
- mCollector.expectTrue("OIS x shifts reported in OIS_DATA_MODE_OFF",
- oisXShifts == null || oisXShifts.length == 0);
- mCollector.expectTrue("OIS y shifts reported in OIS_DATA_MODE_OFF",
- oisYShifts == null || oisYShifts.length == 0);
+ mCollector.expectTrue("OIS samples reported in OIS_DATA_MODE_OFF",
+ oisSamples == null || oisSamples.length == 0);
} else if (oisMode == CameraCharacteristics.STATISTICS_OIS_DATA_MODE_ON) {
mCollector.expectKeyValueEquals(result,
CaptureResult.STATISTICS_OIS_DATA_MODE,
CaptureResult.STATISTICS_OIS_DATA_MODE_ON);
- mCollector.expectTrue("OIS timestamps not reported in OIS_DATA_MODE_ON",
- oisTimestamps != null && oisTimestamps.length != 0);
- mCollector.expectTrue(
- "Number of x shifts doesn't match number of OIS timetamps.",
- oisXShifts != null && oisXShifts.length == oisTimestamps.length);
- mCollector.expectTrue(
- "Number of y shifts doesn't match number of OIS timetamps.",
- oisYShifts != null && oisYShifts.length == oisTimestamps.length);
+ mCollector.expectTrue("OIS samples not reported in OIS_DATA_MODE_ON",
+ oisSamples != null && oisSamples.length != 0);
} else {
mCollector.addMessage(String.format("Invalid OIS mode: %d", oisMode));
}
diff --git a/tests/framework/base/activitymanager/Android.mk b/tests/framework/base/activitymanager/Android.mk
index c502843..25cfd6b 100644
--- a/tests/framework/base/activitymanager/Android.mk
+++ b/tests/framework/base/activitymanager/Android.mk
@@ -20,12 +20,14 @@
# Must match the package name in CtsTestCaseList.mk
LOCAL_PACKAGE_NAME := CtsActivityManagerDeviceTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
$(call all-named-files-under,Components.java, app) \
$(call all-named-files-under,Components.java, app27) \
$(call all-named-files-under,Components.java, appDebuggable) \
+ $(call all-named-files-under,Components.java, appDeprecatedSdk) \
$(call all-named-files-under,Components.java, appDisplaySize) \
$(call all-named-files-under,Components.java, appSecondUid) \
$(call all-named-files-under,Components.java, appThirdUid) \
diff --git a/tests/framework/base/activitymanager/AndroidManifest.xml b/tests/framework/base/activitymanager/AndroidManifest.xml
index 7afc2d4..1e79464 100644
--- a/tests/framework/base/activitymanager/AndroidManifest.xml
+++ b/tests/framework/base/activitymanager/AndroidManifest.xml
@@ -57,6 +57,10 @@
<activity android:name="android.server.am.lifecycle.ActivityLifecycleClientTestBase$SecondActivity"/>
+ <activity
+ android:name="android.server.am.lifecycle.ActivityLifecycleClientTestBase$TranslucentActivity"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar" />
+
<activity android:name="android.server.am.StartActivityTests$TestActivity2" />
</application>
diff --git a/tests/framework/base/activitymanager/app/src/android/server/am/BroadcastReceiverActivity.java b/tests/framework/base/activitymanager/app/src/android/server/am/BroadcastReceiverActivity.java
index 9e53e23..282d750 100644
--- a/tests/framework/base/activitymanager/app/src/android/server/am/BroadcastReceiverActivity.java
+++ b/tests/framework/base/activitymanager/app/src/android/server/am/BroadcastReceiverActivity.java
@@ -25,7 +25,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
-import android.server.am.util.ActivityLauncher;
import android.util.Log;
/**
diff --git a/tests/framework/base/activitymanager/app/src/android/server/am/Components.java b/tests/framework/base/activitymanager/app/src/android/server/am/Components.java
index 8310c69..49bcae3 100644
--- a/tests/framework/base/activitymanager/app/src/android/server/am/Components.java
+++ b/tests/framework/base/activitymanager/app/src/android/server/am/Components.java
@@ -20,13 +20,31 @@
import android.server.am.component.ComponentsBase;
public class Components extends ComponentsBase {
+ public static final ComponentName ALT_LAUNCHING_ACTIVITY = component("AltLaunchingActivity");
public static final ComponentName ALWAYS_FOCUSABLE_PIP_ACTIVITY =
component("AlwaysFocusablePipActivity");
public static final ComponentName ANIMATION_TEST_ACTIVITY = component("AnimationTestActivity");
public static final ComponentName ASSISTANT_ACTIVITY = component("AssistantActivity");
+ public static final ComponentName BOTTOM_ACTIVITY = component("BottomActivity");
+ public static final ComponentName BOTTOM_LEFT_LAYOUT_ACTIVITY =
+ component("BottomLeftLayoutActivity");
+ public static final ComponentName BOTTOM_RIGHT_LAYOUT_ACTIVITY =
+ component("BottomRightLayoutActivity");
+ public static final ComponentName BROADCAST_RECEIVER_ACTIVITY =
+ component("BroadcastReceiverActivity");
+ public static final ComponentName DIALOG_WHEN_LARGE_ACTIVITY =
+ component("DialogWhenLargeActivity");
+ public static final ComponentName DISMISS_KEYGUARD_ACTIVITY =
+ component("DismissKeyguardActivity");
public static final ComponentName DOCKED_ACTIVITY = component("DockedActivity");
public static final ComponentName ENTRY_POINT_ALIAS_ACTIVITY =
component("EntryPointAliasActivity");
+ public static final ComponentName FONT_SCALE_ACTIVITY = component("FontScaleActivity");
+ public static final ComponentName FONT_SCALE_NO_RELAUNCH_ACTIVITY =
+ component("FontScaleNoRelaunchActivity");
+ public static final ComponentName FREEFORM_ACTIVITY = component("FreeformActivity");
+ public static final ComponentName LANDSCAPE_ORIENTATION_ACTIVITY =
+ component("LandscapeOrientationActivity");
public static final ComponentName LAUNCH_ASSISTANT_ACTIVITY_FROM_SESSION =
component("LaunchAssistantActivityFromSession");
public static final ComponentName LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK =
@@ -34,17 +52,38 @@
public static final ComponentName LAUNCH_PIP_ON_PIP_ACTIVITY =
component("LaunchPipOnPipActivity");
public static final ComponentName LAUNCHING_ACTIVITY = component("LaunchingActivity");
+ public static final ComponentName LOG_CONFIGURATION_ACTIVITY =
+ component("LogConfigurationActivity");
public static final ComponentName MOVE_TASK_TO_BACK_ACTIVITY =
component("MoveTaskToBackActivity");
+ public static final ComponentName NIGHT_MODE_ACTIVITY = component("NightModeActivity");
public static final ComponentName NO_HISTORY_ACTIVITY = component("NoHistoryActivity");
+ public static final ComponentName NO_RELAUNCH_ACTIVITY = component("NoRelaunchActivity");
+ public static final ComponentName NON_RESIZEABLE_ACTIVITY = component("NonResizeableActivity");
public static final ComponentName PIP_ACTIVITY = component("PipActivity");
+ public static final ComponentName PORTRAIT_ORIENTATION_ACTIVITY =
+ component("PortraitOrientationActivity");
+ public static final ComponentName RESIZEABLE_ACTIVITY = component("ResizeableActivity");
+ public static final ComponentName SHOW_WHEN_LOCKED_ACTIVITY =
+ component("ShowWhenLockedActivity");
+ public static final ComponentName SHOW_WHEN_LOCKED_ATTR_ACTIVITY =
+ component("ShowWhenLockedAttrActivity");
+ public static final ComponentName SINGLE_INSTANCE_ACTIVITY =
+ component("SingleInstanceActivity");
public static final ComponentName SINGLE_TASK_ACTIVITY = component("SingleTaskActivity");
+ public static final ComponentName SLOW_CREATE_ACTIVITY = component("SlowCreateActivity");
public static final ComponentName SPLASHSCREEN_ACTIVITY = component("SplashscreenActivity");
public static final ComponentName SWIPE_REFRESH_ACTIVITY = component("SwipeRefreshActivity");
public static final ComponentName TEST_ACTIVITY = component("TestActivity");
+ public static final ComponentName TOP_ACTIVITY = component("TopActivity");
+ public static final ComponentName TOP_LEFT_LAYOUT_ACTIVITY = component("TopLeftLayoutActivity");
+ public static final ComponentName TOP_RIGHT_LAYOUT_ACTIVITY =
+ component("TopRightLayoutActivity");
public static final ComponentName TRANSLUCENT_ACTIVITY = component("TranslucentActivity");
public static final ComponentName TRANSLUCENT_ASSISTANT_ACTIVITY =
component("TranslucentAssistantActivity");
+ public static final ComponentName TRANSLUCENT_TOP_ACTIVITY =
+ component("TranslucentTopActivity");
public static final ComponentName TURN_SCREEN_ON_ACTIVITY = component("TurnScreenOnActivity");
public static final ComponentName TURN_SCREEN_ON_ATTR_ACTIVITY =
component("TurnScreenOnAttrActivity");
@@ -56,6 +95,9 @@
component("TurnScreenOnSingleTaskActivity");
public static final ComponentName TURN_SCREEN_ON_WITH_RELAYOUT_ACTIVITY =
component("TurnScreenOnWithRelayoutActivity");
+ public static final ComponentName VIRTUAL_DISPLAY_ACTIVITY =
+ component("VirtualDisplayActivity");
+ public static final ComponentName VR_TEST_ACTIVITY = component("VrTestActivity");
public static final ComponentName ASSISTANT_VOICE_INTERACTION_SERVICE =
component("AssistantVoiceInteractionService");
diff --git a/tests/framework/base/activitymanager/app/src/android/server/am/LaunchBroadcastReceiver.java b/tests/framework/base/activitymanager/app/src/android/server/am/LaunchBroadcastReceiver.java
index 1e51cef..f3cb966 100644
--- a/tests/framework/base/activitymanager/app/src/android/server/am/LaunchBroadcastReceiver.java
+++ b/tests/framework/base/activitymanager/app/src/android/server/am/LaunchBroadcastReceiver.java
@@ -19,7 +19,6 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.server.am.util.ActivityLauncher;
import android.util.Log;
/** Broadcast receiver that can launch activities. */
diff --git a/tests/framework/base/activitymanager/app/src/android/server/am/SlowCreateActivity.java b/tests/framework/base/activitymanager/app/src/android/server/am/SlowCreateActivity.java
index 26992c1..4b78fc5 100644
--- a/tests/framework/base/activitymanager/app/src/android/server/am/SlowCreateActivity.java
+++ b/tests/framework/base/activitymanager/app/src/android/server/am/SlowCreateActivity.java
@@ -18,13 +18,14 @@
import android.app.Activity;
import android.os.Bundle;
+import android.os.SystemClock;
+
+import java.util.concurrent.TimeUnit;
public class SlowCreateActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
- try {
- Thread.sleep(2000);
- } catch(InterruptedException e) {}
+ SystemClock.sleep(TimeUnit.SECONDS.toMillis(2));
super.onCreate(savedInstanceState);
}
}
diff --git a/tests/framework/base/activitymanager/app/src/android/server/am/VirtualDisplayActivity.java b/tests/framework/base/activitymanager/app/src/android/server/am/VirtualDisplayActivity.java
index 8947a15..bf96af2 100644
--- a/tests/framework/base/activitymanager/app/src/android/server/am/VirtualDisplayActivity.java
+++ b/tests/framework/base/activitymanager/app/src/android/server/am/VirtualDisplayActivity.java
@@ -18,13 +18,15 @@
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+import static android.server.am.ActivityLauncher.KEY_DISPLAY_ID;
+import static android.server.am.ActivityLauncher.KEY_LAUNCH_ACTIVITY;
+import static android.server.am.ActivityLauncher.KEY_TARGET_ACTIVITY;
import android.app.Activity;
import android.content.Intent;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.os.Bundle;
-import android.server.am.util.ActivityLauncher;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
@@ -227,9 +229,9 @@
private void launchActivity(String activityName, int displayId) {
final Bundle extras = new Bundle();
- extras.putBoolean("launch_activity", true);
- extras.putString("target_activity", activityName);
- extras.putInt("display_id", displayId);
+ extras.putBoolean(KEY_LAUNCH_ACTIVITY, true);
+ extras.putString(KEY_TARGET_ACTIVITY, activityName);
+ extras.putInt(KEY_DISPLAY_ID, displayId);
ActivityLauncher.launchActivityFromExtras(this, extras);
}
}
diff --git a/tests/framework/base/activitymanager/appDeprecatedSdk/Android.mk b/tests/framework/base/activitymanager/appDeprecatedSdk/Android.mk
index d28d30b..2b556f6 100644
--- a/tests/framework/base/activitymanager/appDeprecatedSdk/Android.mk
+++ b/tests/framework/base/activitymanager/appDeprecatedSdk/Android.mk
@@ -19,6 +19,8 @@
# don't include this package in any target
LOCAL_MODULE_TAGS := optional
+LOCAL_STATIC_JAVA_LIBRARIES := cts-am-app-base
+
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SDK_VERSION := 16
diff --git a/tests/framework/base/activitymanager/appDeprecatedSdk/src/android/server/am/deprecatedsdk/Components.java b/tests/framework/base/activitymanager/appDeprecatedSdk/src/android/server/am/deprecatedsdk/Components.java
new file mode 100644
index 0000000..180738d
--- /dev/null
+++ b/tests/framework/base/activitymanager/appDeprecatedSdk/src/android/server/am/deprecatedsdk/Components.java
@@ -0,0 +1,9 @@
+package android.server.am.deprecatedsdk;
+
+import android.content.ComponentName;
+import android.server.am.component.ComponentsBase;
+
+public class Components extends ComponentsBase {
+
+ public static final ComponentName MAIN_ACTIVITY = component(Components.class, "MainActivity");
+}
diff --git a/tests/framework/base/activitymanager/appSecondUid/src/android/server/am/second/LaunchBroadcastReceiver.java b/tests/framework/base/activitymanager/appSecondUid/src/android/server/am/second/LaunchBroadcastReceiver.java
index caa9e9e..1b975ac 100644
--- a/tests/framework/base/activitymanager/appSecondUid/src/android/server/am/second/LaunchBroadcastReceiver.java
+++ b/tests/framework/base/activitymanager/appSecondUid/src/android/server/am/second/LaunchBroadcastReceiver.java
@@ -19,7 +19,7 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.server.am.util.ActivityLauncher;
+import android.server.am.ActivityLauncher;
import android.util.Log;
/** Broadcast receiver that can launch activities. */
diff --git a/tests/framework/base/activitymanager/app_base/Android.mk b/tests/framework/base/activitymanager/app_base/Android.mk
index c395f97..384d715 100644
--- a/tests/framework/base/activitymanager/app_base/Android.mk
+++ b/tests/framework/base/activitymanager/app_base/Android.mk
@@ -8,6 +8,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
android-support-v4 \
+ cts-amwm-util \
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
diff --git a/tests/framework/base/activitymanager/app_base/src/android/server/am/LaunchingActivity.java b/tests/framework/base/activitymanager/app_base/src/android/server/am/LaunchingActivity.java
index 2b8d3be..1eadf61 100644
--- a/tests/framework/base/activitymanager/app_base/src/android/server/am/LaunchingActivity.java
+++ b/tests/framework/base/activitymanager/app_base/src/android/server/am/LaunchingActivity.java
@@ -17,11 +17,8 @@
package android.server.am;
import android.os.Bundle;
-import android.server.am.util.ActivityLauncher;
import android.app.Activity;
import android.content.Intent;
-import android.server.am.util.ActivityLauncher;
-import android.util.Log;
/**
* Activity that launches another activities when new intent is received.
diff --git a/tests/framework/base/activitymanager/app_base/src/android/server/am/component/ComponentsBase.java b/tests/framework/base/activitymanager/app_base/src/android/server/am/component/ComponentsBase.java
index 2843c4c..f6c3471 100644
--- a/tests/framework/base/activitymanager/app_base/src/android/server/am/component/ComponentsBase.java
+++ b/tests/framework/base/activitymanager/app_base/src/android/server/am/component/ComponentsBase.java
@@ -16,24 +16,10 @@
package android.server.am.component;
-import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertThat;
-import android.app.Activity;
-import android.app.Service;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
-import android.content.Context;
-
-import org.hamcrest.Matchers;
-
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.stream.Collectors;
/**
* Base class for Components constants holding class.
diff --git a/tests/framework/base/activitymanager/app_base/src/android/server/am/util/ActivityLauncher.java b/tests/framework/base/activitymanager/app_base/src/android/server/am/util/ActivityLauncher.java
deleted file mode 100644
index 4f60e0a..0000000
--- a/tests/framework/base/activitymanager/app_base/src/android/server/am/util/ActivityLauncher.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.server.am.util;
-
-import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
-import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT;
-
-import android.app.ActivityOptions;
-import android.content.Intent;
-import android.content.ComponentName;
-import android.content.Context;
-import android.net.Uri;
-import android.os.Bundle;
-import android.server.am.TestActivity;
-import android.text.TextUtils;
-import android.util.Log;
-
-/** Utility class which contains common code for launching activities. */
-public class ActivityLauncher {
- private static final String TAG = ActivityLauncher.class.getSimpleName();
-
- public static void launchActivityFromExtras(final Context context, Bundle extras) {
- if (extras == null || !extras.getBoolean("launch_activity")) {
- return;
- }
-
- Log.i(TAG, "launchActivityFromExtras: extras=" + extras);
-
- final Intent newIntent = new Intent();
- final String targetComponent = extras.getString("target_component");
- final String targetActivity = extras.getString("target_activity");
- if (!TextUtils.isEmpty(targetComponent)) {
- newIntent.setComponent(ComponentName.unflattenFromString(targetComponent));
- } else if (targetActivity != null) {
- final String extraPackageName = extras.getString("package_name");
- final String packageName = extraPackageName != null ? extraPackageName
- : context.getApplicationContext().getPackageName();
- newIntent.setComponent(new ComponentName(packageName,
- packageName + "." + targetActivity));
- } else {
- newIntent.setClass(context, TestActivity.class);
- }
-
- if (extras.getBoolean("launch_to_the_side")) {
- newIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_LAUNCH_ADJACENT);
- if (extras.getBoolean("random_data")) {
- final Uri data = new Uri.Builder()
- .path(String.valueOf(System.currentTimeMillis()))
- .build();
- newIntent.setData(data);
- }
- }
- if (extras.getBoolean("multiple_task")) {
- newIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
- }
- if (extras.getBoolean("new_task")) {
- newIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
- }
-
- if (extras.getBoolean("reorder_to_front")) {
- newIntent.addFlags(FLAG_ACTIVITY_REORDER_TO_FRONT);
- }
-
- ActivityOptions options = null;
- final int displayId = extras.getInt("display_id", -1);
- if (displayId != -1) {
- options = ActivityOptions.makeBasic();
- options.setLaunchDisplayId(displayId);
- newIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK);
- }
-
- final Context launchContext = extras.getBoolean("use_application_context") ?
- context.getApplicationContext() : context;
-
- try {
- launchContext.startActivity(newIntent, options != null ? options.toBundle() : null);
- } catch (SecurityException e) {
- Log.e(TAG, "SecurityException launching activity");
- } catch (Exception e) {
- if (extras.getBoolean("suppress_exceptions")) {
- Log.e(TAG, "Exception launching activity");
- } else {
- throw e;
- }
- }
- }
-}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityAndWindowManagerOverrideConfigTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityAndWindowManagerOverrideConfigTests.java
index 0f83cee..21d6c69 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityAndWindowManagerOverrideConfigTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityAndWindowManagerOverrideConfigTests.java
@@ -17,7 +17,10 @@
package android.server.am;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.server.am.ComponentNameUtils.getLogTag;
+import static android.server.am.Components.LOG_CONFIGURATION_ACTIVITY;
import static android.server.am.StateLogger.log;
+import static android.server.am.StateLogger.logAlways;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
@@ -25,6 +28,9 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
+import android.content.ComponentName;
+import android.os.SystemClock;
+
import org.junit.Test;
import java.util.regex.Matcher;
@@ -35,35 +41,33 @@
* atest CtsActivityManagerDeviceTestCases:ActivityAndWindowManagerOverrideConfigTests
*/
public class ActivityAndWindowManagerOverrideConfigTests extends ActivityManagerTestBase {
- private static final String TEST_ACTIVITY_NAME = "LogConfigurationActivity";
private static class ConfigurationChangeObserver {
- private final Pattern mConfigurationChangedPattern =
+ private static final Pattern CONFIGURATION_CHANGED_PATTERN =
Pattern.compile("(.+)Configuration changed: (\\d+),(\\d+)");
private ConfigurationChangeObserver() {
}
- private boolean findConfigurationChange(String activityName, LogSeparator logSeparator)
- throws InterruptedException {
- int tries = 0;
- boolean observedChange = false;
- while (tries < 5 && !observedChange) {
- final String[] lines = getDeviceLogsForComponents(logSeparator, activityName);
+ private boolean findConfigurationChange(
+ ComponentName activityName, LogSeparator logSeparator) {
+ for (int retry = 1; retry <= 5; retry++) {
+ final String[] lines =
+ getDeviceLogsForComponents(logSeparator, getLogTag(activityName));
log("Looking at logcat");
for (int i = lines.length - 1; i >= 0; i--) {
final String line = lines[i].trim();
log(line);
- Matcher matcher = mConfigurationChangedPattern.matcher(line);
+ Matcher matcher = CONFIGURATION_CHANGED_PATTERN.matcher(line);
if (matcher.matches()) {
- observedChange = true;
- break;
+ return true;
}
}
- tries++;
- Thread.sleep(500);
+ logAlways("***Waiting configuration change of " + getLogTag(activityName)
+ + " retry=" + retry);
+ SystemClock.sleep(500);
}
- return observedChange;
+ return false;
}
}
@@ -71,22 +75,22 @@
public void testReceiveOverrideConfigFromRelayout() throws Exception {
assumeTrue("Device doesn't support freeform. Skipping test.", supportsFreeform());
- launchActivity(TEST_ACTIVITY_NAME, WINDOWING_MODE_FREEFORM);
+ launchActivity(LOG_CONFIGURATION_ACTIVITY, WINDOWING_MODE_FREEFORM);
try (final RotationSession rotationSession = new RotationSession()) {
rotationSession.set(ROTATION_0);
LogSeparator logSeparator = clearLogcat();
- resizeActivityTask(TEST_ACTIVITY_NAME, 0, 0, 100, 100);
+ resizeActivityTask(LOG_CONFIGURATION_ACTIVITY, 0, 0, 100, 100);
ConfigurationChangeObserver c = new ConfigurationChangeObserver();
- final boolean reportedSizeAfterResize = c.findConfigurationChange(TEST_ACTIVITY_NAME,
- logSeparator);
+ final boolean reportedSizeAfterResize = c.findConfigurationChange(
+ LOG_CONFIGURATION_ACTIVITY, logSeparator);
assertTrue("Expected to observe configuration change when resizing",
reportedSizeAfterResize);
logSeparator = clearLogcat();
rotationSession.set(ROTATION_180);
- final boolean reportedSizeAfterRotation = c.findConfigurationChange(TEST_ACTIVITY_NAME,
- logSeparator);
+ final boolean reportedSizeAfterRotation = c.findConfigurationChange(
+ LOG_CONFIGURATION_ACTIVITY, logSeparator);
assertFalse("Not expected to observe configuration change after flip rotation",
reportedSizeAfterRotation);
}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java
index 613bda4..accefe5 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java
@@ -25,8 +25,11 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.server.am.ActivityManagerState.STATE_PAUSED;
import static android.server.am.ActivityManagerState.STATE_RESUMED;
+import static android.server.am.Components.ALT_LAUNCHING_ACTIVITY;
import static android.server.am.Components.ALWAYS_FOCUSABLE_PIP_ACTIVITY;
+import static android.server.am.Components.BROADCAST_RECEIVER_ACTIVITY;
import static android.server.am.Components.DOCKED_ACTIVITY;
+import static android.server.am.Components.LAUNCHING_ACTIVITY;
import static android.server.am.Components.LAUNCH_PIP_ON_PIP_ACTIVITY;
import static android.server.am.Components.MOVE_TASK_TO_BACK_ACTIVITY;
import static android.server.am.Components.NO_HISTORY_ACTIVITY;
@@ -39,6 +42,7 @@
import static android.server.am.Components.TURN_SCREEN_ON_SHOW_ON_LOCK_ACTIVITY;
import static android.server.am.Components.TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY;
import static android.server.am.Components.TURN_SCREEN_ON_WITH_RELAYOUT_ACTIVITY;
+import static android.server.am.UiDeviceUtils.pressBackButton;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -169,7 +173,7 @@
// Launch two activities in docked stack.
launchActivityInSplitScreenWithRecents(LAUNCHING_ACTIVITY);
- getLaunchActivityBuilder().setTargetActivityName(BROADCAST_RECEIVER_ACTIVITY).execute();
+ getLaunchActivityBuilder().setTargetActivity(BROADCAST_RECEIVER_ACTIVITY).execute();
mAmWmState.computeState(BROADCAST_RECEIVER_ACTIVITY);
mAmWmState.assertVisibility(BROADCAST_RECEIVER_ACTIVITY, true);
// Launch something to fullscreen stack to make it focused.
@@ -244,13 +248,14 @@
launchActivity(LAUNCHING_ACTIVITY);
// Launch the alternate launching activity from launching activity with reorder to front.
- getLaunchActivityBuilder().setTargetActivityName(ALT_LAUNCHING_ACTIVITY)
+ getLaunchActivityBuilder().setTargetActivity(ALT_LAUNCHING_ACTIVITY)
.setReorderToFront(true).execute();
// Launch the launching activity from the alternate launching activity with reorder to
// front.
- getLaunchActivityBuilder().setTargetActivityName(LAUNCHING_ACTIVITY)
- .setLaunchingActivityName(ALT_LAUNCHING_ACTIVITY).setReorderToFront(true)
+ getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY)
+ .setLaunchingActivity(ALT_LAUNCHING_ACTIVITY)
+ .setReorderToFront(true)
.execute();
// Press back
@@ -279,8 +284,9 @@
launchActivity(LAUNCHING_ACTIVITY);
// Launch the alternate launching activity from launching activity with reorder to front.
- getLaunchActivityBuilder().setTargetActivityName(ALT_LAUNCHING_ACTIVITY)
- .setReorderToFront(true).execute();
+ getLaunchActivityBuilder().setTargetActivity(ALT_LAUNCHING_ACTIVITY)
+ .setReorderToFront(true)
+ .execute();
// Return home
launchHomeActivity();
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java
index 99472b5..3adec21 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java
@@ -17,6 +17,7 @@
package android.server.am;
import static android.server.am.ComponentNameUtils.getActivityName;
+import static android.server.am.UiDeviceUtils.pressHomeButton;
import static android.server.am.debuggable.Components.DEBUGGABLE_APP_ACTIVITY;
import static org.junit.Assert.assertEquals;
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmStartOptionsTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmStartOptionsTests.java
index b5bb1da..ab73fcd 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmStartOptionsTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmStartOptionsTests.java
@@ -20,6 +20,7 @@
import static android.server.am.Components.ENTRY_POINT_ALIAS_ACTIVITY;
import static android.server.am.Components.SINGLE_TASK_ACTIVITY;
import static android.server.am.Components.TEST_ACTIVITY;
+import static android.server.am.UiDeviceUtils.pressHomeButton;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAppConfigurationTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAppConfigurationTests.java
index adf2e14..59a2509 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAppConfigurationTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAppConfigurationTests.java
@@ -22,6 +22,15 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.server.am.ActivityAndWindowManagersState.dpToPx;
import static android.server.am.ActivityManagerState.STATE_RESUMED;
+import static android.server.am.ComponentNameUtils.getWindowName;
+import static android.server.am.Components.BROADCAST_RECEIVER_ACTIVITY;
+import static android.server.am.Components.DIALOG_WHEN_LARGE_ACTIVITY;
+import static android.server.am.Components.LANDSCAPE_ORIENTATION_ACTIVITY;
+import static android.server.am.Components.LAUNCHING_ACTIVITY;
+import static android.server.am.Components.NIGHT_MODE_ACTIVITY;
+import static android.server.am.Components.PORTRAIT_ORIENTATION_ACTIVITY;
+import static android.server.am.Components.RESIZEABLE_ACTIVITY;
+import static android.server.am.Components.TEST_ACTIVITY;
import static android.server.am.StateLogger.log;
import static android.server.am.StateLogger.logE;
import static android.server.am.translucentapp.Components.TRANSLUCENT_LANDSCAPE_ACTIVITY;
@@ -37,10 +46,12 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
+import android.content.ComponentName;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.FlakyTest;
+import org.junit.Ignore;
import org.junit.Test;
import java.util.ArrayList;
@@ -51,12 +62,6 @@
* atest CtsActivityManagerDeviceTestCases:ActivityManagerAppConfigurationTests
*/
public class ActivityManagerAppConfigurationTests extends ActivityManagerTestBase {
- private static final String RESIZEABLE_ACTIVITY_NAME = "ResizeableActivity";
- private static final String TEST_ACTIVITY_NAME = "TestActivity";
- private static final String PORTRAIT_ACTIVITY_NAME = "PortraitOrientationActivity";
- private static final String LANDSCAPE_ACTIVITY_NAME = "LandscapeOrientationActivity";
- private static final String NIGHT_MODE_ACTIVITY = "NightModeActivity";
- private static final String DIALOG_WHEN_LARGE_ACTIVITY = "DialogWhenLargeActivity";
private static final int SMALL_WIDTH_DP = 426;
private static final int SMALL_HEIGHT_DP = 320;
@@ -75,13 +80,13 @@
assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow());
LogSeparator logSeparator = clearLogcat();
- launchActivity(RESIZEABLE_ACTIVITY_NAME, WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
- final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ launchActivity(RESIZEABLE_ACTIVITY, WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
+ final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY,
logSeparator);
logSeparator = clearLogcat();
- setActivityTaskWindowingMode(RESIZEABLE_ACTIVITY_NAME, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ setActivityTaskWindowingMode(RESIZEABLE_ACTIVITY, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY,
logSeparator);
assertSizesAreSane(fullscreenSizes, dockedSizes);
@@ -98,13 +103,13 @@
assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow());
LogSeparator logSeparator = clearLogcat();
- launchActivity(RESIZEABLE_ACTIVITY_NAME, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ launchActivity(RESIZEABLE_ACTIVITY, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY,
logSeparator);
logSeparator = clearLogcat();
- setActivityTaskWindowingMode(RESIZEABLE_ACTIVITY_NAME, WINDOWING_MODE_FULLSCREEN);
- final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ setActivityTaskWindowingMode(RESIZEABLE_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
+ final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY,
logSeparator);
assertSizesAreSane(fullscreenSizes, dockedSizes);
@@ -121,9 +126,9 @@
rotationSession.set(ROTATION_0);
final LogSeparator logSeparator = clearLogcat();
- launchActivity(RESIZEABLE_ACTIVITY_NAME,
+ launchActivity(RESIZEABLE_ACTIVITY,
WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
- final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY,
logSeparator);
rotateAndCheckSizes(rotationSession, initialSizes);
@@ -145,10 +150,12 @@
final LogSeparator logSeparator = clearLogcat();
// Launch our own activity to side in case Recents (or other activity to side) doesn't
// support rotation.
- launchActivitiesInSplitScreen(LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME);
+ launchActivitiesInSplitScreen(
+ getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
// Launch target activity in docked stack.
- getLaunchActivityBuilder().setTargetActivityName(RESIZEABLE_ACTIVITY_NAME).execute();
- final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ getLaunchActivityBuilder().setTargetActivity(RESIZEABLE_ACTIVITY).execute();
+ final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY,
logSeparator);
rotateAndCheckSizes(rotationSession, initialSizes);
@@ -168,8 +175,10 @@
rotationSession.set(ROTATION_0);
final LogSeparator logSeparator = clearLogcat();
- launchActivitiesInSplitScreen(LAUNCHING_ACTIVITY, RESIZEABLE_ACTIVITY_NAME);
- final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ launchActivitiesInSplitScreen(
+ getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivity(RESIZEABLE_ACTIVITY));
+ final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY,
logSeparator);
rotateAndCheckSizes(rotationSession, initialSizes);
@@ -181,8 +190,8 @@
final int[] rotations = { ROTATION_270, ROTATION_180, ROTATION_90, ROTATION_0 };
for (final int rotation : rotations) {
final LogSeparator logSeparator = clearLogcat();
- final int actualStackId = mAmWmState.getAmState().getTaskByActivityName(
- RESIZEABLE_ACTIVITY_NAME).mStackId;
+ final int actualStackId =
+ mAmWmState.getAmState().getTaskByActivity(RESIZEABLE_ACTIVITY).mStackId;
final int displayId = mAmWmState.getAmState().getStackById(actualStackId).mDisplayId;
rotationSession.set(rotation);
final int newDeviceRotation = getDeviceRotation(displayId);
@@ -195,7 +204,7 @@
return;
}
- final ReportedSizes rotatedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+ final ReportedSizes rotatedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY,
logSeparator);
assertSizesRotate(prevSizes, rotatedSizes);
prevSizes = rotatedSizes;
@@ -208,7 +217,7 @@
*/
@Test
public void testSameConfigurationFullSplitFullRelaunch() throws Exception {
- moveActivityFullSplitFull(TEST_ACTIVITY_NAME);
+ moveActivityFullSplitFull(TEST_ACTIVITY);
}
/**
@@ -217,7 +226,7 @@
@Presubmit
@Test
public void testSameConfigurationFullSplitFullNoRelaunch() throws Exception {
- moveActivityFullSplitFull(RESIZEABLE_ACTIVITY_NAME);
+ moveActivityFullSplitFull(RESIZEABLE_ACTIVITY);
}
/**
@@ -227,7 +236,7 @@
* user long-presses overview/recents button to exit split-screen.
* Asserts that initial and final reported sizes in fullscreen stack are the same.
*/
- private void moveActivityFullSplitFull(String activityName) throws Exception {
+ private void moveActivityFullSplitFull(ComponentName activityName) throws Exception {
assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow());
// Launch to fullscreen stack and record size.
@@ -271,7 +280,7 @@
*/
@Test
public void testSameConfigurationSplitFullSplitRelaunch() throws Exception {
- moveActivitySplitFullSplit(TEST_ACTIVITY_NAME);
+ moveActivitySplitFullSplit(TEST_ACTIVITY);
}
/**
@@ -279,7 +288,7 @@
*/
@Test
public void testSameConfigurationSplitFullSplitNoRelaunch() throws Exception {
- moveActivitySplitFullSplit(RESIZEABLE_ACTIVITY_NAME);
+ moveActivitySplitFullSplit(RESIZEABLE_ACTIVITY);
}
/**
@@ -301,8 +310,11 @@
final int smallHeightPx = dpToPx(SMALL_HEIGHT_DP, density);
mAm.resizeStack(stack.mStackId, new Rect(0, 0, smallWidthPx, smallHeightPx));
- mAmWmState.waitForValidState(DIALOG_WHEN_LARGE_ACTIVITY,
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD);
+ mAmWmState.waitForValidState(
+ new WaitForValidActivityState.Builder(DIALOG_WHEN_LARGE_ACTIVITY)
+ .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
+ .setActivityType(ACTIVITY_TYPE_STANDARD)
+ .build());
}
/**
@@ -313,26 +325,26 @@
@FlakyTest(bugId = 71875755)
public void testFullscreenAppOrientationRequests() throws Exception {
LogSeparator logSeparator = clearLogcat();
- launchActivity(PORTRAIT_ACTIVITY_NAME);
- mAmWmState.assertVisibility(PORTRAIT_ACTIVITY_NAME, true /* visible */);
+ launchActivity(PORTRAIT_ORIENTATION_ACTIVITY);
+ mAmWmState.assertVisibility(PORTRAIT_ORIENTATION_ACTIVITY, true /* visible */);
ReportedSizes reportedSizes =
- getLastReportedSizesForActivity(PORTRAIT_ACTIVITY_NAME, logSeparator);
+ getLastReportedSizesForActivity(PORTRAIT_ORIENTATION_ACTIVITY, logSeparator);
assertEquals("portrait activity should be in portrait",
1 /* portrait */, reportedSizes.orientation);
logSeparator = clearLogcat();
- launchActivity(LANDSCAPE_ACTIVITY_NAME);
- mAmWmState.assertVisibility(LANDSCAPE_ACTIVITY_NAME, true /* visible */);
+ launchActivity(LANDSCAPE_ORIENTATION_ACTIVITY);
+ mAmWmState.assertVisibility(LANDSCAPE_ORIENTATION_ACTIVITY, true /* visible */);
reportedSizes =
- getLastReportedSizesForActivity(LANDSCAPE_ACTIVITY_NAME, logSeparator);
+ getLastReportedSizesForActivity(LANDSCAPE_ORIENTATION_ACTIVITY, logSeparator);
assertEquals("landscape activity should be in landscape",
2 /* landscape */, reportedSizes.orientation);
logSeparator = clearLogcat();
- launchActivity(PORTRAIT_ACTIVITY_NAME);
- mAmWmState.assertVisibility(PORTRAIT_ACTIVITY_NAME, true /* visible */);
+ launchActivity(PORTRAIT_ORIENTATION_ACTIVITY);
+ mAmWmState.assertVisibility(PORTRAIT_ORIENTATION_ACTIVITY, true /* visible */);
reportedSizes =
- getLastReportedSizesForActivity(PORTRAIT_ACTIVITY_NAME, logSeparator);
+ getLastReportedSizesForActivity(PORTRAIT_ORIENTATION_ACTIVITY, logSeparator);
assertEquals("portrait activity should be in portrait",
1 /* portrait */, reportedSizes.orientation);
logSeparator = clearLogcat();
@@ -341,9 +353,9 @@
@Test
public void testNonfullscreenAppOrientationRequests() throws Exception {
LogSeparator logSeparator = clearLogcat();
- launchActivity(PORTRAIT_ACTIVITY_NAME);
+ launchActivity(PORTRAIT_ORIENTATION_ACTIVITY);
final ReportedSizes initialReportedSizes =
- getLastReportedSizesForActivity(PORTRAIT_ACTIVITY_NAME, logSeparator);
+ getLastReportedSizesForActivity(PORTRAIT_ORIENTATION_ACTIVITY, logSeparator);
assertEquals("portrait activity should be in portrait",
1 /* portrait */, initialReportedSizes.orientation);
logSeparator = clearLogcat();
@@ -360,13 +372,14 @@
}
// TODO(b/70870253): This test seems malfunction.
- // @Test
+ @Ignore("b/70870253")
+ @Test
public void testNonFullscreenActivityProhibited() throws Exception {
// We do not wait for the activity as it should not launch based on the restrictions around
// specifying orientation. We instead start an activity known to launch immediately after
// so that we can ensure processing the first activity occurred.
launchActivityNoWait(TRANSLUCENT_LANDSCAPE_ACTIVITY);
- launchActivity(PORTRAIT_ACTIVITY_NAME);
+ launchActivity(PORTRAIT_ORIENTATION_ACTIVITY);
assertFalse("target SDK > 26 non-fullscreen activity should not reach onResume",
mAmWmState.getAmState().containsActivity(TRANSLUCENT_LANDSCAPE_ACTIVITY));
@@ -392,8 +405,8 @@
@Test
public void testTaskCloseRestoreOrientation() throws Exception {
// Start landscape activity.
- launchActivity(LANDSCAPE_ACTIVITY_NAME);
- mAmWmState.assertVisibility(LANDSCAPE_ACTIVITY_NAME, true /* visible */);
+ launchActivity(LANDSCAPE_ORIENTATION_ACTIVITY);
+ mAmWmState.assertVisibility(LANDSCAPE_ORIENTATION_ACTIVITY, true /* visible */);
assertEquals("Fullscreen app requested landscape orientation",
0 /* landscape */, mAmWmState.getWmState().getLastOrientation());
@@ -408,8 +421,7 @@
executeShellCommand(FINISH_ACTIVITY_BROADCAST);
// Verify that activity brought to front is in originally requested orientation.
- mAmWmState.computeState(
- new WaitForValidActivityState.Builder(LANDSCAPE_ACTIVITY_NAME).build());
+ mAmWmState.computeState(LANDSCAPE_ORIENTATION_ACTIVITY);
assertEquals("Should return to app in landscape orientation",
0 /* landscape */, mAmWmState.getWmState().getLastOrientation());
}
@@ -422,8 +434,8 @@
@FlakyTest(bugId = 71792393)
public void testTaskMoveToBackOrientation() throws Exception {
// Start landscape activity.
- launchActivity(LANDSCAPE_ACTIVITY_NAME);
- mAmWmState.assertVisibility(LANDSCAPE_ACTIVITY_NAME, true /* visible */);
+ launchActivity(LANDSCAPE_ORIENTATION_ACTIVITY);
+ mAmWmState.assertVisibility(LANDSCAPE_ORIENTATION_ACTIVITY, true /* visible */);
assertEquals("Fullscreen app requested landscape orientation",
0 /* landscape */, mAmWmState.getWmState().getLastOrientation());
@@ -438,7 +450,7 @@
executeShellCommand(MOVE_TASK_TO_BACK_BROADCAST);
// Verify that activity brought to front is in originally requested orientation.
- mAmWmState.waitForValidState(LANDSCAPE_ACTIVITY_NAME);
+ mAmWmState.waitForValidState(LANDSCAPE_ORIENTATION_ACTIVITY);
assertEquals("Should return to app in landscape orientation",
0 /* landscape */, mAmWmState.getWmState().getLastOrientation());
}
@@ -454,7 +466,7 @@
try (final RotationSession rotationSession = new RotationSession()) {
requestOrientationInSplitScreen(rotationSession,
- ROTATION_90 /* portrait */, LANDSCAPE_ACTIVITY_NAME);
+ ROTATION_90 /* portrait */, LANDSCAPE_ORIENTATION_ACTIVITY);
}
}
@@ -468,7 +480,7 @@
try (final RotationSession rotationSession = new RotationSession()) {
requestOrientationInSplitScreen(rotationSession,
- ROTATION_0 /* landscape */, PORTRAIT_ACTIVITY_NAME);
+ ROTATION_0 /* landscape */, PORTRAIT_ORIENTATION_ACTIVITY);
}
}
@@ -477,7 +489,7 @@
* didn't change.
*/
private void requestOrientationInSplitScreen(RotationSession rotationSession, int orientation,
- String activity) throws Exception {
+ ComponentName activity) throws Exception {
assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow());
// Set initial orientation.
@@ -485,15 +497,15 @@
// Launch activities that request orientations and check that device doesn't rotate.
launchActivitiesInSplitScreen(
- getLaunchActivityBuilder().setTargetActivityName(LAUNCHING_ACTIVITY),
- getLaunchActivityBuilder().setTargetActivityName(activity).setMultipleTask(true));
+ getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivity(activity).setMultipleTask(true));
mAmWmState.assertVisibility(activity, true /* visible */);
assertEquals("Split-screen apps shouldn't influence device orientation",
orientation, mAmWmState.getWmState().getRotation());
- getLaunchActivityBuilder().setMultipleTask(true).setTargetActivityName(activity).execute();
- mAmWmState.computeState(new String[] {activity});
+ getLaunchActivityBuilder().setMultipleTask(true).setTargetActivity(activity).execute();
+ mAmWmState.computeState(activity);
mAmWmState.assertVisibility(activity, true /* visible */);
assertEquals("Split-screen apps shouldn't influence device orientation",
orientation, mAmWmState.getWmState().getRotation());
@@ -503,7 +515,7 @@
* Launches activity in docked stack, moves to fullscreen stack and back to docked stack.
* Asserts that initial and final reported sizes in docked stack are the same.
*/
- private void moveActivitySplitFullSplit(String activityName) throws Exception {
+ private void moveActivitySplitFullSplit(ComponentName activityName) throws Exception {
assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow());
// Launch to docked stack and record size.
@@ -587,20 +599,20 @@
assertEquals(firstSize.smallestWidthDp, secondSize.smallestWidthDp);
}
- private ReportedSizes getActivityDisplaySize(String activityName, LogSeparator logSeparator)
- throws Exception {
+ private ReportedSizes getActivityDisplaySize(ComponentName activityName,
+ LogSeparator logSeparator) throws Exception {
mAmWmState.computeState(false /* compareTaskAndStackBounds */,
- new WaitForValidActivityState.Builder(activityName).build());
+ new WaitForValidActivityState(activityName));
final ReportedSizes details = getLastReportedSizesForActivity(activityName, logSeparator);
assertNotNull(details);
return details;
}
- private Rect getDisplayRect(String activityName)
+ private Rect getDisplayRect(ComponentName activityName)
throws Exception {
- final String windowName = getActivityWindowName(activityName);
+ final String windowName = getWindowName(activityName);
- mAmWmState.computeState(new String[] {activityName});
+ mAmWmState.computeState(activityName);
mAmWmState.assertFocusedWindow("Test window must be the front window.", windowName);
final List<WindowManagerState.WindowState> tempWindowList = new ArrayList<>();
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAssistantStackTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAssistantStackTests.java
index fca289c..84c22d2 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAssistantStackTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAssistantStackTests.java
@@ -42,6 +42,7 @@
import static android.server.am.Components.TEST_ACTIVITY;
import static android.server.am.Components.TRANSLUCENT_ASSISTANT_ACTIVITY;
import static android.server.am.Components.TestActivity.TEST_ACTIVITY_ACTION_FINISH_SELF;
+import static android.server.am.UiDeviceUtils.pressBackButton;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertEquals;
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerConfigChangeTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerConfigChangeTests.java
index fd8d9eb..ab1a820 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerConfigChangeTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerConfigChangeTests.java
@@ -17,17 +17,23 @@
package android.server.am;
import static android.server.am.ActivityManagerState.STATE_RESUMED;
+import static android.server.am.ComponentNameUtils.getLogTag;
+import static android.server.am.Components.FONT_SCALE_ACTIVITY;
+import static android.server.am.Components.FONT_SCALE_NO_RELAUNCH_ACTIVITY;
+import static android.server.am.Components.NO_RELAUNCH_ACTIVITY;
+import static android.server.am.Components.TEST_ACTIVITY;
import static android.server.am.StateLogger.log;
import static android.server.am.StateLogger.logE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import android.content.ComponentName;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
import android.server.am.settings.SettingsSession;
-
import android.support.test.filters.FlakyTest;
+
import org.junit.Test;
import java.util.regex.Matcher;
@@ -38,66 +44,61 @@
* atest CtsActivityManagerDeviceTestCases:ActivityManagerConfigChangeTests
*/
public class ActivityManagerConfigChangeTests extends ActivityManagerTestBase {
- private static final String TEST_ACTIVITY_NAME = "TestActivity";
- private static final String NO_RELAUNCH_ACTIVITY_NAME = "NoRelaunchActivity";
-
- private static final String FONT_SCALE_ACTIVITY_NAME = "FontScaleActivity";
- private static final String FONT_SCALE_NO_RELAUNCH_ACTIVITY_NAME =
- "FontScaleNoRelaunchActivity";
private static final float EXPECTED_FONT_SIZE_SP = 10.0f;
@Test
public void testRotation90Relaunch() throws Exception{
// Should relaunch on every rotation and receive no onConfigurationChanged()
- testRotation(TEST_ACTIVITY_NAME, 1, 1, 0);
+ testRotation(TEST_ACTIVITY, 1, 1, 0);
}
@Test
public void testRotation90NoRelaunch() throws Exception {
// Should receive onConfigurationChanged() on every rotation and no relaunch
- testRotation(NO_RELAUNCH_ACTIVITY_NAME, 1, 0, 1);
+ testRotation(NO_RELAUNCH_ACTIVITY, 1, 0, 1);
}
@Test
public void testRotation180Relaunch() throws Exception {
// Should receive nothing
- testRotation(TEST_ACTIVITY_NAME, 2, 0, 0);
+ testRotation(TEST_ACTIVITY, 2, 0, 0);
}
@Test
public void testRotation180NoRelaunch() throws Exception {
// Should receive nothing
- testRotation(NO_RELAUNCH_ACTIVITY_NAME, 2, 0, 0);
+ testRotation(NO_RELAUNCH_ACTIVITY, 2, 0, 0);
}
+ @FlakyTest(bugId = 73701185)
@Presubmit
@Test
public void testChangeFontScaleRelaunch() throws Exception {
// Should relaunch and receive no onConfigurationChanged()
- testChangeFontScale(FONT_SCALE_ACTIVITY_NAME, true /* relaunch */);
+ testChangeFontScale(FONT_SCALE_ACTIVITY, true /* relaunch */);
}
+ @FlakyTest(bugId = 73812451)
@Presubmit
@Test
public void testChangeFontScaleNoRelaunch() throws Exception {
// Should receive onConfigurationChanged() and no relaunch
- testChangeFontScale(FONT_SCALE_NO_RELAUNCH_ACTIVITY_NAME, false /* relaunch */);
+ testChangeFontScale(FONT_SCALE_NO_RELAUNCH_ACTIVITY, false /* relaunch */);
}
- private void testRotation(String activityName, int rotationStep, int numRelaunch,
+ private void testRotation(ComponentName activityName, int rotationStep, int numRelaunch,
int numConfigChange) throws Exception {
launchActivity(activityName);
- final String[] waitForActivitiesVisible = new String[] {activityName};
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(activityName);
final int initialRotation = 4 - rotationStep;
try (final RotationSession rotationSession = new RotationSession()) {
rotationSession.set(initialRotation);
- mAmWmState.computeState(waitForActivitiesVisible);
- final int actualStackId = mAmWmState.getAmState().getTaskByActivityName(
- activityName).mStackId;
+ mAmWmState.computeState(activityName);
+ final int actualStackId =
+ mAmWmState.getAmState().getTaskByActivity(activityName).mStackId;
final int displayId = mAmWmState.getAmState().getStackById(actualStackId).mDisplayId;
final int newDeviceRotation = getDeviceRotation(displayId);
if (newDeviceRotation == INVALID_DEVICE_ROTATION) {
@@ -112,7 +113,7 @@
for (int rotation = 0; rotation < 4; rotation += rotationStep) {
final LogSeparator logSeparator = clearLogcat();
rotationSession.set(rotation);
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(activityName);
assertRelaunchOrConfigChanged(activityName, numRelaunch, numConfigChange,
logSeparator);
}
@@ -129,20 +130,19 @@
}
private void testChangeFontScale(
- String activityName, boolean relaunch) throws Exception {
+ ComponentName activityName, boolean relaunch) throws Exception {
try (final FontScaleSession fontScaleSession = new FontScaleSession()) {
fontScaleSession.set(1.0f);
LogSeparator logSeparator = clearLogcat();
launchActivity(activityName);
- final String[] waitForActivitiesVisible = new String[]{activityName};
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(activityName);
final int densityDpi = getActivityDensityDpi(activityName, logSeparator);
for (float fontScale = 0.85f; fontScale <= 1.3f; fontScale += 0.15f) {
logSeparator = clearLogcat();
fontScaleSession.set(fontScale);
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(activityName);
assertRelaunchOrConfigChanged(activityName, relaunch ? 1 : 0, relaunch ? 0 : 1,
logSeparator);
@@ -164,8 +164,8 @@
final LogSeparator firstLogSeparator = clearLogcat();
// Launch an activity that prints applied config.
- launchActivity(TEST_ACTIVITY_NAME);
- final int assetSeq = readAssetSeqNumber(TEST_ACTIVITY_NAME, firstLogSeparator);
+ launchActivity(TEST_ACTIVITY);
+ final int assetSeq = readAssetSeqNumber(TEST_ACTIVITY, firstLogSeparator);
final LogSeparator logSeparator = clearLogcat();
// Update package info.
@@ -173,8 +173,8 @@
mAmWmState.waitForWithAmState((amState) -> {
// Wait for activity to be resumed and asset seq number to be updated.
try {
- return readAssetSeqNumber(TEST_ACTIVITY_NAME, logSeparator) == assetSeq + 1
- && amState.hasActivityState(TEST_ACTIVITY_NAME, STATE_RESUMED);
+ return readAssetSeqNumber(TEST_ACTIVITY, logSeparator) == assetSeq + 1
+ && amState.hasActivityState(TEST_ACTIVITY, STATE_RESUMED);
} catch (Exception e) {
logE("Error waiting for valid state: " + e.getMessage());
return false;
@@ -182,9 +182,9 @@
}, "Waiting asset sequence number to be updated and for activity to be resumed.");
// Check if activity is relaunched and asset seq is updated.
- assertRelaunchOrConfigChanged(TEST_ACTIVITY_NAME, 1 /* numRelaunch */,
+ assertRelaunchOrConfigChanged(TEST_ACTIVITY, 1 /* numRelaunch */,
0 /* numConfigChange */, logSeparator);
- final int newAssetSeq = readAssetSeqNumber(TEST_ACTIVITY_NAME, logSeparator);
+ final int newAssetSeq = readAssetSeqNumber(TEST_ACTIVITY, logSeparator);
assertEquals("Asset sequence number must be incremented.", assetSeq + 1, newAssetSeq);
}
@@ -192,9 +192,9 @@
"(.+): Configuration: \\{(.*) as.(\\d+)(.*)\\}");
/** Read asset sequence number in last applied configuration from logs. */
- private int readAssetSeqNumber(String activityName, LogSeparator logSeparator)
+ private int readAssetSeqNumber(ComponentName activityName, LogSeparator logSeparator)
throws Exception {
- final String[] lines = getDeviceLogsForComponents(logSeparator, activityName);
+ final String[] lines = getDeviceLogsForComponents(logSeparator, getLogTag(activityName));
for (int i = lines.length - 1; i >= 0; i--) {
final String line = lines[i].trim();
final Matcher matcher = sConfigurationPattern.matcher(line);
@@ -219,9 +219,9 @@
private static Pattern sDeviceDensityPattern = Pattern.compile("^(.+): fontActivityDpi=(.+)$");
- private int getActivityDensityDpi(String activityName, LogSeparator logSeparator)
+ private int getActivityDensityDpi(ComponentName activityName, LogSeparator logSeparator)
throws Exception {
- final String[] lines = getDeviceLogsForComponents(logSeparator, activityName);
+ final String[] lines = getDeviceLogsForComponents(logSeparator, getLogTag(activityName));
for (int i = lines.length - 1; i >= 0; i--) {
final String line = lines[i].trim();
final Matcher matcher = sDeviceDensityPattern.matcher(line);
@@ -236,9 +236,9 @@
private static final Pattern sFontSizePattern = Pattern.compile("^(.+): fontPixelSize=(.+)$");
/** Read the font size in the last log line. */
- private void assertExpectedFontPixelSize(String activityName, int fontPixelSize,
+ private void assertExpectedFontPixelSize(ComponentName activityName, int fontPixelSize,
LogSeparator logSeparator) throws Exception {
- final String[] lines = getDeviceLogsForComponents(logSeparator, activityName);
+ final String[] lines = getDeviceLogsForComponents(logSeparator, getLogTag(activityName));
for (int i = lines.length - 1; i >= 0; i--) {
final String line = lines[i].trim();
final Matcher matcher = sFontSizePattern.matcher(line);
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayKeyguardTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayKeyguardTests.java
index a24b7ad..32262d5 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayKeyguardTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayKeyguardTests.java
@@ -16,6 +16,8 @@
package android.server.am;
+import static android.server.am.Components.DISMISS_KEYGUARD_ACTIVITY;
+
import static org.junit.Assume.assumeTrue;
import android.server.am.ActivityManagerState.ActivityDisplay;
@@ -30,7 +32,6 @@
* atest CtsActivityManagerDeviceTestCases:ActivityManagerDisplayKeyguardTests
*/
public class ActivityManagerDisplayKeyguardTests extends ActivityManagerDisplayTestBase {
- private static final String DISMISS_KEYGUARD_ACTIVITY = "DismissKeyguardActivity";
@Before
@Override
@@ -52,7 +53,6 @@
final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
lockScreenSession.gotoKeyguard();
- mAmWmState.waitForKeyguardShowingAndNotOccluded();
mAmWmState.assertKeyguardShowingAndNotOccluded();
launchActivityOnDisplay(DISMISS_KEYGUARD_ACTIVITY, newDisplay.mId);
mAmWmState.waitForKeyguardShowingAndNotOccluded();
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayLockedKeyguardTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayLockedKeyguardTests.java
index fb8ead8..a68dafd 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayLockedKeyguardTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayLockedKeyguardTests.java
@@ -18,6 +18,10 @@
import static android.server.am.ActivityManagerState.STATE_RESUMED;
import static android.server.am.ActivityManagerState.STATE_STOPPED;
+import static android.server.am.Components.DISMISS_KEYGUARD_ACTIVITY;
+import static android.server.am.Components.SHOW_WHEN_LOCKED_ACTIVITY;
+import static android.server.am.Components.TEST_ACTIVITY;
+import static android.server.am.Components.VIRTUAL_DISPLAY_ACTIVITY;
import static org.junit.Assume.assumeTrue;
@@ -34,11 +38,6 @@
*/
public class ActivityManagerDisplayLockedKeyguardTests extends ActivityManagerDisplayTestBase {
- private static final String TEST_ACTIVITY_NAME = "TestActivity";
- private static final String VIRTUAL_DISPLAY_ACTIVITY = "VirtualDisplayActivity";
- private static final String DISMISS_KEYGUARD_ACTIVITY = "DismissKeyguardActivity";
- private static final String SHOW_WHEN_LOCKED_ACTIVITY = "ShowWhenLockedActivity";
-
@Before
@Override
public void setUp() throws Exception {
@@ -62,21 +61,20 @@
mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
// Launch activity on new secondary display.
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mId);
- mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */);
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
+ mAmWmState.assertVisibility(TEST_ACTIVITY, true /* visible */);
// Lock the device.
lockScreenSession.gotoKeyguard();
- mAmWmState.waitForKeyguardShowingAndNotOccluded();
- mAmWmState.waitForActivityState(TEST_ACTIVITY_NAME, STATE_STOPPED);
- mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, false /* visible */);
+ mAmWmState.waitForActivityState(TEST_ACTIVITY, STATE_STOPPED);
+ mAmWmState.assertVisibility(TEST_ACTIVITY, false /* visible */);
// Unlock and check if visibility is back.
lockScreenSession.unlockDevice()
.enterAndConfirmLockCredential();
mAmWmState.waitForKeyguardGone();
- mAmWmState.waitForActivityState(TEST_ACTIVITY_NAME, STATE_RESUMED);
- mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */);
+ mAmWmState.waitForActivityState(TEST_ACTIVITY, STATE_RESUMED);
+ mAmWmState.assertVisibility(TEST_ACTIVITY, true /* visible */);
}
}
@@ -91,7 +89,6 @@
final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
lockScreenSession.gotoKeyguard();
- mAmWmState.waitForKeyguardShowingAndNotOccluded();
mAmWmState.assertKeyguardShowingAndNotOccluded();
launchActivityOnDisplay(DISMISS_KEYGUARD_ACTIVITY, newDisplay.mId);
lockScreenSession.enterAndConfirmLockCredential();
@@ -109,10 +106,9 @@
final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
lockScreenSession.gotoKeyguard();
- mAmWmState.waitForKeyguardShowingAndNotOccluded();
mAmWmState.assertKeyguardShowingAndNotOccluded();
launchActivity(SHOW_WHEN_LOCKED_ACTIVITY);
- mAmWmState.computeState(new WaitForValidActivityState(SHOW_WHEN_LOCKED_ACTIVITY));
+ mAmWmState.computeState(SHOW_WHEN_LOCKED_ACTIVITY);
mAmWmState.assertVisibility(SHOW_WHEN_LOCKED_ACTIVITY, true);
launchActivityOnDisplay(DISMISS_KEYGUARD_ACTIVITY, newDisplay.mId);
lockScreenSession.enterAndConfirmLockCredential();
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayTestBase.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayTestBase.java
index a13d7811..85bf4d5 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayTestBase.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayTestBase.java
@@ -18,11 +18,14 @@
import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
import static android.server.am.ActivityAndWindowManagersState.DEFAULT_DISPLAY_ID;
+import static android.server.am.ComponentNameUtils.getSimpleClassName;
+import static android.server.am.Components.VIRTUAL_DISPLAY_ACTIVITY;
import static android.server.am.StateLogger.log;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.content.ComponentName;
import android.content.res.Configuration;
import android.provider.Settings;
import android.server.am.ActivityManagerState.ActivityDisplay;
@@ -43,13 +46,9 @@
* @see ActivityManagerDisplayTests
* @see ActivityManagerDisplayLockedKeyguardTests
*/
-public class ActivityManagerDisplayTestBase extends ActivityManagerTestBase {
- private static final String WM_SIZE = "wm size";
- private static final String WM_DENSITY = "wm density";
+class ActivityManagerDisplayTestBase extends ActivityManagerTestBase {
static final int CUSTOM_DENSITY_DPI = 222;
-
- private static final String VIRTUAL_DISPLAY_ACTIVITY = "VirtualDisplayActivity";
private static final int INVALID_DENSITY_DPI = -1;
ActivityDisplay getDisplayState(List<ActivityDisplay> displays, int displayId) {
@@ -196,7 +195,7 @@
private boolean mCanShowWithInsecureKeyguard = false;
private boolean mPublicDisplay = false;
private boolean mResizeDisplay = true;
- private String mLaunchActivity = null;
+ private ComponentName mLaunchActivity = null;
private boolean mSimulateDisplay = false;
private boolean mMustBeCreated = true;
@@ -230,7 +229,7 @@
return this;
}
- public VirtualDisplaySession setLaunchActivity(String launchActivity) {
+ public VirtualDisplaySession setLaunchActivity(ComponentName launchActivity) {
mLaunchActivity = launchActivity;
return this;
}
@@ -307,7 +306,7 @@
if (mLaunchInSplitScreen) {
getLaunchActivityBuilder()
.setToSide(true)
- .setTargetActivityName(VIRTUAL_DISPLAY_ACTIVITY)
+ .setTargetActivity(VIRTUAL_DISPLAY_ACTIVITY)
.execute();
} else {
launchActivity(VIRTUAL_DISPLAY_ACTIVITY);
@@ -337,7 +336,8 @@
if (mLaunchActivity != null) {
createVirtualDisplayCommand
.append(" --es launch_target_activity ")
- .append(mLaunchActivity);
+ // TODO(b/73349193): Should pass component name.
+ .append(getSimpleClassName(mLaunchActivity));
}
executeShellCommand(createVirtualDisplayCommand.toString());
mVirtualDisplayCreated = true;
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayTests.java
index 459aa57..6a0291f 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerDisplayTests.java
@@ -17,6 +17,8 @@
package android.server.am;
import static android.server.am.ActivityAndWindowManagersState.DEFAULT_DISPLAY_ID;
+import static android.server.am.ComponentNameUtils.getActivityName;
+import static android.server.am.Components.TEST_ACTIVITY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeFalse;
@@ -34,7 +36,6 @@
* atest CtsActivityManagerDeviceTestCases:ActivityManagerDisplayTests
*/
public class ActivityManagerDisplayTests extends ActivityManagerDisplayTestBase {
- private static final String TEST_ACTIVITY_NAME = "TestActivity";
/**
* Tests that the global configuration is equal to the default display's override configuration.
@@ -79,18 +80,18 @@
final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
// Launch activity on new secondary display.
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mId);
- mAmWmState.computeState(new WaitForValidActivityState(TEST_ACTIVITY_NAME));
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
+ mAmWmState.computeState(TEST_ACTIVITY);
mAmWmState.assertFocusedActivity("Launched activity must be focused",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
// Check that activity is on the right display.
final int frontStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY_ID);
final ActivityManagerState.ActivityStack frontStack =
mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Launched activity must be resumed",
- getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity);
+ getActivityName(TEST_ACTIVITY), frontStack.mResumedActivity);
assertEquals("Front stack must be on the default display", DEFAULT_DISPLAY_ID,
frontStack.mDisplayId);
mAmWmState.assertFocusedStack("Focus must be on the default display", frontStackId);
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerFreeformStackTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerFreeformStackTests.java
index 64f79b7..d8808ea 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerFreeformStackTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerFreeformStackTests.java
@@ -18,6 +18,11 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.server.am.Components.FREEFORM_ACTIVITY;
+import static android.server.am.Components.NON_RESIZEABLE_ACTIVITY;
+import static android.server.am.Components.NO_RELAUNCH_ACTIVITY;
+import static android.server.am.Components.TEST_ACTIVITY;
+
import static org.junit.Assert.assertEquals;
import android.graphics.Rect;
@@ -32,7 +37,6 @@
*/
public class ActivityManagerFreeformStackTests extends ActivityManagerTestBase {
- private static final String TEST_ACTIVITY = "TestActivity";
private static final int TEST_TASK_OFFSET = 20;
private static final int TEST_TASK_OFFSET_2 = 100;
private static final int TEST_TASK_SIZE_1 = 900;
@@ -42,9 +46,6 @@
// NOTE: Launching the FreeformActivity will automatically launch the TestActivity
// with bounds (0, 0, 900, 900)
- private static final String FREEFORM_ACTIVITY = "FreeformActivity";
- private static final String NON_RESIZEABLE_ACTIVITY = "NonResizeableActivity";
- private static final String NO_RELAUNCH_ACTIVITY = "NoRelaunchActivity";
@Test
public void testFreeformWindowManagementSupport() throws Exception {
@@ -66,17 +67,17 @@
mAmWmState.assertFocusedActivity(
TEST_ACTIVITY + " must be focused Activity", TEST_ACTIVITY);
assertEquals(new Rect(0, 0, TEST_TASK_SIZE_1, TEST_TASK_SIZE_1),
- mAmWmState.getAmState().getTaskByActivityName(TEST_ACTIVITY).getBounds());
+ mAmWmState.getAmState().getTaskByActivity(TEST_ACTIVITY).getBounds());
}
@Test
public void testNonResizeableActivityHasFullDisplayBounds() throws Exception {
launchActivity(NON_RESIZEABLE_ACTIVITY, WINDOWING_MODE_FREEFORM);
- mAmWmState.computeState(new WaitForValidActivityState.Builder(NON_RESIZEABLE_ACTIVITY).build());
+ mAmWmState.computeState(NON_RESIZEABLE_ACTIVITY);
final ActivityTask task =
- mAmWmState.getAmState().getTaskByActivityName(NON_RESIZEABLE_ACTIVITY);
+ mAmWmState.getAmState().getTaskByActivity(NON_RESIZEABLE_ACTIVITY);
final ActivityStack stack = mAmWmState.getAmState().getStackById(task.mStackId);
if (task.isFullscreen()) {
@@ -96,8 +97,7 @@
launchActivity(TEST_ACTIVITY, WINDOWING_MODE_FREEFORM);
launchActivity(NO_RELAUNCH_ACTIVITY, WINDOWING_MODE_FREEFORM);
- mAmWmState.computeState(new WaitForValidActivityState.Builder(TEST_ACTIVITY).build(),
- new WaitForValidActivityState.Builder(NO_RELAUNCH_ACTIVITY).build());
+ mAmWmState.computeState(TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY);
if (!supportsFreeform()) {
mAmWmState.assertDoesNotContainStack("Must not contain freeform stack.",
@@ -127,8 +127,7 @@
TEST_TASK_OFFSET, TEST_TASK_OFFSET, testTaskSize2, testTaskSize1);
resizeActivityTask(NO_RELAUNCH_ACTIVITY,
TEST_TASK_OFFSET_2, TEST_TASK_OFFSET_2, testTaskSize2, testTaskSize1);
- mAmWmState.computeState(new WaitForValidActivityState.Builder(TEST_ACTIVITY).build(),
- new WaitForValidActivityState.Builder(NO_RELAUNCH_ACTIVITY).build());
+ mAmWmState.computeState(TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY);
assertActivityLifecycle(TEST_ACTIVITY, true /* relaunched */, logSeparator);
assertActivityLifecycle(NO_RELAUNCH_ACTIVITY, false /* relaunched */, logSeparator);
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerManifestLayoutTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerManifestLayoutTests.java
index 2929d90..3aa514a 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerManifestLayoutTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerManifestLayoutTests.java
@@ -19,15 +19,22 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.server.am.ActivityAndWindowManagersState.dpToPx;
+import static android.server.am.ComponentNameUtils.getWindowName;
+import static android.server.am.Components.BOTTOM_LEFT_LAYOUT_ACTIVITY;
+import static android.server.am.Components.BOTTOM_RIGHT_LAYOUT_ACTIVITY;
+import static android.server.am.Components.TOP_LEFT_LAYOUT_ACTIVITY;
+import static android.server.am.Components.TOP_RIGHT_LAYOUT_ACTIVITY;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
import static org.junit.Assume.assumeTrue;
+import android.content.ComponentName;
import android.graphics.Rect;
import android.server.am.WindowManagerState.Display;
import android.server.am.WindowManagerState.WindowState;
-import junit.framework.Assert;
-
import org.junit.Test;
import java.util.ArrayList;
@@ -93,33 +100,37 @@
}
private void testMinimalSize(int windowingMode) throws Exception {
- final String activityName = "BottomRightLayoutActivity";
-
// Issue command to resize to <0,0,1,1>. We expect the size to be floored at
// MIN_WIDTH_DPxMIN_HEIGHT_DP.
if (windowingMode == WINDOWING_MODE_FREEFORM) {
- launchActivity(activityName, WINDOWING_MODE_FREEFORM);
- resizeActivityTask(activityName, 0, 0, 1, 1);
+ launchActivity(BOTTOM_RIGHT_LAYOUT_ACTIVITY, WINDOWING_MODE_FREEFORM);
+ resizeActivityTask(BOTTOM_RIGHT_LAYOUT_ACTIVITY, 0, 0, 1, 1);
} else { // stackId == DOCKED_STACK_ID
- launchActivityInSplitScreenWithRecents(activityName);
+ launchActivityInSplitScreenWithRecents(BOTTOM_RIGHT_LAYOUT_ACTIVITY);
resizeDockedStack(1, 1, 1, 1);
}
- getDisplayAndWindowState(activityName, false);
+ getDisplayAndWindowState(BOTTOM_RIGHT_LAYOUT_ACTIVITY, false);
final int minWidth = dpToPx(MIN_WIDTH_DP, mDisplay.getDpi());
final int minHeight = dpToPx(MIN_HEIGHT_DP, mDisplay.getDpi());
final Rect containingRect = mWindowState.getContainingFrame();
- Assert.assertEquals("Min width is incorrect", minWidth, containingRect.width());
- Assert.assertEquals("Min height is incorrect", minHeight, containingRect.height());
+ assertEquals("Min width is incorrect", minWidth, containingRect.width());
+ assertEquals("Min height is incorrect", minHeight, containingRect.height());
}
private void testLayout(
int vGravity, int hGravity, boolean fraction) throws Exception {
assumeTrue("Skipping test: no freeform support", supportsFreeform());
- final String activityName = (vGravity == GRAVITY_VER_TOP ? "Top" : "Bottom")
- + (hGravity == GRAVITY_HOR_LEFT ? "Left" : "Right") + "LayoutActivity";
+ final ComponentName activityName;
+ if (vGravity == GRAVITY_VER_TOP) {
+ activityName = (hGravity == GRAVITY_HOR_LEFT) ? TOP_LEFT_LAYOUT_ACTIVITY
+ : TOP_RIGHT_LAYOUT_ACTIVITY;
+ } else {
+ activityName = (hGravity == GRAVITY_HOR_LEFT) ? BOTTOM_LEFT_LAYOUT_ACTIVITY
+ : BOTTOM_RIGHT_LAYOUT_ACTIVITY;
+ }
// Launch in freeform stack
launchActivity(activityName, WINDOWING_MODE_FREEFORM);
@@ -145,11 +156,11 @@
vGravity, hGravity, expectedWidthPx, expectedHeightPx, containingRect, appRect);
}
- private void getDisplayAndWindowState(String activityName, boolean checkFocus)
+ private void getDisplayAndWindowState(ComponentName activityName, boolean checkFocus)
throws Exception {
- final String windowName = getActivityWindowName(activityName);
+ final String windowName = getWindowName(activityName);
- mAmWmState.computeState(new WaitForValidActivityState.Builder(activityName).build());
+ mAmWmState.computeState(activityName);
if (checkFocus) {
mAmWmState.assertFocusedWindow("Test window must be the front window.", windowName);
@@ -159,34 +170,32 @@
mAmWmState.getWmState().getMatchingVisibleWindowState(windowName, mTempWindowList);
- Assert.assertEquals("Should have exactly one window state for the activity.",
+ assertEquals("Should have exactly one window state for the activity.",
1, mTempWindowList.size());
mWindowState = mTempWindowList.get(0);
- Assert.assertNotNull("Should have a valid window", mWindowState);
+ assertNotNull("Should have a valid window", mWindowState);
mDisplay = mAmWmState.getWmState().getDisplay(mWindowState.getDisplayId());
- Assert.assertNotNull("Should be on a display", mDisplay);
+ assertNotNull("Should be on a display", mDisplay);
}
private void verifyFrameSizeAndPosition(
int vGravity, int hGravity, int expectedWidthPx, int expectedHeightPx,
Rect containingFrame, Rect parentFrame) {
- Assert.assertEquals("Width is incorrect", expectedWidthPx, containingFrame.width());
- Assert.assertEquals("Height is incorrect", expectedHeightPx, containingFrame.height());
+ assertEquals("Width is incorrect", expectedWidthPx, containingFrame.width());
+ assertEquals("Height is incorrect", expectedHeightPx, containingFrame.height());
if (vGravity == GRAVITY_VER_TOP) {
- Assert.assertEquals("Should be on the top", parentFrame.top, containingFrame.top);
+ assertEquals("Should be on the top", parentFrame.top, containingFrame.top);
} else if (vGravity == GRAVITY_VER_BOTTOM) {
- Assert.assertEquals("Should be on the bottom",
- parentFrame.bottom, containingFrame.bottom);
+ assertEquals("Should be on the bottom", parentFrame.bottom, containingFrame.bottom);
}
if (hGravity == GRAVITY_HOR_LEFT) {
- Assert.assertEquals("Should be on the left", parentFrame.left, containingFrame.left);
+ assertEquals("Should be on the left", parentFrame.left, containingFrame.left);
} else if (hGravity == GRAVITY_HOR_RIGHT){
- Assert.assertEquals("Should be on the right",
- parentFrame.right, containingFrame.right);
+ assertEquals("Should be on the right", parentFrame.right, containingFrame.right);
}
}
}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java
index 3961d83..7c49d13 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java
@@ -20,12 +20,30 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.server.am.ActivityAndWindowManagersState.DEFAULT_DISPLAY_ID;
+import static android.server.am.ActivityLauncher.KEY_LAUNCH_ACTIVITY;
+import static android.server.am.ActivityLauncher.KEY_NEW_TASK;
+import static android.server.am.ActivityLauncher.KEY_TARGET_ACTIVITY;
import static android.server.am.ActivityManagerDisplayTestBase.ReportedDisplayMetrics
.getDisplayMetrics;
import static android.server.am.ActivityManagerState.STATE_RESUMED;
import static android.server.am.ActivityManagerState.STATE_STOPPED;
import static android.server.am.ComponentNameUtils.getActivityName;
+import static android.server.am.ComponentNameUtils.getSimpleClassName;
+import static android.server.am.ComponentNameUtils.getWindowName;
+import static android.server.am.Components.ALT_LAUNCHING_ACTIVITY;
+import static android.server.am.Components.BROADCAST_RECEIVER_ACTIVITY;
+import static android.server.am.Components.LAUNCHING_ACTIVITY;
+import static android.server.am.Components.LAUNCH_BROADCAST_ACTION;
+import static android.server.am.Components.LAUNCH_BROADCAST_RECEIVER;
+import static android.server.am.Components.NON_RESIZEABLE_ACTIVITY;
+import static android.server.am.Components.RESIZEABLE_ACTIVITY;
+import static android.server.am.Components.SHOW_WHEN_LOCKED_ATTR_ACTIVITY;
+import static android.server.am.Components.TEST_ACTIVITY;
+import static android.server.am.Components.VIRTUAL_DISPLAY_ACTIVITY;
+import static android.server.am.StateLogger.logAlways;
import static android.server.am.StateLogger.logE;
+import static android.server.am.UiDeviceUtils.pressSleepButton;
+import static android.server.am.UiDeviceUtils.pressWakeupButton;
import static android.server.am.second.Components.SECOND_ACTIVITY;
import static android.server.am.second.Components.SECOND_LAUNCH_BROADCAST_ACTION;
import static android.server.am.second.Components.SECOND_LAUNCH_BROADCAST_RECEIVER;
@@ -59,17 +77,6 @@
* atest CtsActivityManagerDeviceTestCases:ActivityManagerMultiDisplayTests
*/
public class ActivityManagerMultiDisplayTests extends ActivityManagerDisplayTestBase {
- private static final String TEST_ACTIVITY_NAME = "TestActivity";
- private static final String VIRTUAL_DISPLAY_ACTIVITY = "VirtualDisplayActivity";
- private static final String RESIZEABLE_ACTIVITY_NAME = "ResizeableActivity";
- private static final String NON_RESIZEABLE_ACTIVITY_NAME = "NonResizeableActivity";
- private static final String SHOW_WHEN_LOCKED_ATTR_ACTIVITY_NAME = "ShowWhenLockedAttrActivity";
-
- private static final ComponentName TEST_ACTIVITY = ComponentName.createRelative(
- componentName, "." + TEST_ACTIVITY_NAME);
- private final ComponentName LAUNCH_BROADCAST_RECEIVER = ComponentName.createRelative(
- componentName, ".LaunchBroadcastReceiver");
- private final String LAUNCH_BROADCAST_ACTION = componentName + ".LAUNCH_BROADCAST_ACTION";
@Before
@Override
@@ -91,23 +98,23 @@
// Launch activity on new secondary display.
final LogSeparator logSeparator = clearLogcat();
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mId);
- mAmWmState.computeState(new WaitForValidActivityState(TEST_ACTIVITY_NAME));
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
+ mAmWmState.computeState(TEST_ACTIVITY);
mAmWmState.assertFocusedActivity(
"Activity launched on secondary display must be focused",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
// Check that activity is on the right display.
final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
final ActivityManagerState.ActivityStack frontStack =
mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Launched activity must be on the secondary display and resumed",
- getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity);
+ getActivityName(TEST_ACTIVITY), frontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
// Check that activity config corresponds to display config.
- final ReportedSizes reportedSizes = getLastReportedSizesForActivity(TEST_ACTIVITY_NAME,
+ final ReportedSizes reportedSizes = getLastReportedSizesForActivity(TEST_ACTIVITY,
logSeparator);
assertEquals("Activity launched on secondary display must have proper configuration",
CUSTOM_DENSITY_DPI, reportedSizes.densityDpi);
@@ -125,19 +132,19 @@
final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
// Launch activity on new secondary display.
- launchActivityOnDisplay(NON_RESIZEABLE_ACTIVITY_NAME, newDisplay.mId);
- mAmWmState.computeState(new WaitForValidActivityState(NON_RESIZEABLE_ACTIVITY_NAME));
+ launchActivityOnDisplay(NON_RESIZEABLE_ACTIVITY, newDisplay.mId);
+ mAmWmState.computeState(NON_RESIZEABLE_ACTIVITY);
mAmWmState.assertFocusedActivity(
"Activity launched on secondary display must be focused",
- NON_RESIZEABLE_ACTIVITY_NAME);
+ NON_RESIZEABLE_ACTIVITY);
// Check that activity is on the right display.
final int frontStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY_ID);
final ActivityManagerState.ActivityStack frontStack =
mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Launched activity must be on the primary display and resumed",
- getActivityComponentName(NON_RESIZEABLE_ACTIVITY_NAME),
+ getActivityName(NON_RESIZEABLE_ACTIVITY),
frontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on the primary display", frontStackId);
}
@@ -160,19 +167,19 @@
.createDisplay();
// Launch activity on new secondary display.
- launchActivityOnDisplay(NON_RESIZEABLE_ACTIVITY_NAME, newDisplay.mId);
- mAmWmState.computeState(new WaitForValidActivityState(NON_RESIZEABLE_ACTIVITY_NAME));
+ launchActivityOnDisplay(NON_RESIZEABLE_ACTIVITY, newDisplay.mId);
+ mAmWmState.computeState(NON_RESIZEABLE_ACTIVITY);
mAmWmState.assertFocusedActivity(
"Activity launched on secondary display must be focused",
- NON_RESIZEABLE_ACTIVITY_NAME);
+ NON_RESIZEABLE_ACTIVITY);
// Check that activity is on the right display.
final int frontStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY_ID);
final ActivityManagerState.ActivityStack frontStack =
mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Launched activity must be on the primary display and resumed",
- getActivityComponentName(NON_RESIZEABLE_ACTIVITY_NAME),
+ getActivityName(NON_RESIZEABLE_ACTIVITY),
frontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on the primary display", frontStackId);
mAmWmState.assertDoesNotContainStack("Must not contain docked stack.",
@@ -190,19 +197,19 @@
// Create new virtual display.
final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
// Launch a non-resizeable activity on a primary display.
- launchActivityInNewTask(NON_RESIZEABLE_ACTIVITY_NAME);
+ launchActivityInNewTask(NON_RESIZEABLE_ACTIVITY);
// Launch a resizeable activity on new secondary display to create a new stack there.
- launchActivityOnDisplay(RESIZEABLE_ACTIVITY_NAME, newDisplay.mId);
+ launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
final int externalFrontStackId = mAmWmState.getAmState()
.getFrontStackId(newDisplay.mId);
// Try to move the non-resizeable activity to new secondary display.
- moveActivityToStack(NON_RESIZEABLE_ACTIVITY_NAME, externalFrontStackId);
- mAmWmState.computeState(new WaitForValidActivityState(NON_RESIZEABLE_ACTIVITY_NAME));
+ moveActivityToStack(NON_RESIZEABLE_ACTIVITY, externalFrontStackId);
+ mAmWmState.computeState(NON_RESIZEABLE_ACTIVITY);
mAmWmState.assertFocusedActivity(
"Activity launched on secondary display must be focused",
- RESIZEABLE_ACTIVITY_NAME);
+ RESIZEABLE_ACTIVITY);
// Check that activity is in the same stack
final int defaultFrontStackId = mAmWmState.getAmState().getFrontStackId(
@@ -210,7 +217,7 @@
final ActivityManagerState.ActivityStack defaultFrontStack =
mAmWmState.getAmState().getStackById(defaultFrontStackId);
assertEquals("Launched activity must be on the primary display and resumed",
- getActivityComponentName(NON_RESIZEABLE_ACTIVITY_NAME),
+ getActivityName(NON_RESIZEABLE_ACTIVITY),
defaultFrontStack.getTopTask().mRealActivity);
mAmWmState.assertFocusedStack("Focus must remain on the secondary display",
externalFrontStackId);
@@ -239,21 +246,22 @@
ActivityManagerState.ActivityStack frontStack =
mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Launched activity must be on the secondary display and resumed",
- getActivityComponentName(BROADCAST_RECEIVER_ACTIVITY),
+ getActivityName(BROADCAST_RECEIVER_ACTIVITY),
frontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on the secondary display", frontStackId);
// Launch non-resizeable activity from secondary display.
- executeShellCommand("am broadcast -a trigger_broadcast --ez launch_activity true "
- + "--ez new_task true --es target_activity " + NON_RESIZEABLE_ACTIVITY_NAME);
- mAmWmState.computeState(new WaitForValidActivityState(NON_RESIZEABLE_ACTIVITY_NAME));
+ executeShellCommand("am broadcast -a trigger_broadcast --ez " + KEY_LAUNCH_ACTIVITY
+ + " true --ez " + KEY_NEW_TASK + " true --es " + KEY_TARGET_ACTIVITY + " "
+ + getSimpleClassName(NON_RESIZEABLE_ACTIVITY));
+ mAmWmState.computeState(NON_RESIZEABLE_ACTIVITY);
// Check that non-resizeable activity is on the secondary display, because of the
// resizeable root of the task.
frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
frontStack = mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Launched activity must be on the primary display and resumed",
- getActivityComponentName(NON_RESIZEABLE_ACTIVITY_NAME),
+ getActivityName(NON_RESIZEABLE_ACTIVITY),
frontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on the primary display", frontStackId);
}
@@ -280,12 +288,12 @@
ActivityManagerState.ActivityStack frontStack =
mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Launched activity must be on the secondary display and resumed",
- getActivityComponentName(LAUNCHING_ACTIVITY),
+ getActivityName(LAUNCHING_ACTIVITY),
frontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on the secondary display", frontStackId);
// Launch non-resizeable activity from secondary display.
- getLaunchActivityBuilder().setTargetActivityName(NON_RESIZEABLE_ACTIVITY_NAME)
+ getLaunchActivityBuilder().setTargetActivity(NON_RESIZEABLE_ACTIVITY)
.setNewTask(true).setMultipleTask(true).execute();
// Check that non-resizeable activity is on the primary display.
@@ -294,7 +302,7 @@
assertFalse("Launched activity must be on a different display",
newDisplay.mId == frontStack.mDisplayId);
assertEquals("Launched activity must be resumed",
- getActivityComponentName(NON_RESIZEABLE_ACTIVITY_NAME),
+ getActivityName(NON_RESIZEABLE_ACTIVITY),
frontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on a just launched activity",
frontStackId);
@@ -323,10 +331,9 @@
assertSecurityException("ActivityLauncher", logSeparator);
- mAmWmState.computeState(new WaitForValidActivityState(TEST_ACTIVITY_NAME));
+ mAmWmState.computeState(TEST_ACTIVITY);
assertFalse("Restricted activity must not be launched",
- mAmWmState.getAmState().containsActivity(
- getActivityComponentName(TEST_ACTIVITY_NAME)));
+ mAmWmState.getAmState().containsActivity(TEST_ACTIVITY));
}
}
@@ -347,7 +354,7 @@
.setTargetActivity(TEST_ACTIVITY)
.execute();
- mAmWmState.waitForValidState(TEST_ACTIVITY_NAME);
+ mAmWmState.waitForValidState(TEST_ACTIVITY);
final int externalFocusedStackId = mAmWmState.getAmState().getFocusedStackId();
final ActivityManagerState.ActivityStack focusedStack =
@@ -356,7 +363,7 @@
focusedStack.mDisplayId);
mAmWmState.assertFocusedActivity("Focus must be on newly launched app",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
assertEquals("Activity launched by owner must be on external display",
externalFocusedStackId, mAmWmState.getAmState().getFocusedStackId());
}
@@ -375,16 +382,16 @@
final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
// Launch activity on new secondary display.
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mId);
- mAmWmState.computeState(new WaitForValidActivityState(TEST_ACTIVITY_NAME));
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
+ mAmWmState.computeState(TEST_ACTIVITY);
mAmWmState.assertFocusedActivity(
"Activity launched on secondary display must be focused",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
// Launch second activity without specifying display.
launchActivity(LAUNCHING_ACTIVITY);
- mAmWmState.computeState(new WaitForValidActivityState(LAUNCHING_ACTIVITY));
+ mAmWmState.computeState(LAUNCHING_ACTIVITY);
// Check that activity is launched in focused stack on primary display.
mAmWmState.assertFocusedActivity("Launched activity must be focused",
@@ -393,7 +400,7 @@
final ActivityManagerState.ActivityStack frontStack
= mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Launched activity must be resumed in front stack",
- getActivityComponentName(LAUNCHING_ACTIVITY), frontStack.mResumedActivity);
+ getActivityName(LAUNCHING_ACTIVITY), frontStack.mResumedActivity);
assertEquals("Front stack must be on primary display",
DEFAULT_DISPLAY_ID, frontStack.mDisplayId);
}
@@ -421,17 +428,17 @@
LAUNCHING_ACTIVITY);
// Launch second activity from app on secondary display without specifying display id.
- getLaunchActivityBuilder().setTargetActivityName(TEST_ACTIVITY_NAME).execute();
- mAmWmState.computeState(new WaitForValidActivityState(TEST_ACTIVITY_NAME));
+ getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY).execute();
+ mAmWmState.computeState(TEST_ACTIVITY);
// Check that activity is launched in focused stack on external display.
mAmWmState.assertFocusedActivity("Launched activity must be focused",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
final ActivityManagerState.ActivityStack frontStack
= mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Launched activity must be resumed in front stack",
- getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity);
+ getActivityName(TEST_ACTIVITY), frontStack.mResumedActivity);
}
}
@@ -454,17 +461,17 @@
LAUNCHING_ACTIVITY);
// Launch second activity from app on secondary display without specifying display id.
- getLaunchActivityBuilder().setTargetActivityName(TEST_ACTIVITY_NAME).execute();
- mAmWmState.computeState(TEST_ACTIVITY_NAME);
+ getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY).execute();
+ mAmWmState.computeState(TEST_ACTIVITY);
// Check that activity is launched in focused stack on external display.
mAmWmState.assertFocusedActivity("Launched activity must be focused",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
final ActivityManagerState.ActivityStack frontStack = mAmWmState.getAmState()
.getStackById(frontStackId);
assertEquals("Launched activity must be resumed in front stack",
- getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity);
+ getActivityName(TEST_ACTIVITY), frontStack.mResumedActivity);
}
}
@@ -491,7 +498,7 @@
.setTargetActivity(SECOND_ACTIVITY)
.setDisplayId(newDisplay.mId)
.execute();
- mAmWmState.computeState(TEST_ACTIVITY_NAME);
+ mAmWmState.computeState(TEST_ACTIVITY);
// Check that activity is launched in focused stack on external display.
mAmWmState.assertFocusedActivity("Launched activity must be focused", SECOND_ACTIVITY);
@@ -508,7 +515,7 @@
.setDisplayId(newDisplay.mId)
.setTargetActivity(THIRD_ACTIVITY)
.execute();
- mAmWmState.waitForValidState(new WaitForValidActivityState(THIRD_ACTIVITY));
+ mAmWmState.waitForValidState(THIRD_ACTIVITY);
// Check that activity is launched in focused stack on external display.
mAmWmState.assertFocusedActivity("Launched activity must be focused", THIRD_ACTIVITY);
@@ -563,19 +570,19 @@
.createDisplay();
// Launch activity on secondary display from the app on primary display.
- getLaunchActivityBuilder().setTargetActivityName(TEST_ACTIVITY_NAME)
+ getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)
.setDisplayId(newDisplay.mId).execute();
// Check that activity is launched on external display.
- mAmWmState.computeState(new WaitForValidActivityState(TEST_ACTIVITY_NAME));
+ mAmWmState.computeState(TEST_ACTIVITY);
mAmWmState.assertFocusedActivity(
"Activity launched on secondary display must be focused",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
final ActivityManagerState.ActivityStack frontStack =
mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Launched activity must be resumed in front stack",
- getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity);
+ getActivityName(TEST_ACTIVITY), frontStack.mResumedActivity);
}
}
@@ -595,16 +602,16 @@
mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
// Launch activity on new secondary display.
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mId);
- mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */);
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
+ mAmWmState.assertVisibility(TEST_ACTIVITY, true /* visible */);
mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
// Launch activity on primary display and check if it doesn't affect activity on
// secondary display.
- getLaunchActivityBuilder().setTargetActivityName(RESIZEABLE_ACTIVITY_NAME).execute();
- mAmWmState.waitForValidState(RESIZEABLE_ACTIVITY_NAME);
- mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */);
- mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true /* visible */);
+ getLaunchActivityBuilder().setTargetActivity(RESIZEABLE_ACTIVITY).execute();
+ mAmWmState.waitForValidState(RESIZEABLE_ACTIVITY);
+ mAmWmState.assertVisibility(TEST_ACTIVITY, true /* visible */);
+ mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */);
}
}
@@ -628,18 +635,18 @@
focusedStack.mDisplayId);
// Launch activity on new secondary display.
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mId);
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
mAmWmState.assertFocusedActivity("Focus must be on secondary display",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
int focusedStackId = mAmWmState.getAmState().getFocusedStackId();
focusedStack = mAmWmState.getAmState().getStackById(focusedStackId);
assertEquals("Focused stack must be on secondary display",
newDisplay.mId, focusedStack.mDisplayId);
// Move activity from secondary display to primary.
- moveActivityToStack(TEST_ACTIVITY_NAME, defaultDisplayStackId);
+ moveActivityToStack(TEST_ACTIVITY, defaultDisplayStackId);
mAmWmState.waitForFocusedStack(defaultDisplayStackId);
- mAmWmState.assertFocusedActivity("Focus must be on moved activity", TEST_ACTIVITY_NAME);
+ mAmWmState.assertFocusedActivity("Focus must be on moved activity", TEST_ACTIVITY);
focusedStackId = mAmWmState.getAmState().getFocusedStackId();
focusedStack = mAmWmState.getAmState().getStackById(focusedStackId);
assertEquals("Focus must return to primary display", DEFAULT_DISPLAY_ID,
@@ -676,7 +683,9 @@
assumeTrue(supportsSplitScreenMultiWindow());
// Setup split-screen.
- launchActivitiesInSplitScreen(TEST_ACTIVITY_NAME, LAUNCHING_ACTIVITY);
+ launchActivitiesInSplitScreen(
+ getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY));
mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
tryCreatingAndRemovingDisplayWithActivity(true /* splitScreen */,
@@ -720,9 +729,9 @@
}
// Launch activity on new secondary display.
- launchActivityOnDisplay(RESIZEABLE_ACTIVITY_NAME, newDisplay.mId);
+ launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
mAmWmState.assertFocusedActivity("Focus must be on secondary display",
- RESIZEABLE_ACTIVITY_NAME);
+ RESIZEABLE_ACTIVITY);
final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
@@ -731,20 +740,22 @@
}
mAmWmState.computeState(true);
- assertActivityLifecycle(RESIZEABLE_ACTIVITY_NAME, false /* relaunched */, logSeparator);
- mAmWmState.waitForValidState(RESIZEABLE_ACTIVITY_NAME, windowingMode,
- ACTIVITY_TYPE_STANDARD);
+ assertActivityLifecycle(RESIZEABLE_ACTIVITY, false /* relaunched */, logSeparator);
+ mAmWmState.waitForValidState(new WaitForValidActivityState.Builder(RESIZEABLE_ACTIVITY)
+ .setWindowingMode(windowingMode)
+ .setActivityType(ACTIVITY_TYPE_STANDARD)
+ .build());
mAmWmState.assertSanity();
mAmWmState.assertValidBounds(true /* compareTaskAndStackBounds */);
// Check if the focus is switched back to primary display.
- mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true /* visible */);
+ mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */);
mAmWmState.assertFocusedStack(
"Default stack on primary display must be focused after display removed",
windowingMode, ACTIVITY_TYPE_STANDARD);
mAmWmState.assertFocusedActivity(
"Focus must be switched back to activity on primary display",
- RESIZEABLE_ACTIVITY_NAME);
+ RESIZEABLE_ACTIVITY);
}
/**
@@ -791,23 +802,23 @@
// Create new virtual display.
final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
- mAmWmState.computeState(new WaitForValidActivityState(VIRTUAL_DISPLAY_ACTIVITY));
+ mAmWmState.computeState(VIRTUAL_DISPLAY_ACTIVITY);
mAmWmState.assertFocusedActivity("Focus must be switched back to primary display",
VIRTUAL_DISPLAY_ACTIVITY);
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mId);
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
- mAmWmState.computeState(new WaitForValidActivityState(TEST_ACTIVITY_NAME));
+ mAmWmState.computeState(TEST_ACTIVITY);
mAmWmState.assertFocusedActivity(
"Activity launched on secondary display must be focused",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
final ReportedDisplayMetrics displayMetrics = getDisplayMetrics();
final int width = displayMetrics.getSize().getWidth();
final int height = displayMetrics.getSize().getHeight();
executeShellCommand("input tap " + (width / 2) + " " + (height / 2));
- mAmWmState.computeState(new WaitForValidActivityState(VIRTUAL_DISPLAY_ACTIVITY));
+ mAmWmState.computeState(VIRTUAL_DISPLAY_ACTIVITY);
mAmWmState.assertFocusedActivity("Focus must be switched back to primary display",
VIRTUAL_DISPLAY_ACTIVITY);
}
@@ -829,9 +840,9 @@
focusedStack.mDisplayId);
// Launch activity on new secondary display.
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mId);
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
mAmWmState.assertFocusedActivity("Focus must be on secondary display",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
final int externalFocusedStackId = mAmWmState.getAmState().getFocusedStackId();
focusedStack = mAmWmState.getAmState().getStackById(externalFocusedStackId);
assertEquals("Focused stack must be on secondary display", newDisplay.mId,
@@ -843,7 +854,7 @@
+ " --display " + newDisplay.mId;
executeShellCommand(startCmd);
- mAmWmState.waitForValidState(new WaitForValidActivityState(SECOND_ACTIVITY));
+ mAmWmState.waitForValidState(SECOND_ACTIVITY);
mAmWmState.assertFocusedActivity(
"Focus must be on newly launched app", SECOND_ACTIVITY);
assertEquals("Activity launched by system must be on external display",
@@ -864,7 +875,7 @@
+ " --display " + newDisplay.mId;
executeShellCommand(startCmd);
- mAmWmState.waitForValidState(new WaitForValidActivityState(SECOND_ACTIVITY));
+ mAmWmState.waitForValidState(SECOND_ACTIVITY);
mAmWmState.assertFocusedActivity(
"Focus must be on newly launched app", SECOND_ACTIVITY);
final int externalFocusedStackId = mAmWmState.getAmState().getFocusedStackId();
@@ -882,7 +893,7 @@
.setTargetActivity(THIRD_ACTIVITY)
.execute();
- mAmWmState.waitForValidState(new WaitForValidActivityState(THIRD_ACTIVITY));
+ mAmWmState.waitForValidState(THIRD_ACTIVITY);
mAmWmState.assertFocusedActivity("Focus must be on newly launched app", THIRD_ACTIVITY);
assertEquals("Activity launched by app on secondary display must be on that display",
externalFocusedStackId, mAmWmState.getAmState().getFocusedStackId());
@@ -897,14 +908,14 @@
.createDisplay();
launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId);
- mAmWmState.computeState(new WaitForValidActivityState(LAUNCHING_ACTIVITY));
+ mAmWmState.computeState(LAUNCHING_ACTIVITY);
// Check that the first activity is launched onto the secondary display
final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
ActivityManagerState.ActivityStack frontStack = mAmWmState.getAmState().getStackById(
frontStackId);
assertEquals("Activity launched on secondary display must be resumed",
- getActivityComponentName(LAUNCHING_ACTIVITY),
+ getActivityName(LAUNCHING_ACTIVITY),
frontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
@@ -942,7 +953,7 @@
+ " --display " + newDisplay.mId;
executeShellCommand(startCmd);
- mAmWmState.waitForValidState(new WaitForValidActivityState(SECOND_ACTIVITY));
+ mAmWmState.waitForValidState(SECOND_ACTIVITY);
mAmWmState.assertFocusedActivity(
"Focus must be on newly launched app", SECOND_ACTIVITY);
final int externalFocusedStackId = mAmWmState.getAmState().getFocusedStackId();
@@ -958,9 +969,9 @@
.setDisplayId(newDisplay.mId)
.execute();
- mAmWmState.waitForValidState(TEST_ACTIVITY_NAME);
+ mAmWmState.waitForValidState(TEST_ACTIVITY);
mAmWmState.assertFocusedActivity("Focus must be on newly launched app",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
assertEquals("Activity launched by owner must be on external display",
externalFocusedStackId, mAmWmState.getAmState().getFocusedStackId());
}
@@ -985,9 +996,9 @@
focusedStack.mDisplayId);
// Launch activity on new secondary display.
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mId);
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
mAmWmState.assertFocusedActivity("Focus must be on secondary display",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
final int externalFocusedStackId = mAmWmState.getAmState().getFocusedStackId();
focusedStack = mAmWmState.getAmState().getStackById(externalFocusedStackId);
assertEquals("Focused stack must be on secondary display", newDisplay.mId,
@@ -1005,9 +1016,8 @@
assertSecurityException("ActivityLauncher", logSeparator);
- mAmWmState.waitForValidState(false /* compareTaskAndStackBounds */, componentName,
- new WaitForValidActivityState(TEST_ACTIVITY_NAME));
- mAmWmState.assertFocusedActivity("Focus must be on first activity", TEST_ACTIVITY_NAME);
+ mAmWmState.waitForValidState(TEST_ACTIVITY);
+ mAmWmState.assertFocusedActivity("Focus must be on first activity", TEST_ACTIVITY);
assertEquals("Focused stack must be on secondary display's stack",
externalFocusedStackId, mAmWmState.getAmState().getFocusedStackId());
}
@@ -1015,26 +1025,22 @@
private void assertSecurityException(String component, LogSeparator logSeparator)
throws Exception {
- int tries = 0;
- boolean match = false;
final Pattern pattern = Pattern.compile(".*SecurityException launching activity.*");
- while (tries < 5 && !match) {
+ for (int retry = 1; retry <= 5; retry++) {
String[] logs = getDeviceLogsForComponents(logSeparator, component);
for (String line : logs) {
Matcher m = pattern.matcher(line);
if (m.matches()) {
- match = true;
- break;
+ return;
}
}
- tries++;
+ logAlways("***Waiting for SecurityException for " + component + " ... retry=" + retry);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
-
- assertTrue("Expected exception not found", match);
+ fail("Expected exception for " + component + " not found");
}
/**
@@ -1069,45 +1075,41 @@
mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
// Launch activities on new secondary display.
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mId);
- mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */);
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
+ mAmWmState.assertVisibility(TEST_ACTIVITY, true /* visible */);
mAmWmState.assertFocusedActivity("Launched activity must be focused",
- TEST_ACTIVITY_NAME);
- launchActivityOnDisplay(RESIZEABLE_ACTIVITY_NAME, newDisplay.mId);
- mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true /* visible */);
+ TEST_ACTIVITY);
+ launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
+ mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */);
mAmWmState.assertFocusedActivity("Launched activity must be focused",
- RESIZEABLE_ACTIVITY_NAME);
+ RESIZEABLE_ACTIVITY);
// Destroy the display and check if activities are removed from system.
logSeparator = clearLogcat();
}
- final String activityName1 = getActivityComponentName(TEST_ACTIVITY_NAME);
- final String activityName2 = getActivityComponentName(RESIZEABLE_ACTIVITY_NAME);
- final String windowName1 = getActivityWindowName(TEST_ACTIVITY_NAME);
- final String windowName2 = getActivityWindowName(RESIZEABLE_ACTIVITY_NAME);
mAmWmState.waitForWithAmState(
- (state) -> !state.containsActivity(activityName1)
- && !state.containsActivity(activityName2),
+ (state) -> !state.containsActivity(TEST_ACTIVITY)
+ && !state.containsActivity(RESIZEABLE_ACTIVITY),
"Waiting for activity to be removed");
mAmWmState.waitForWithWmState(
- (state) -> !state.containsWindow(windowName1)
- && !state.containsWindow(windowName2),
+ (state) -> !state.containsWindow(getWindowName(TEST_ACTIVITY))
+ && !state.containsWindow(getWindowName(RESIZEABLE_ACTIVITY)),
"Waiting for activity window to be gone");
// Check AM state.
assertFalse("Activity from removed display must be destroyed",
- mAmWmState.getAmState().containsActivity(activityName1));
+ mAmWmState.getAmState().containsActivity(TEST_ACTIVITY));
assertFalse("Activity from removed display must be destroyed",
- mAmWmState.getAmState().containsActivity(activityName2));
+ mAmWmState.getAmState().containsActivity(RESIZEABLE_ACTIVITY));
// Check WM state.
assertFalse("Activity windows from removed display must be destroyed",
- mAmWmState.getWmState().containsWindow(windowName1));
+ mAmWmState.getWmState().containsWindow(getWindowName(TEST_ACTIVITY)));
assertFalse("Activity windows from removed display must be destroyed",
- mAmWmState.getWmState().containsWindow(windowName2));
+ mAmWmState.getWmState().containsWindow(getWindowName(RESIZEABLE_ACTIVITY)));
// Check activity logs.
- assertActivityDestroyed(TEST_ACTIVITY_NAME, logSeparator);
- assertActivityDestroyed(RESIZEABLE_ACTIVITY_NAME, logSeparator);
+ assertActivityDestroyed(TEST_ACTIVITY, logSeparator);
+ assertActivityDestroyed(RESIZEABLE_ACTIVITY, logSeparator);
}
/**
@@ -1123,15 +1125,14 @@
// Launch a resizeable activity on new secondary display.
final LogSeparator initialLogSeparator = clearLogcat();
- launchActivityOnDisplay(RESIZEABLE_ACTIVITY_NAME, newDisplay.mId);
- mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true /* visible */);
+ launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
+ mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */);
mAmWmState.assertFocusedActivity("Launched activity must be focused",
- RESIZEABLE_ACTIVITY_NAME);
+ RESIZEABLE_ACTIVITY);
// Grab reported sizes and compute new with slight size change.
final ReportedSizes initialSize = getLastReportedSizesForActivity(
- RESIZEABLE_ACTIVITY_NAME,
- initialLogSeparator);
+ RESIZEABLE_ACTIVITY, initialLogSeparator);
// Resize the docked stack, so that activity with virtual display will also be resized.
final LogSeparator logSeparator = clearLogcat();
@@ -1139,8 +1140,8 @@
mAmWmState.waitForWithAmState(amState -> {
try {
- return readConfigChangeNumber(RESIZEABLE_ACTIVITY_NAME, logSeparator) == 1
- && amState.hasActivityState(RESIZEABLE_ACTIVITY_NAME, STATE_RESUMED);
+ return readConfigChangeNumber(RESIZEABLE_ACTIVITY, logSeparator) == 1
+ && amState.hasActivityState(RESIZEABLE_ACTIVITY, STATE_RESUMED);
} catch (Exception e) {
logE("Error waiting for valid state: " + e.getMessage());
return false;
@@ -1148,18 +1149,17 @@
}, "Wait for the configuration change to happen and for activity to be resumed.");
mAmWmState.computeState(false /* compareTaskAndStackBounds */,
- new WaitForValidActivityState(RESIZEABLE_ACTIVITY_NAME),
+ new WaitForValidActivityState(RESIZEABLE_ACTIVITY),
new WaitForValidActivityState(VIRTUAL_DISPLAY_ACTIVITY));
mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true);
- mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true);
+ mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY, true);
// Check if activity in virtual display was resized properly.
- assertRelaunchOrConfigChanged(RESIZEABLE_ACTIVITY_NAME, 0 /* numRelaunch */,
+ assertRelaunchOrConfigChanged(RESIZEABLE_ACTIVITY, 0 /* numRelaunch */,
1 /* numConfigChange */, logSeparator);
final ReportedSizes updatedSize = getLastReportedSizesForActivity(
- RESIZEABLE_ACTIVITY_NAME,
- logSeparator);
+ RESIZEABLE_ACTIVITY, logSeparator);
assertTrue(updatedSize.widthDp <= initialSize.widthDp);
assertTrue(updatedSize.heightDp <= initialSize.heightDp);
assertTrue(updatedSize.displayWidth == initialSize.displayWidth / 2);
@@ -1168,7 +1168,7 @@
}
/** Read the number of configuration changes sent to activity from logs. */
- private int readConfigChangeNumber(String activityName, LogSeparator logSeparator)
+ private int readConfigChangeNumber(ComponentName activityName, LogSeparator logSeparator)
throws Exception {
return (new ActivityLifecycleCounts(activityName, logSeparator)).mConfigurationChangedCount;
}
@@ -1188,8 +1188,8 @@
mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
// Launch something to that display so that a new stack is created. We need this to be
// able to compare task numbers in stacks later.
- launchActivityOnDisplay(RESIZEABLE_ACTIVITY_NAME, newDisplay.mId);
- mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true /* visible */);
+ launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
+ mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */);
final int stackNum = mAmWmState.getAmState().getDisplay(DEFAULT_DISPLAY_ID)
.mStacks.size();
@@ -1202,8 +1202,7 @@
// {@link Intent#FLAG_ACTIVITY_NEW_TASK} and {@link Intent#FLAG_ACTIVITY_MULTIPLE_TASK}
// when launching on some specific display. We don't do it here as we want an existing
// task to be used.
- final String launchCommand = "am start -n " + getActivityComponentName(
- LAUNCHING_ACTIVITY)
+ final String launchCommand = "am start -n " + getActivityName(LAUNCHING_ACTIVITY)
+ " --display " + newDisplay.mId;
executeShellCommand(launchCommand);
mAmWmState.waitForActivityState(LAUNCHING_ACTIVITY, STATE_RESUMED);
@@ -1211,13 +1210,14 @@
// Check that activity is brought to front.
mAmWmState.assertFocusedActivity("Existing task must be brought to front",
LAUNCHING_ACTIVITY);
- mAmWmState.assertResumedActivity("Existing task must be resumed", LAUNCHING_ACTIVITY);
+ mAmWmState.assertResumedActivity("Existing task must be resumed",
+ LAUNCHING_ACTIVITY);
// Check that activity is on the right display.
final ActivityManagerState.ActivityStack firstFrontStack =
mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Activity must be moved to the secondary display",
- getActivityComponentName(LAUNCHING_ACTIVITY), firstFrontStack.mResumedActivity);
+ getActivityName(LAUNCHING_ACTIVITY), firstFrontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
// Check that task has moved from primary display to secondary.
@@ -1254,8 +1254,7 @@
// {@link Intent#FLAG_ACTIVITY_NEW_TASK} and {@link Intent#FLAG_ACTIVITY_MULTIPLE_TASK}
// when launching on some specific display. We don't do it here as we want an existing
// task to be used.
- final String launchCommand = "am start -n " + getActivityComponentName(
- LAUNCHING_ACTIVITY)
+ final String launchCommand = "am start -n " + getActivityName(LAUNCHING_ACTIVITY)
+ " --display " + newDisplay.mId;
executeShellCommand(launchCommand);
mAmWmState.waitForActivityState(LAUNCHING_ACTIVITY, STATE_RESUMED);
@@ -1263,14 +1262,15 @@
// Check that activity is brought to front.
mAmWmState.assertFocusedActivity("Existing task must be brought to front",
LAUNCHING_ACTIVITY);
- mAmWmState.assertResumedActivity("Existing task must be resumed", LAUNCHING_ACTIVITY);
+ mAmWmState.assertResumedActivity("Existing task must be resumed",
+ LAUNCHING_ACTIVITY);
// Check that activity is on the right display.
final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
final ActivityManagerState.ActivityStack firstFrontStack =
mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Activity must be moved to the secondary display",
- getActivityComponentName(LAUNCHING_ACTIVITY), firstFrontStack.mResumedActivity);
+ getActivityName(LAUNCHING_ACTIVITY), firstFrontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
// Check that task has moved from primary display to secondary.
@@ -1294,30 +1294,30 @@
// Launch activity on new secondary display.
LogSeparator logSeparator = clearLogcat();
- launchActivityOnDisplay(RESIZEABLE_ACTIVITY_NAME, newDisplay.mId);
+ launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
mAmWmState.assertFocusedActivity("Focus must be on secondary display",
- RESIZEABLE_ACTIVITY_NAME);
+ RESIZEABLE_ACTIVITY);
final ReportedSizes initialSizes = getLastReportedSizesForActivity(
- RESIZEABLE_ACTIVITY_NAME, logSeparator);
+ RESIZEABLE_ACTIVITY, logSeparator);
assertNotNull("Test activity must have reported initial sizes on launch", initialSizes);
try (final RotationSession rotationSession = new RotationSession()) {
// Rotate primary display and check that activity on secondary display is not
// affected.
- rotateAndCheckSameSizes(rotationSession, RESIZEABLE_ACTIVITY_NAME);
+ rotateAndCheckSameSizes(rotationSession, RESIZEABLE_ACTIVITY);
// Launch activity to secondary display when primary one is rotated.
final int initialRotation = mAmWmState.getWmState().getRotation();
rotationSession.set((initialRotation + 1) % 4);
logSeparator = clearLogcat();
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mId);
- mAmWmState.waitForActivityState(TEST_ACTIVITY_NAME, STATE_RESUMED);
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
+ mAmWmState.waitForActivityState(TEST_ACTIVITY, STATE_RESUMED);
mAmWmState.assertFocusedActivity("Focus must be on secondary display",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
final ReportedSizes testActivitySizes = getLastReportedSizesForActivity(
- TEST_ACTIVITY_NAME, logSeparator);
+ TEST_ACTIVITY, logSeparator);
assertEquals(
"Sizes of secondary display must not change after rotation of primary "
+ "display",
@@ -1326,8 +1326,8 @@
}
}
- private void rotateAndCheckSameSizes(RotationSession rotationSession, String activityName)
- throws Exception {
+ private void rotateAndCheckSameSizes(
+ RotationSession rotationSession, ComponentName activityName) throws Exception {
for (int rotation = 3; rotation >= 0; --rotation) {
final LogSeparator logSeparator = clearLogcat();
rotationSession.set(rotation);
@@ -1347,17 +1347,17 @@
final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId);
- mAmWmState.computeState(new WaitForValidActivityState(LAUNCHING_ACTIVITY));
+ mAmWmState.computeState(LAUNCHING_ACTIVITY);
// Check that activity is on the secondary display.
final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
final ActivityManagerState.ActivityStack firstFrontStack =
mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Activity launched on secondary display must be resumed",
- getActivityComponentName(LAUNCHING_ACTIVITY), firstFrontStack.mResumedActivity);
+ getActivityName(LAUNCHING_ACTIVITY), firstFrontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
- executeShellCommand("am start -n " + getActivityComponentName(ALT_LAUNCHING_ACTIVITY));
+ executeShellCommand("am start -n " + getActivityName(ALT_LAUNCHING_ACTIVITY));
mAmWmState.waitForValidState(false /* compareTaskAndStackBounds */, componentName,
new WaitForValidActivityState(ALT_LAUNCHING_ACTIVITY));
@@ -1368,12 +1368,12 @@
final ActivityManagerState.ActivityStack defaultDisplayFrontStack =
mAmWmState.getAmState().getStackById(defaultDisplayFrontStackId);
assertEquals("Activity launched on default display must be resumed",
- getActivityComponentName(ALT_LAUNCHING_ACTIVITY),
+ getActivityName(ALT_LAUNCHING_ACTIVITY),
defaultDisplayFrontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on primary display",
defaultDisplayFrontStackId);
- executeShellCommand("am start -n " + getActivityComponentName(LAUNCHING_ACTIVITY));
+ executeShellCommand("am start -n " + getActivityName(LAUNCHING_ACTIVITY));
mAmWmState.waitForFocusedStack(frontStackId);
// Check that the third intent is redirected to the first task due to the root
@@ -1381,7 +1381,7 @@
final ActivityManagerState.ActivityStack secondFrontStack
= mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Activity launched on secondary display must be resumed",
- getActivityComponentName(LAUNCHING_ACTIVITY),
+ getActivityName(LAUNCHING_ACTIVITY),
secondFrontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on primary display", frontStackId);
assertEquals("Focused stack must only contain 1 task",
@@ -1406,15 +1406,14 @@
final ActivityManagerState.ActivityStack firstFrontStack =
mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Activity launched on secondary display must be resumed",
- getActivityComponentName(LAUNCHING_ACTIVITY), firstFrontStack.mResumedActivity);
+ getActivityName(LAUNCHING_ACTIVITY), firstFrontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
// We don't want FLAG_ACTIVITY_MULTIPLE_TASK, so we can't use launchActivityOnDisplay
- executeShellCommand("am start -n "
- + getActivityComponentName(ALT_LAUNCHING_ACTIVITY)
+ executeShellCommand("am start -n " + getActivityName(ALT_LAUNCHING_ACTIVITY)
+ " -f 0x10000000" // FLAG_ACTIVITY_NEW_TASK
+ " --display " + newDisplay.mId);
- mAmWmState.computeState(new WaitForValidActivityState(ALT_LAUNCHING_ACTIVITY));
+ mAmWmState.computeState(ALT_LAUNCHING_ACTIVITY);
// Check that second activity gets launched into the affinity matching
// task on the secondary display
@@ -1423,7 +1422,7 @@
final ActivityManagerState.ActivityStack secondFrontStack =
mAmWmState.getAmState().getStackById(secondFrontStackId);
assertEquals("Activity launched on secondary display must be resumed",
- getActivityComponentName(ALT_LAUNCHING_ACTIVITY),
+ getActivityName(ALT_LAUNCHING_ACTIVITY),
secondFrontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on secondary display",
secondFrontStackId);
@@ -1445,32 +1444,32 @@
.createDisplay();
launchActivityOnDisplay(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mId);
- mAmWmState.computeState(new WaitForValidActivityState(BROADCAST_RECEIVER_ACTIVITY));
+ mAmWmState.computeState(BROADCAST_RECEIVER_ACTIVITY);
// Check that the first activity is launched onto the secondary display
final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
final ActivityManagerState.ActivityStack firstFrontStack =
mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Activity launched on secondary display must be resumed",
- getActivityComponentName(BROADCAST_RECEIVER_ACTIVITY),
+ getActivityName(BROADCAST_RECEIVER_ACTIVITY),
firstFrontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
- executeShellCommand("am start -n " + getActivityComponentName(TEST_ACTIVITY_NAME));
- mAmWmState.waitForValidState(false /* compareTaskAndStackBounds */, componentName,
- new WaitForValidActivityState(TEST_ACTIVITY_NAME));
+ executeShellCommand("am start -n " + getActivityName(TEST_ACTIVITY));
+ mAmWmState.waitForValidState(TEST_ACTIVITY);
// Check that the second activity is launched on the default display
final int focusedStackId = mAmWmState.getAmState().getFocusedStackId();
final ActivityManagerState.ActivityStack focusedStack
= mAmWmState.getAmState().getStackById(focusedStackId);
assertEquals("Activity launched on default display must be resumed",
- getActivityComponentName(TEST_ACTIVITY_NAME), focusedStack.mResumedActivity);
+ getActivityName(TEST_ACTIVITY), focusedStack.mResumedActivity);
assertEquals("Focus must be on primary display", DEFAULT_DISPLAY_ID,
focusedStack.mDisplayId);
- executeShellCommand("am broadcast -a trigger_broadcast --ez launch_activity true "
- + "--ez new_task true --es target_activity " + LAUNCHING_ACTIVITY);
+ executeShellCommand("am broadcast -a trigger_broadcast --ez " + KEY_LAUNCH_ACTIVITY
+ + " true --ez " + KEY_NEW_TASK + " true --es " + KEY_TARGET_ACTIVITY + " "
+ + LAUNCHING_ACTIVITY);
// Check that the third activity ends up in a new task in the same stack as the
// first activity
@@ -1480,7 +1479,7 @@
final ActivityManagerState.ActivityStack secondFrontStack =
mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Activity must be launched on secondary display",
- getActivityComponentName(LAUNCHING_ACTIVITY),
+ getActivityName(LAUNCHING_ACTIVITY),
secondFrontStack.mResumedActivity);
assertEquals("Secondary display must contain 2 tasks",
2, secondFrontStack.getTasks().size());
@@ -1495,18 +1494,18 @@
try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
// Create new virtual display and immediately launch an activity on it.
final ActivityDisplay newDisplay = virtualDisplaySession
- .setLaunchActivity(TEST_ACTIVITY_NAME)
+ .setLaunchActivity(TEST_ACTIVITY)
.createDisplay();
// Check that activity is launched and placed correctly.
- mAmWmState.waitForActivityState(TEST_ACTIVITY_NAME, STATE_RESUMED);
+ mAmWmState.waitForActivityState(TEST_ACTIVITY, STATE_RESUMED);
mAmWmState.assertResumedActivity("Test activity must be launched on a new display",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
final ActivityManagerState.ActivityStack firstFrontStack =
mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Activity launched on secondary display must be resumed",
- getActivityComponentName(TEST_ACTIVITY_NAME), firstFrontStack.mResumedActivity);
+ getActivityName(TEST_ACTIVITY), firstFrontStack.mResumedActivity);
mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
}
}
@@ -1518,8 +1517,8 @@
@Test
public void testExternalDisplayActivityTurnPrimaryOff() throws Exception {
// Launch something on the primary display so we know there is a resumed activity there
- launchActivity(RESIZEABLE_ACTIVITY_NAME);
- waitAndAssertActivityResumed(RESIZEABLE_ACTIVITY_NAME, DEFAULT_DISPLAY_ID,
+ launchActivity(RESIZEABLE_ACTIVITY);
+ waitAndAssertActivityResumed(RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY_ID,
"Activity launched on primary display must be resumed");
try (final ExternalDisplaySession externalDisplaySession = new ExternalDisplaySession();
@@ -1528,19 +1527,19 @@
final ActivityDisplay newDisplay =
externalDisplaySession.createVirtualDisplay(true /* showContentWhenLocked */);
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mId);
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
// Check that the activity is launched onto the external display
- waitAndAssertActivityResumed(TEST_ACTIVITY_NAME, newDisplay.mId,
+ waitAndAssertActivityResumed(TEST_ACTIVITY, newDisplay.mId,
"Activity launched on external display must be resumed");
displayStateSession.turnScreenOff();
// Wait for the fullscreen stack to start sleeping, and then make sure the
// test activity is still resumed.
- waitAndAssertActivityStopped(RESIZEABLE_ACTIVITY_NAME,
+ waitAndAssertActivityStopped(RESIZEABLE_ACTIVITY,
"Activity launched on primary display must be stopped after turning off");
- waitAndAssertActivityResumed(TEST_ACTIVITY_NAME, newDisplay.mId,
+ waitAndAssertActivityResumed(TEST_ACTIVITY, newDisplay.mId,
"Activity launched on external display must be resumed");
}
}
@@ -1552,8 +1551,8 @@
@Test
public void testLaunchExternalDisplayActivityWhilePrimaryOff() throws Exception {
// Launch something on the primary display so we know there is a resumed activity there
- launchActivity(RESIZEABLE_ACTIVITY_NAME);
- waitAndAssertActivityResumed(RESIZEABLE_ACTIVITY_NAME, DEFAULT_DISPLAY_ID,
+ launchActivity(RESIZEABLE_ACTIVITY);
+ waitAndAssertActivityResumed(RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY_ID,
"Activity launched on primary display must be resumed");
try (final PrimaryDisplayStateSession displayStateSession =
@@ -1562,7 +1561,7 @@
displayStateSession.turnScreenOff();
// Make sure there is no resumed activity when the primary display is off
- waitAndAssertActivityStopped(RESIZEABLE_ACTIVITY_NAME,
+ waitAndAssertActivityStopped(RESIZEABLE_ACTIVITY,
"Activity launched on primary display must be stopped after turning off");
assertEquals("Unexpected resumed activity",
0, mAmWmState.getAmState().getResumedActivitiesCount());
@@ -1570,10 +1569,10 @@
final ActivityDisplay newDisplay =
externalDisplaySession.createVirtualDisplay(true /* showContentWhenLocked */);
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mId);
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
// Check that the test activity is resumed on the external display
- waitAndAssertActivityResumed(TEST_ACTIVITY_NAME, newDisplay.mId,
+ waitAndAssertActivityResumed(TEST_ACTIVITY, newDisplay.mId,
"Activity launched on external display must be resumed");
}
}
@@ -1587,22 +1586,22 @@
final ActivityDisplay newDisplay =
externalDisplaySession.createVirtualDisplay(false /* showContentWhenLocked */);
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mId);
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
// Check that the test activity is resumed on the external display
- waitAndAssertActivityResumed(TEST_ACTIVITY_NAME, newDisplay.mId,
+ waitAndAssertActivityResumed(TEST_ACTIVITY, newDisplay.mId,
"Activity launched on external display must be resumed");
externalDisplaySession.turnDisplayOff();
// Check that turning off the external display stops the activity
- waitAndAssertActivityStopped(TEST_ACTIVITY_NAME,
+ waitAndAssertActivityStopped(TEST_ACTIVITY,
"Activity launched on external display must be stopped after turning off");
externalDisplaySession.turnDisplayOn();
// Check that turning on the external display resumes the activity
- waitAndAssertActivityResumed(TEST_ACTIVITY_NAME, newDisplay.mId,
+ waitAndAssertActivityResumed(TEST_ACTIVITY, newDisplay.mId,
"Activity launched on external display must be resumed");
}
}
@@ -1614,8 +1613,8 @@
@Test
public void testStackFocusSwitchOnTouchEventAfterKeyguard() throws Exception {
// Launch something on the primary display so we know there is a resumed activity there
- launchActivity(RESIZEABLE_ACTIVITY_NAME);
- waitAndAssertActivityResumed(RESIZEABLE_ACTIVITY_NAME, DEFAULT_DISPLAY_ID,
+ launchActivity(RESIZEABLE_ACTIVITY);
+ waitAndAssertActivityResumed(RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY_ID,
"Activity launched on primary display must be resumed");
try (final LockScreenSession lockScreenSession = new LockScreenSession();
@@ -1623,7 +1622,7 @@
lockScreenSession.sleepDevice();
// Make sure there is no resumed activity when the primary display is off
- waitAndAssertActivityStopped(RESIZEABLE_ACTIVITY_NAME,
+ waitAndAssertActivityStopped(RESIZEABLE_ACTIVITY,
"Activity launched on primary display must be stopped after turning off");
assertEquals("Unexpected resumed activity",
0, mAmWmState.getAmState().getResumedActivitiesCount());
@@ -1631,47 +1630,48 @@
final ActivityDisplay newDisplay =
externalDisplaySession.createVirtualDisplay(true /* showContentWhenLocked */);
- launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mId);
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
// Check that the test activity is resumed on the external display
- waitAndAssertActivityResumed(TEST_ACTIVITY_NAME, newDisplay.mId,
+ waitAndAssertActivityResumed(TEST_ACTIVITY, newDisplay.mId,
"Activity launched on external display must be resumed");
// Unlock the device and tap on the middle of the primary display
lockScreenSession.wakeUpDevice();
executeShellCommand("wm dismiss-keyguard");
mAmWmState.waitForKeyguardGone();
- mAmWmState.waitForValidState(new WaitForValidActivityState(TEST_ACTIVITY_NAME));
+ mAmWmState.waitForValidState(TEST_ACTIVITY);
final ReportedDisplayMetrics displayMetrics = getDisplayMetrics();
final int width = displayMetrics.getSize().getWidth();
final int height = displayMetrics.getSize().getHeight();
executeShellCommand("input tap " + (width / 2) + " " + (height / 2));
// Check that the activity on the primary display is resumed
- waitAndAssertActivityResumed(RESIZEABLE_ACTIVITY_NAME, DEFAULT_DISPLAY_ID,
+ waitAndAssertActivityResumed(RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY_ID,
"Activity launched on primary display must be resumed");
assertEquals("Unexpected resumed activity",
1, mAmWmState.getAmState().getResumedActivitiesCount());
}
}
- private void waitAndAssertActivityResumed(String activityName, int displayId, String message)
- throws Exception {
+ private void waitAndAssertActivityResumed(
+ ComponentName activityName, int displayId, String message) throws Exception {
mAmWmState.waitForActivityState(activityName, STATE_RESUMED);
- final String fullActivityName = getActivityComponentName(activityName);
- assertEquals(message, fullActivityName, mAmWmState.getAmState().getResumedActivity());
+ assertEquals(message,
+ getActivityName(activityName), mAmWmState.getAmState().getResumedActivity());
final int frontStackId = mAmWmState.getAmState().getFrontStackId(displayId);
ActivityManagerState.ActivityStack firstFrontStack =
mAmWmState.getAmState().getStackById(frontStackId);
- assertEquals(message, fullActivityName, firstFrontStack.mResumedActivity);
+ assertEquals(message,
+ getActivityName(activityName), firstFrontStack.mResumedActivity);
assertTrue(message,
mAmWmState.getAmState().hasActivityState(activityName, STATE_RESUMED));
mAmWmState.assertFocusedStack("Focus must be on external display", frontStackId);
mAmWmState.assertVisibility(activityName, true /* visible */);
}
- private void waitAndAssertActivityStopped(String activityName, String message)
+ private void waitAndAssertActivityStopped(ComponentName activityName, String message)
throws Exception {
mAmWmState.waitForActivityState(activityName, STATE_STOPPED);
@@ -1688,26 +1688,25 @@
final LockScreenSession lockScreenSession = new LockScreenSession()) {
lockScreenSession.setLockCredential();
- launchActivity(TEST_ACTIVITY_NAME);
+ launchActivity(TEST_ACTIVITY);
final ActivityDisplay newDisplay =
externalDisplaySession.createVirtualDisplay(false /* showContentWhenLocked */);
- launchActivityOnDisplay(SHOW_WHEN_LOCKED_ATTR_ACTIVITY_NAME, newDisplay.mId);
+ launchActivityOnDisplay(SHOW_WHEN_LOCKED_ATTR_ACTIVITY, newDisplay.mId);
lockScreenSession.gotoKeyguard();
- mAmWmState.waitForKeyguardShowingAndNotOccluded();
- mAmWmState.waitForActivityState(TEST_ACTIVITY_NAME, STATE_STOPPED);
- mAmWmState.waitForActivityState(SHOW_WHEN_LOCKED_ATTR_ACTIVITY_NAME, STATE_RESUMED);
+ mAmWmState.waitForActivityState(TEST_ACTIVITY, STATE_STOPPED);
+ mAmWmState.waitForActivityState(SHOW_WHEN_LOCKED_ATTR_ACTIVITY, STATE_RESUMED);
- mAmWmState.computeState(SHOW_WHEN_LOCKED_ATTR_ACTIVITY_NAME);
+ mAmWmState.computeState(SHOW_WHEN_LOCKED_ATTR_ACTIVITY);
assertTrue("Expected resumed activity on secondary display", mAmWmState.getAmState()
- .hasActivityState(SHOW_WHEN_LOCKED_ATTR_ACTIVITY_NAME, STATE_RESUMED));
+ .hasActivityState(SHOW_WHEN_LOCKED_ATTR_ACTIVITY, STATE_RESUMED));
}
}
/** Assert that component received onMovedToDisplay and onConfigurationChanged callbacks. */
- private void assertMovedToDisplay(String componentName, LogSeparator logSeparator)
+ private void assertMovedToDisplay(ComponentName componentName, LogSeparator logSeparator)
throws Exception {
final ActivityLifecycleCounts lifecycleCounts
= new ActivityLifecycleCounts(componentName, logSeparator);
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerPinnedStackTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerPinnedStackTests.java
index 7a28d9a..6a2f9ee 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerPinnedStackTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerPinnedStackTests.java
@@ -27,7 +27,7 @@
import static android.server.am.ActivityManagerState.STATE_RESUMED;
import static android.server.am.ActivityManagerState.STATE_STOPPED;
import static android.server.am.Components.TestActivity.TEST_ACTIVITY_ACTION_FINISH_SELF;
-import static android.view.KeyEvent.KEYCODE_WINDOW;
+import static android.server.am.UiDeviceUtils.pressWindowButton;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -1036,29 +1036,29 @@
launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
launchActivitiesInSplitScreen(
- getLaunchActivityBuilder().setTargetActivityName(LAUNCHING_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivityName(LAUNCHING_ACTIVITY_NAME),
getLaunchActivityBuilder().setTargetActivityName(TEST_ACTIVITY).setRandomData(true)
.setMultipleTask(false)
);
mAmWmState.assertVisibility(PIP_ACTIVITY, true);
- mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true);
+ mAmWmState.assertVisibility(LAUNCHING_ACTIVITY_NAME, true);
mAmWmState.assertVisibility(TEST_ACTIVITY, true);
// Launch the activities again to take focus and make sure nothing is hidden
launchActivitiesInSplitScreen(
- getLaunchActivityBuilder().setTargetActivityName(LAUNCHING_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivityName(LAUNCHING_ACTIVITY_NAME),
getLaunchActivityBuilder().setTargetActivityName(TEST_ACTIVITY).setRandomData(true)
.setMultipleTask(false)
);
- mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true);
+ mAmWmState.assertVisibility(LAUNCHING_ACTIVITY_NAME, true);
mAmWmState.assertVisibility(TEST_ACTIVITY, true);
// Go to recents to make sure that fullscreen stack is invisible
// Some devices do not support recents or implement it differently (instead of using a
// separate stack id or as an activity), for those cases the visibility asserts will be
// ignored
- pressAppSwitchButton();
- mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true);
+ pressAppSwitchButtonAndWaitForRecents();
+ mAmWmState.assertVisibility(LAUNCHING_ACTIVITY_NAME, true);
mAmWmState.assertVisibility(TEST_ACTIVITY, false);
}
@@ -1493,13 +1493,6 @@
}
/**
- * Triggers the window keycode.
- */
- private void pressWindowButton() throws Exception {
- mDevice.pressKeyCode(KEYCODE_WINDOW);
- }
-
- /**
* TODO: Improve tests check to actually check that apps are not interactive instead of checking
* if the stack is focused.
*/
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerReplaceWindowTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerReplaceWindowTests.java
index 233bad6..0ef9364 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerReplaceWindowTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerReplaceWindowTests.java
@@ -17,17 +17,23 @@
package android.server.am;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.server.am.ComponentNameUtils.getWindowName;
+import static android.server.am.Components.NO_RELAUNCH_ACTIVITY;
+import static android.server.am.Components.SLOW_CREATE_ACTIVITY;
import static android.server.am.StateLogger.log;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
-import junit.framework.Assert;
+import android.content.ComponentName;
+import android.os.SystemClock;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.TimeUnit;
/**
* Build/Install/Run:
@@ -35,11 +41,6 @@
*/
public class ActivityManagerReplaceWindowTests extends ActivityManagerTestBase {
- private static final String SLOW_CREATE_ACTIVITY_NAME = "SlowCreateActivity";
- private static final String NO_RELAUNCH_ACTIVITY_NAME = "NoRelaunchActivity";
-
- private List<String> mTempWindowTokens = new ArrayList();
-
@Before
@Override
public void setUp() throws Exception {
@@ -59,20 +60,18 @@
}
private void testReplaceWindow_Dock(boolean relaunch) throws Exception {
- final String activityName =
- relaunch ? SLOW_CREATE_ACTIVITY_NAME : NO_RELAUNCH_ACTIVITY_NAME;
- final String windowName = getActivityWindowName(activityName);
+ final ComponentName activityName = relaunch ? SLOW_CREATE_ACTIVITY : NO_RELAUNCH_ACTIVITY;
+ final String windowName = getWindowName(activityName);
final String amStartCmd = getAmStartCmd(activityName);
executeShellCommand(amStartCmd);
- // Sleep 2 seconds, then check if the window is started properly.
- // SlowCreateActivity will do a sleep inside its onCreate() to simulate a
- // slow-starting app. So instead of relying on WindowManagerState's
- // retrying mechanism, we do an explicit sleep to avoid excess spews
- // from WindowManagerState.
- if (SLOW_CREATE_ACTIVITY_NAME.equals(activityName)) {
- Thread.sleep(2000);
+ // Sleep 2 seconds, then check if the window is started properly. SlowCreateActivity
+ // will do a sleep inside its onCreate() to simulate a slow-starting app. So instead of
+ // relying on WindowManagerState's retrying mechanism, we do an explicit sleep to avoid
+ // excess spews from WindowManagerState.
+ if (relaunch) {
+ SystemClock.sleep(TimeUnit.SECONDS.toMillis(2));
}
log("==========Before Docking========");
@@ -82,26 +81,26 @@
setActivityTaskWindowingMode(activityName, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
// Sleep 5 seconds, then check if the window is replaced properly.
- Thread.sleep(5000);
+ SystemClock.sleep(TimeUnit.SECONDS.toMillis(5));
log("==========After Docking========");
final String newToken = getWindowToken(windowName, activityName);
// For both relaunch and not relaunch case, we'd like the window to be kept.
- Assert.assertEquals("Window replaced while docking.", oldToken, newToken);
+ assertEquals("Window replaced while docking.", oldToken, newToken);
}
- private String getWindowToken(String windowName, String activityName)
- throws Exception {
- mAmWmState.computeState(new WaitForValidActivityState.Builder(activityName).build());
+ private String getWindowToken(String windowName, ComponentName activityName) throws Exception {
+ mAmWmState.computeState(activityName);
mAmWmState.assertVisibility(activityName, true);
- mAmWmState.getWmState().getMatchingWindowTokens(windowName, mTempWindowTokens);
+ final List<String> windowTokens = new ArrayList<>();
+ mAmWmState.getWmState().getMatchingWindowTokens(windowName, windowTokens);
- Assert.assertEquals("Should have exactly one window for the activity.",
- 1, mTempWindowTokens.size());
+ assertEquals("Should have exactly one window for the activity.",
+ 1, windowTokens.size());
- return mTempWindowTokens.get(0);
+ return windowTokens.get(0);
}
}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerSplitScreenTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerSplitScreenTests.java
index a3ab768..b8885ac 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerSplitScreenTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerSplitScreenTests.java
@@ -26,20 +26,31 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.server.am.Components.DOCKED_ACTIVITY;
+import static android.server.am.Components.LAUNCHING_ACTIVITY;
+import static android.server.am.Components.NON_RESIZEABLE_ACTIVITY;
+import static android.server.am.Components.NO_RELAUNCH_ACTIVITY;
+import static android.server.am.Components.SINGLE_INSTANCE_ACTIVITY;
+import static android.server.am.Components.SINGLE_TASK_ACTIVITY;
+import static android.server.am.Components.TEST_ACTIVITY;
import static android.server.am.Components.TestActivity.TEST_ACTIVITY_ACTION_FINISH_SELF;
+import static android.server.am.UiDeviceUtils.pressHomeButton;
import static android.server.am.WindowManagerState.TRANSIT_WALLPAPER_OPEN;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
+import static org.hamcrest.Matchers.lessThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
+import android.content.ComponentName;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.FlakyTest;
@@ -53,13 +64,6 @@
*/
public class ActivityManagerSplitScreenTests extends ActivityManagerTestBase {
- private static final String TEST_ACTIVITY_NAME = "TestActivity";
- private static final String NON_RESIZEABLE_ACTIVITY_NAME = "NonResizeableActivity";
- private static final String DOCKED_ACTIVITY_NAME = "DockedActivity";
- private static final String NO_RELAUNCH_ACTIVITY_NAME = "NoRelaunchActivity";
- private static final String SINGLE_INSTANCE_ACTIVITY_NAME = "SingleInstanceActivity";
- private static final String SINGLE_TASK_ACTIVITY_NAME = "SingleTaskActivity";
-
private static final int TASK_SIZE = 600;
private static final int STACK_SIZE = 300;
@@ -83,8 +87,8 @@
@Presubmit
@FlakyTest(bugId = 71792393)
public void testStackList() throws Exception {
- launchActivity(TEST_ACTIVITY_NAME);
- mAmWmState.computeState(new String[] {TEST_ACTIVITY_NAME});
+ launchActivity(TEST_ACTIVITY);
+ mAmWmState.computeState(TEST_ACTIVITY);
mAmWmState.assertContainsStack("Must contain home stack.",
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME);
mAmWmState.assertContainsStack("Must contain fullscreen stack.",
@@ -96,7 +100,7 @@
@Test
@Presubmit
public void testDockActivity() throws Exception {
- launchActivityInSplitScreenWithRecents(TEST_ACTIVITY_NAME);
+ launchActivityInSplitScreenWithRecents(TEST_ACTIVITY);
mAmWmState.assertContainsStack("Must contain home stack.",
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME);
mAmWmState.assertContainsStack("Must contain docked stack.",
@@ -106,7 +110,7 @@
@Test
@Presubmit
public void testNonResizeableNotDocked() throws Exception {
- launchActivityInSplitScreenWithRecents(NON_RESIZEABLE_ACTIVITY_NAME);
+ launchActivityInSplitScreenWithRecents(NON_RESIZEABLE_ACTIVITY);
mAmWmState.assertContainsStack("Must contain home stack.",
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME);
@@ -119,7 +123,9 @@
@Test
@Presubmit
public void testLaunchToSide() throws Exception {
- launchActivitiesInSplitScreen(LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME);
+ launchActivitiesInSplitScreen(
+ getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
mAmWmState.assertContainsStack("Must contain fullscreen stack.",
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD);
mAmWmState.assertContainsStack("Must contain docked stack.",
@@ -130,7 +136,9 @@
@Presubmit
public void testLaunchToSideMultiWindowCallbacks() throws Exception {
// Launch two activities in split-screen mode.
- launchActivitiesInSplitScreen(LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME);
+ launchActivitiesInSplitScreen(
+ getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
mAmWmState.assertContainsStack("Must contain fullscreen stack.",
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD);
mAmWmState.assertContainsStack("Must contain docked stack.",
@@ -140,7 +148,7 @@
final LogSeparator logSeparator = clearLogcat();
removeStacksInWindowingModes(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
final ActivityLifecycleCounts lifecycleCounts = waitForOnMultiWindowModeChanged(
- TEST_ACTIVITY_NAME, logSeparator);
+ TEST_ACTIVITY, logSeparator);
assertEquals(1, lifecycleCounts.mMultiWindowModeChangedCount);
}
@@ -148,25 +156,25 @@
@Presubmit
@FlakyTest(bugId = 72956284)
public void testNoUserLeaveHintOnMultiWindowModeChanged() throws Exception {
- launchActivity(TEST_ACTIVITY_NAME, WINDOWING_MODE_FULLSCREEN);
+ launchActivity(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
// Move to docked stack.
LogSeparator logSeparator = clearLogcat();
- setActivityTaskWindowingMode(TEST_ACTIVITY_NAME, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ setActivityTaskWindowingMode(TEST_ACTIVITY, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
ActivityLifecycleCounts lifecycleCounts = waitForOnMultiWindowModeChanged(
- TEST_ACTIVITY_NAME, logSeparator);
+ TEST_ACTIVITY, logSeparator);
assertEquals("mMultiWindowModeChangedCount",
1, lifecycleCounts.mMultiWindowModeChangedCount);
assertEquals("mUserLeaveHintCount", 0, lifecycleCounts.mUserLeaveHintCount);
// Make sure docked stack is focused. This way when we dismiss it later fullscreen stack
// will come up.
- launchActivity(TEST_ACTIVITY_NAME, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ launchActivity(TEST_ACTIVITY, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
// Move activity back to fullscreen stack.
logSeparator = clearLogcat();
- setActivityTaskWindowingMode(TEST_ACTIVITY_NAME, WINDOWING_MODE_FULLSCREEN);
- lifecycleCounts = waitForOnMultiWindowModeChanged(TEST_ACTIVITY_NAME, logSeparator);
+ setActivityTaskWindowingMode(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
+ lifecycleCounts = waitForOnMultiWindowModeChanged(TEST_ACTIVITY, logSeparator);
assertEquals("mMultiWindowModeChangedCount",
1, lifecycleCounts.mMultiWindowModeChangedCount);
assertEquals("mUserLeaveHintCount", 0, lifecycleCounts.mUserLeaveHintCount);
@@ -175,26 +183,27 @@
@Test
@Presubmit
public void testLaunchToSideAndBringToFront() throws Exception {
- launchActivitiesInSplitScreen(LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME);
+ launchActivitiesInSplitScreen(
+ getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
int taskNumberInitial = mAmWmState.getAmState().getStandardTaskCountByWindowingMode(
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
mAmWmState.assertFocusedActivity("Launched to side activity must be in front.",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
// Launch another activity to side to cover first one.
- launchActivity(
- NO_RELAUNCH_ACTIVITY_NAME, WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
+ launchActivity(NO_RELAUNCH_ACTIVITY, WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
int taskNumberCovered = mAmWmState.getAmState().getStandardTaskCountByWindowingMode(
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
assertEquals("Fullscreen stack must have one task added.",
taskNumberInitial + 1, taskNumberCovered);
mAmWmState.assertFocusedActivity("Launched to side covering activity must be in front.",
- NO_RELAUNCH_ACTIVITY_NAME);
+ NO_RELAUNCH_ACTIVITY);
// Launch activity that was first launched to side. It should be brought to front.
getLaunchActivityBuilder()
- .setTargetActivityName(TEST_ACTIVITY_NAME)
+ .setTargetActivity(TEST_ACTIVITY)
.setToSide(true)
.setWaitForLaunched(true)
.execute();
@@ -203,58 +212,59 @@
assertEquals("Task number in fullscreen stack must remain the same.",
taskNumberCovered, taskNumberFinal);
mAmWmState.assertFocusedActivity("Launched to side covering activity must be in front.",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
}
@Test
@Presubmit
@FlakyTest(bugId = 71792393)
public void testLaunchToSideMultiple() throws Exception {
- launchActivitiesInSplitScreen(LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME);
+ launchActivitiesInSplitScreen(
+ getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
int taskNumberInitial = mAmWmState.getAmState().getStandardTaskCountByWindowingMode(
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
assertNotNull("Launched to side activity must be in fullscreen stack.",
- mAmWmState.getAmState().getTaskByActivityName(
- TEST_ACTIVITY_NAME, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY));
+ mAmWmState.getAmState().getTaskByActivity(
+ TEST_ACTIVITY, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY));
// Try to launch to side same activity again.
getLaunchActivityBuilder().setToSide(true).execute();
- final String[] waitForActivitiesVisible =
- new String[] {TEST_ACTIVITY_NAME, LAUNCHING_ACTIVITY};
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(TEST_ACTIVITY, LAUNCHING_ACTIVITY);
int taskNumberFinal = mAmWmState.getAmState().getStandardTaskCountByWindowingMode(
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
assertEquals("Task number mustn't change.", taskNumberInitial, taskNumberFinal);
mAmWmState.assertFocusedActivity("Launched to side activity must remain in front.",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
assertNotNull("Launched to side activity must remain in fullscreen stack.",
- mAmWmState.getAmState().getTaskByActivityName(
- TEST_ACTIVITY_NAME, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY));
+ mAmWmState.getAmState().getTaskByActivity(
+ TEST_ACTIVITY, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY));
}
@Test
@Presubmit
+ @FlakyTest(bugId = 73808815)
public void testLaunchToSideSingleInstance() throws Exception {
- launchTargetToSide(SINGLE_INSTANCE_ACTIVITY_NAME, false);
+ launchTargetToSide(SINGLE_INSTANCE_ACTIVITY, false);
}
@Test
public void testLaunchToSideSingleTask() throws Exception {
- launchTargetToSide(SINGLE_TASK_ACTIVITY_NAME, false);
+ launchTargetToSide(SINGLE_TASK_ACTIVITY, false);
}
@Presubmit
@FlakyTest(bugId = 71792393)
@Test
public void testLaunchToSideMultipleWithDifferentIntent() throws Exception {
- launchTargetToSide(TEST_ACTIVITY_NAME, true);
+ launchTargetToSide(TEST_ACTIVITY, true);
}
- private void launchTargetToSide(String targetActivityName, boolean taskCountMustIncrement)
- throws Exception {
+ private void launchTargetToSide(ComponentName targetActivityName,
+ boolean taskCountMustIncrement) throws Exception {
final LaunchActivityBuilder targetActivityLauncher = getLaunchActivityBuilder()
- .setTargetActivityName(targetActivityName)
+ .setTargetActivity(targetActivityName)
.setToSide(true)
.setRandomData(true)
.setMultipleTask(false);
@@ -263,27 +273,21 @@
// the target being launched directly. Options such as LaunchActivityBuilder#setRandomData
// are not respected.
launchActivitiesInSplitScreen(
- getLaunchActivityBuilder().setTargetActivityName(LAUNCHING_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
targetActivityLauncher);
- final WaitForValidActivityState[] waitForActivitiesVisible =
- new WaitForValidActivityState[] {
- new WaitForValidActivityState.Builder(targetActivityName).build(),
- new WaitForValidActivityState.Builder(LAUNCHING_ACTIVITY).build()
- };
-
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(targetActivityName, LAUNCHING_ACTIVITY);
mAmWmState.assertContainsStack("Must contain fullscreen stack.",
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD);
int taskNumberInitial = mAmWmState.getAmState().getStandardTaskCountByWindowingMode(
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
assertNotNull("Launched to side activity must be in fullscreen stack.",
- mAmWmState.getAmState().getTaskByActivityName(
+ mAmWmState.getAmState().getTaskByActivity(
targetActivityName, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY));
// Try to launch to side same activity again with different data.
targetActivityLauncher.execute();
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(targetActivityName, LAUNCHING_ACTIVITY);
int taskNumberSecondLaunch = mAmWmState.getAmState().getStandardTaskCountByWindowingMode(
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
if (taskCountMustIncrement) {
@@ -296,14 +300,14 @@
mAmWmState.assertFocusedActivity("Launched to side activity must be in front.",
targetActivityName);
assertNotNull("Launched to side activity must be launched in fullscreen stack.",
- mAmWmState.getAmState().getTaskByActivityName(
+ mAmWmState.getAmState().getTaskByActivity(
targetActivityName, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY));
// Try to launch to side same activity again with different random data. Note that null
// cannot be used here, since the first instance of TestActivity is launched with no data
// in order to launch into split screen.
targetActivityLauncher.execute();
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(targetActivityName, LAUNCHING_ACTIVITY);
int taskNumberFinal = mAmWmState.getAmState().getStandardTaskCountByWindowingMode(
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
if (taskCountMustIncrement) {
@@ -316,39 +320,41 @@
mAmWmState.assertFocusedActivity("Launched to side activity must be in front.",
targetActivityName);
assertNotNull("Launched to side activity must be launched in fullscreen stack.",
- mAmWmState.getAmState().getTaskByActivityName(
+ mAmWmState.getAmState().getTaskByActivity(
targetActivityName, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY));
}
@Presubmit
@Test
public void testLaunchToSideMultipleWithFlag() throws Exception {
- launchActivitiesInSplitScreen(LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME);
+ launchActivitiesInSplitScreen(
+ getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
int taskNumberInitial = mAmWmState.getAmState().getStandardTaskCountByWindowingMode(
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
assertNotNull("Launched to side activity must be in fullscreen stack.",
- mAmWmState.getAmState().getTaskByActivityName(
- TEST_ACTIVITY_NAME, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY));
+ mAmWmState.getAmState().getTaskByActivity(
+ TEST_ACTIVITY, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY));
// Try to launch to side same activity again, but with Intent#FLAG_ACTIVITY_MULTIPLE_TASK.
getLaunchActivityBuilder().setToSide(true).setMultipleTask(true).execute();
- final String[] waitForActivitiesVisible =
- new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME};
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(LAUNCHING_ACTIVITY, TEST_ACTIVITY);
int taskNumberFinal = mAmWmState.getAmState().getStandardTaskCountByWindowingMode(
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
assertEquals("Task number must be incremented.", taskNumberInitial + 1,
taskNumberFinal);
mAmWmState.assertFocusedActivity("Launched to side activity must be in front.",
- TEST_ACTIVITY_NAME);
+ TEST_ACTIVITY);
assertNotNull("Launched to side activity must remain in fullscreen stack.",
- mAmWmState.getAmState().getTaskByActivityName(
- TEST_ACTIVITY_NAME, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY));
+ mAmWmState.getAmState().getTaskByActivity(
+ TEST_ACTIVITY, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY));
}
@Test
public void testRotationWhenDocked() throws Exception {
- launchActivitiesInSplitScreen(LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME);
+ launchActivitiesInSplitScreen(
+ getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
mAmWmState.assertContainsStack("Must contain fullscreen stack.",
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD);
mAmWmState.assertContainsStack("Must contain docked stack.",
@@ -356,40 +362,38 @@
// Rotate device single steps (90°) 0-1-2-3.
// Each time we compute the state we implicitly assert valid bounds.
- String[] waitForActivitiesVisible =
- new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME};
try (final RotationSession rotationSession = new RotationSession()) {
for (int i = 0; i < 4; i++) {
rotationSession.set(i);
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(LAUNCHING_ACTIVITY, TEST_ACTIVITY);
}
// Double steps (180°) We ended the single step at 3. So, we jump directly to 1 for
// double step. So, we are testing 3-1-3 for one side and 0-2-0 for the other side.
rotationSession.set(ROTATION_90);
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(LAUNCHING_ACTIVITY, TEST_ACTIVITY);
rotationSession.set(ROTATION_270);
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(LAUNCHING_ACTIVITY, TEST_ACTIVITY);
rotationSession.set(ROTATION_0);
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(LAUNCHING_ACTIVITY, TEST_ACTIVITY);
rotationSession.set(ROTATION_180);
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(LAUNCHING_ACTIVITY, TEST_ACTIVITY);
rotationSession.set(ROTATION_0);
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(LAUNCHING_ACTIVITY, TEST_ACTIVITY);
}
}
@Test
@Presubmit
public void testRotationWhenDockedWhileLocked() throws Exception {
- launchActivitiesInSplitScreen(LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME);
+ launchActivitiesInSplitScreen(
+ getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
mAmWmState.assertSanity();
mAmWmState.assertContainsStack("Must contain fullscreen stack.",
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD);
mAmWmState.assertContainsStack("Must contain docked stack.",
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD);
- String[] waitForActivitiesVisible =
- new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME};
try (final RotationSession rotationSession = new RotationSession();
final LockScreenSession lockScreenSession = new LockScreenSession()) {
for (int i = 0; i < 4; i++) {
@@ -397,7 +401,7 @@
rotationSession.set(i);
lockScreenSession.wakeUpDevice()
.unlockDevice();
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(LAUNCHING_ACTIVITY, TEST_ACTIVITY);
}
}
}
@@ -407,11 +411,11 @@
try (final RotationSession rotationSession = new RotationSession()) {
for (int i = 0; i < 2; i++) {
rotationSession.set(i);
- launchActivityInDockStackAndMinimize(TEST_ACTIVITY_NAME);
+ launchActivityInDockStackAndMinimize(TEST_ACTIVITY);
if (!mAmWmState.isScreenPortrait() && isTablet()) {
// Test minimize to the right only on tablets in landscape
removeStacksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME);
- launchActivityInDockStackAndMinimize(TEST_ACTIVITY_NAME,
+ launchActivityInDockStackAndMinimize(TEST_ACTIVITY,
SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT);
}
removeStacksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME);
@@ -422,30 +426,29 @@
@Test
@Presubmit
public void testRotationWhileDockMinimized() throws Exception {
- launchActivityInDockStackAndMinimize(TEST_ACTIVITY_NAME);
+ launchActivityInDockStackAndMinimize(TEST_ACTIVITY);
// Rotate device single steps (90°) 0-1-2-3.
// Each time we compute the state we implicitly assert valid bounds in minimized mode.
- String[] waitForActivitiesVisible = new String[] {TEST_ACTIVITY_NAME};
try (final RotationSession rotationSession = new RotationSession()) {
for (int i = 0; i < 4; i++) {
rotationSession.set(i);
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(TEST_ACTIVITY);
}
// Double steps (180°) We ended the single step at 3. So, we jump directly to 1 for
// double step. So, we are testing 3-1-3 for one side and 0-2-0 for the other side in
// minimized mode.
rotationSession.set(ROTATION_90);
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(TEST_ACTIVITY);
rotationSession.set(ROTATION_270);
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(TEST_ACTIVITY);
rotationSession.set(ROTATION_0);
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(TEST_ACTIVITY);
rotationSession.set(ROTATION_180);
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(TEST_ACTIVITY);
rotationSession.set(ROTATION_0);
- mAmWmState.computeState(waitForActivitiesVisible);
+ mAmWmState.computeState(TEST_ACTIVITY);
}
}
@@ -456,22 +459,23 @@
try (final RotationSession rotationSession = new RotationSession()) {
for (int i = 0; i < 4; i++) {
rotationSession.set(i);
- launchActivityInDockStackAndMinimize(DOCKED_ACTIVITY_NAME);
+ launchActivityInDockStackAndMinimize(DOCKED_ACTIVITY);
// Unminimize the docked stack
- pressAppSwitchButton();
+ pressAppSwitchButtonAndWaitForRecents();
waitForDockNotMinimized();
assertDockNotMinimized();
// Dismiss the dock stack
- launchActivity(TEST_ACTIVITY_NAME,
+ launchActivity(TEST_ACTIVITY,
WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
- setActivityTaskWindowingMode(DOCKED_ACTIVITY_NAME,
+ setActivityTaskWindowingMode(DOCKED_ACTIVITY,
WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
- mAmWmState.computeState(new String[]{DOCKED_ACTIVITY_NAME});
+ mAmWmState.computeState(DOCKED_ACTIVITY);
// Go home and check the app transition
- assertNotSame(TRANSIT_WALLPAPER_OPEN, mAmWmState.getWmState().getLastTransition());
+ assertNotEquals(
+ TRANSIT_WALLPAPER_OPEN, mAmWmState.getWmState().getLastTransition());
pressHomeButton();
mAmWmState.computeState(true);
assertEquals(TRANSIT_WALLPAPER_OPEN, mAmWmState.getWmState().getLastTransition());
@@ -479,55 +483,58 @@
}
}
+ @FlakyTest(bugId = 73813034)
@Test
@Presubmit
public void testFinishDockActivityWhileMinimized() throws Exception {
- launchActivityInDockStackAndMinimize(TEST_ACTIVITY_NAME);
+ launchActivityInDockStackAndMinimize(TEST_ACTIVITY);
executeShellCommand("am broadcast -a " + TEST_ACTIVITY_ACTION_FINISH_SELF);
waitForDockNotMinimized();
- mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, false);
+ mAmWmState.assertVisibility(TEST_ACTIVITY, false);
assertDockNotMinimized();
}
@Test
@Presubmit
public void testDockedStackToMinimizeWhenUnlocked() throws Exception {
- launchActivityInSplitScreenWithRecents(TEST_ACTIVITY_NAME);
- mAmWmState.computeState(new WaitForValidActivityState(TEST_ACTIVITY_NAME));
+ launchActivityInSplitScreenWithRecents(TEST_ACTIVITY);
+ mAmWmState.computeState(TEST_ACTIVITY);
try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
lockScreenSession.sleepDevice()
.wakeUpDevice()
.unlockDevice();
- mAmWmState.computeState(new WaitForValidActivityState(TEST_ACTIVITY_NAME));
+ mAmWmState.computeState(TEST_ACTIVITY);
assertDockMinimized();
}
}
@Test
public void testMinimizedStateWhenUnlockedAndUnMinimized() throws Exception {
- launchActivityInDockStackAndMinimize(TEST_ACTIVITY_NAME);
+ launchActivityInDockStackAndMinimize(TEST_ACTIVITY);
try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
lockScreenSession.sleepDevice()
.wakeUpDevice()
.unlockDevice();
- mAmWmState.computeState(new WaitForValidActivityState(TEST_ACTIVITY_NAME));
+ mAmWmState.computeState(TEST_ACTIVITY);
// Unminimized back to splitscreen
- pressAppSwitchButton();
- mAmWmState.computeState(new WaitForValidActivityState(TEST_ACTIVITY_NAME));
+ pressAppSwitchButtonAndWaitForRecents();
+ mAmWmState.computeState(TEST_ACTIVITY);
}
}
@Test
@Presubmit
public void testResizeDockedStack() throws Exception {
- launchActivitiesInSplitScreen(DOCKED_ACTIVITY_NAME, TEST_ACTIVITY_NAME);
+ launchActivitiesInSplitScreen(
+ getLaunchActivityBuilder().setTargetActivity(DOCKED_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
resizeDockedStack(STACK_SIZE, STACK_SIZE, TASK_SIZE, TASK_SIZE);
mAmWmState.computeState(false /* compareTaskAndStackBounds */,
- new WaitForValidActivityState.Builder(TEST_ACTIVITY_NAME).build(),
- new WaitForValidActivityState.Builder(DOCKED_ACTIVITY_NAME).build());
+ new WaitForValidActivityState(TEST_ACTIVITY),
+ new WaitForValidActivityState(DOCKED_ACTIVITY));
mAmWmState.assertContainsStack("Must contain secondary split-screen stack.",
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD);
mAmWmState.assertContainsStack("Must contain primary split-screen stack.",
@@ -535,46 +542,41 @@
assertEquals(new Rect(0, 0, STACK_SIZE, STACK_SIZE),
mAmWmState.getAmState().getStandardStackByWindowingMode(
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).getBounds());
- mAmWmState.assertDockedTaskBounds(TASK_SIZE, TASK_SIZE, DOCKED_ACTIVITY_NAME);
- mAmWmState.assertVisibility(DOCKED_ACTIVITY_NAME, true);
- mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true);
+ mAmWmState.assertDockedTaskBounds(TASK_SIZE, TASK_SIZE, DOCKED_ACTIVITY);
+ mAmWmState.assertVisibility(DOCKED_ACTIVITY, true);
+ mAmWmState.assertVisibility(TEST_ACTIVITY, true);
}
@Test
public void testActivityLifeCycleOnResizeDockedStack() throws Exception {
- final WaitForValidActivityState[] waitTestActivityName =
- new WaitForValidActivityState[] {new WaitForValidActivityState.Builder(
- TEST_ACTIVITY_NAME).build()};
- launchActivity(TEST_ACTIVITY_NAME);
- mAmWmState.computeState(waitTestActivityName);
+ launchActivity(TEST_ACTIVITY);
+ mAmWmState.computeState(TEST_ACTIVITY);
final Rect fullScreenBounds = mAmWmState.getWmState().getStandardStackByWindowingMode(
WINDOWING_MODE_FULLSCREEN).getBounds();
- setActivityTaskWindowingMode(TEST_ACTIVITY_NAME, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- mAmWmState.computeState(waitTestActivityName);
- launchActivity(NO_RELAUNCH_ACTIVITY_NAME,
- WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
+ setActivityTaskWindowingMode(TEST_ACTIVITY, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ mAmWmState.computeState(TEST_ACTIVITY);
+ launchActivity(NO_RELAUNCH_ACTIVITY, WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
- mAmWmState.computeState(new WaitForValidActivityState.Builder(TEST_ACTIVITY_NAME).build(),
- new WaitForValidActivityState.Builder(NO_RELAUNCH_ACTIVITY_NAME).build());
+ mAmWmState.computeState(TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY);
final Rect initialDockBounds = mAmWmState.getWmState().getStandardStackByWindowingMode(
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) .getBounds();
final LogSeparator logSeparator = clearLogcat();
Rect newBounds = computeNewDockBounds(fullScreenBounds, initialDockBounds, true);
- resizeDockedStack(newBounds.width(), newBounds.height(), newBounds.width(), newBounds.height());
- mAmWmState.computeState(new WaitForValidActivityState.Builder(TEST_ACTIVITY_NAME).build(),
- new WaitForValidActivityState.Builder(NO_RELAUNCH_ACTIVITY_NAME).build());
+ resizeDockedStack(
+ newBounds.width(), newBounds.height(), newBounds.width(), newBounds.height());
+ mAmWmState.computeState(TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY);
// We resize twice to make sure we cross an orientation change threshold for both
// activities.
newBounds = computeNewDockBounds(fullScreenBounds, initialDockBounds, false);
- resizeDockedStack(newBounds.width(), newBounds.height(), newBounds.width(), newBounds.height());
- mAmWmState.computeState(new WaitForValidActivityState.Builder(TEST_ACTIVITY_NAME).build(),
- new WaitForValidActivityState.Builder(NO_RELAUNCH_ACTIVITY_NAME).build());
- assertActivityLifecycle(TEST_ACTIVITY_NAME, true /* relaunched */, logSeparator);
- assertActivityLifecycle(NO_RELAUNCH_ACTIVITY_NAME, false /* relaunched */, logSeparator);
+ resizeDockedStack(
+ newBounds.width(), newBounds.height(), newBounds.width(), newBounds.height());
+ mAmWmState.computeState(TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY);
+ assertActivityLifecycle(TEST_ACTIVITY, true /* relaunched */, logSeparator);
+ assertActivityLifecycle(NO_RELAUNCH_ACTIVITY, false /* relaunched */, logSeparator);
}
private Rect computeNewDockBounds(
@@ -597,41 +599,44 @@
@Test
@Presubmit
public void testStackListOrderLaunchDockedActivity() throws Exception {
- launchActivityInSplitScreenWithRecents(TEST_ACTIVITY_NAME);
+ launchActivityInSplitScreenWithRecents(TEST_ACTIVITY);
final int homeStackIndex = mAmWmState.getStackIndexByActivityType(ACTIVITY_TYPE_HOME);
final int recentsStackIndex = mAmWmState.getStackIndexByActivityType(ACTIVITY_TYPE_RECENTS);
- assertTrue("Recents stack should be on top of home stack",
- recentsStackIndex < homeStackIndex);
+ assertThat("Recents stack should be on top of home stack",
+ recentsStackIndex, lessThan(homeStackIndex));
}
@Test
@Presubmit
public void testStackListOrderOnSplitScreenDismissed() throws Exception {
- launchActivitiesInSplitScreen(DOCKED_ACTIVITY_NAME, TEST_ACTIVITY_NAME);
+ launchActivitiesInSplitScreen(
+ getLaunchActivityBuilder().setTargetActivity(DOCKED_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
- setActivityTaskWindowingMode(DOCKED_ACTIVITY_NAME, WINDOWING_MODE_FULLSCREEN);
- mAmWmState.computeState(new WaitForValidActivityState.Builder(
- DOCKED_ACTIVITY_NAME).setWindowingMode(WINDOWING_MODE_FULLSCREEN).build());
+ setActivityTaskWindowingMode(DOCKED_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
+ mAmWmState.computeState(new WaitForValidActivityState.Builder(DOCKED_ACTIVITY)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+ .build());
final int homeStackIndex = mAmWmState.getStackIndexByActivityType(ACTIVITY_TYPE_HOME);
final int prevSplitScreenPrimaryIndex =
- mAmWmState.getAmState().getStackIndexByActivityName(DOCKED_ACTIVITY_NAME);
+ mAmWmState.getAmState().getStackIndexByActivity(DOCKED_ACTIVITY);
final int prevSplitScreenSecondaryIndex =
- mAmWmState.getAmState().getStackIndexByActivityName(TEST_ACTIVITY_NAME);
+ mAmWmState.getAmState().getStackIndexByActivity(TEST_ACTIVITY);
final int expectedHomeStackIndex =
(prevSplitScreenPrimaryIndex > prevSplitScreenSecondaryIndex
? prevSplitScreenPrimaryIndex : prevSplitScreenSecondaryIndex) - 1;
- assertTrue("Home stack needs to be directly behind the top stack",
- expectedHomeStackIndex == homeStackIndex);
+ assertEquals("Home stack needs to be directly behind the top stack",
+ expectedHomeStackIndex, homeStackIndex);
}
- private void launchActivityInDockStackAndMinimize(String activityName) throws Exception {
+ private void launchActivityInDockStackAndMinimize(ComponentName activityName) throws Exception {
launchActivityInDockStackAndMinimize(activityName, SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT);
}
- private void launchActivityInDockStackAndMinimize(String activityName, int createMode)
+ private void launchActivityInDockStackAndMinimize(ComponentName activityName, int createMode)
throws Exception {
launchActivityInSplitScreenWithRecents(activityName, createMode);
pressHomeButton();
@@ -645,7 +650,7 @@
private void waitForAndAssertDockMinimized() throws Exception {
waitForDockMinimized();
assertDockMinimized();
- mAmWmState.computeState(new WaitForValidActivityState.Builder(TEST_ACTIVITY_NAME).build());
+ mAmWmState.computeState(TEST_ACTIVITY);
mAmWmState.assertContainsStack("Must contain docked stack.",
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD);
mAmWmState.assertFocusedStack("Home activity should be focused in minimized mode",
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerTransitionSelectionTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerTransitionSelectionTests.java
index fe05359..925f9a4 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerTransitionSelectionTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerTransitionSelectionTests.java
@@ -16,6 +16,9 @@
package android.server.am;
+import static android.server.am.Components.BOTTOM_ACTIVITY;
+import static android.server.am.Components.TOP_ACTIVITY;
+import static android.server.am.Components.TRANSLUCENT_TOP_ACTIVITY;
import static android.server.am.WindowManagerState.TRANSIT_ACTIVITY_CLOSE;
import static android.server.am.WindowManagerState.TRANSIT_ACTIVITY_OPEN;
import static android.server.am.WindowManagerState.TRANSIT_TASK_CLOSE;
@@ -27,6 +30,7 @@
import static org.junit.Assert.assertEquals;
+import android.content.ComponentName;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.FlakyTest;
@@ -48,12 +52,6 @@
@FlakyTest(bugId = 71792333)
public class ActivityManagerTransitionSelectionTests extends ActivityManagerTestBase {
- private static final String BOTTOM_ACTIVITY_NAME = "BottomActivity";
- private static final String TOP_ACTIVITY_NAME = "TopActivity";
- private static final String TRANSLUCENT_TOP_ACTIVITY_NAME = "TranslucentTopActivity";
-
- //------------------------------------------------------------------------//
-
// Test activity open/close under normal timing
@Test
public void testOpenActivity_NeitherWallpaper() throws Exception {
@@ -225,40 +223,46 @@
testTransitionSelection(true /*testOpen*/, false /*testNewTask*/,
bottomWallpaper, topWallpaper, false /*topTranslucent*/, slowStop, expectedTransit);
}
+
private void testCloseActivity(boolean bottomWallpaper,
boolean topWallpaper, boolean slowStop, String expectedTransit) throws Exception {
testTransitionSelection(false /*testOpen*/, false /*testNewTask*/,
bottomWallpaper, topWallpaper, false /*topTranslucent*/, slowStop, expectedTransit);
}
+
private void testOpenTask(boolean bottomWallpaper,
boolean topWallpaper, boolean slowStop, String expectedTransit) throws Exception {
testTransitionSelection(true /*testOpen*/, true /*testNewTask*/,
bottomWallpaper, topWallpaper, false /*topTranslucent*/, slowStop, expectedTransit);
}
+
private void testCloseTask(boolean bottomWallpaper,
boolean topWallpaper, boolean slowStop, String expectedTransit) throws Exception {
testTransitionSelection(false /*testOpen*/, true /*testNewTask*/,
bottomWallpaper, topWallpaper, false /*topTranslucent*/, slowStop, expectedTransit);
}
+
private void testCloseActivityTranslucent(boolean bottomWallpaper,
boolean topWallpaper, String expectedTransit) throws Exception {
testTransitionSelection(false /*testOpen*/, false /*testNewTask*/,
bottomWallpaper, topWallpaper, true /*topTranslucent*/,
false /*slowStop*/, expectedTransit);
}
+
private void testCloseTaskTranslucent(boolean bottomWallpaper,
boolean topWallpaper, String expectedTransit) throws Exception {
testTransitionSelection(false /*testOpen*/, true /*testNewTask*/,
bottomWallpaper, topWallpaper, true /*topTranslucent*/,
false /*slowStop*/, expectedTransit);
}
+
//------------------------------------------------------------------------//
private void testTransitionSelection(
boolean testOpen, boolean testNewTask,
boolean bottomWallpaper, boolean topWallpaper, boolean topTranslucent,
boolean testSlowStop, String expectedTransit) throws Exception {
- String bottomStartCmd = getAmStartCmd(BOTTOM_ACTIVITY_NAME);
+ String bottomStartCmd = getAmStartCmd(BOTTOM_ACTIVITY);
if (bottomWallpaper) {
bottomStartCmd += " --ez USE_WALLPAPER true";
}
@@ -267,11 +271,10 @@
}
executeShellCommand(bottomStartCmd);
- mAmWmState.computeState(new WaitForValidActivityState(BOTTOM_ACTIVITY_NAME));
+ mAmWmState.computeState(BOTTOM_ACTIVITY);
- final String topActivityName = topTranslucent ?
- TRANSLUCENT_TOP_ACTIVITY_NAME : TOP_ACTIVITY_NAME;
- String topStartCmd = getAmStartCmd(topActivityName);
+ final ComponentName topActivity = topTranslucent ? TRANSLUCENT_TOP_ACTIVITY : TOP_ACTIVITY;
+ String topStartCmd = getAmStartCmd(topActivity);
if (testNewTask) {
topStartCmd += " -f 0x18000000";
}
@@ -285,9 +288,9 @@
Thread.sleep(5000);
if (testOpen) {
- mAmWmState.computeState(new WaitForValidActivityState(topActivityName));
+ mAmWmState.computeState(topActivity);
} else {
- mAmWmState.computeState(new WaitForValidActivityState(BOTTOM_ACTIVITY_NAME));
+ mAmWmState.computeState(BOTTOM_ACTIVITY);
}
assertEquals("Picked wrong transition", expectedTransit,
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java
index 3c0a584..82576e8 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java
@@ -17,6 +17,11 @@
package android.server.am;
import static android.server.am.ActivityAndWindowManagersState.DEFAULT_DISPLAY_ID;
+import static android.server.am.ComponentNameUtils.getActivityName;
+import static android.server.am.Components.ALT_LAUNCHING_ACTIVITY;
+import static android.server.am.Components.LAUNCHING_ACTIVITY;
+import static android.server.am.Components.RESIZEABLE_ACTIVITY;
+import static android.server.am.Components.VR_TEST_ACTIVITY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -34,8 +39,6 @@
* atest CtsActivityManagerDeviceTestCases:ActivityManagerVrDisplayTests
*/
public class ActivityManagerVrDisplayTests extends ActivityManagerDisplayTestBase {
- private static final String RESIZEABLE_ACTIVITY_NAME = "ResizeableActivity";
- private static final String VR_TEST_ACTIVITY_NAME = "VrTestActivity";
private static final int VR_VIRTUAL_DISPLAY_WIDTH = 700;
private static final int VR_VIRTUAL_DISPLAY_HEIGHT = 900;
private static final int VR_VIRTUAL_DISPLAY_DPI = 320;
@@ -74,13 +77,13 @@
vrModeSession.enablePersistentVrMode();
// Launch the VR activity.
- launchActivity(VR_TEST_ACTIVITY_NAME);
- mAmWmState.computeState(new WaitForValidActivityState(VR_TEST_ACTIVITY_NAME));
- mAmWmState.assertVisibility(VR_TEST_ACTIVITY_NAME, true /* visible */);
+ launchActivity(VR_TEST_ACTIVITY);
+ mAmWmState.computeState(VR_TEST_ACTIVITY);
+ mAmWmState.assertVisibility(VR_TEST_ACTIVITY, true /* visible */);
// Launch the non-VR 2D activity and check where it ends up.
launchActivity(LAUNCHING_ACTIVITY);
- mAmWmState.computeState(new WaitForValidActivityState(LAUNCHING_ACTIVITY));
+ mAmWmState.computeState(LAUNCHING_ACTIVITY);
// Ensure that the subsequent activity is visible
mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
@@ -92,7 +95,7 @@
final ActivityManagerState.ActivityStack focusedStack
= mAmWmState.getAmState().getStackById(focusedStackId);
assertEquals("Launched activity must be resumed in focused stack",
- getActivityComponentName(LAUNCHING_ACTIVITY), focusedStack.mResumedActivity);
+ getActivityName(LAUNCHING_ACTIVITY), focusedStack.mResumedActivity);
// Check if the launch activity is in Vr virtual display id.
final List<ActivityDisplay> reportedDisplays = getDisplaysStates();
@@ -121,13 +124,13 @@
vrModeSession.enablePersistentVrMode();
// Launch the VR activity.
- launchActivity(VR_TEST_ACTIVITY_NAME);
- mAmWmState.computeState(new WaitForValidActivityState(VR_TEST_ACTIVITY_NAME));
- mAmWmState.assertVisibility(VR_TEST_ACTIVITY_NAME, true /* visible */);
+ launchActivity(VR_TEST_ACTIVITY);
+ mAmWmState.computeState(VR_TEST_ACTIVITY);
+ mAmWmState.assertVisibility(VR_TEST_ACTIVITY, true /* visible */);
// Re-launch the non-VR 2D activity and check where it ends up.
launchActivity(LAUNCHING_ACTIVITY);
- mAmWmState.computeState(new WaitForValidActivityState(LAUNCHING_ACTIVITY));
+ mAmWmState.computeState(LAUNCHING_ACTIVITY);
// Ensure that the subsequent activity is visible
mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
@@ -139,7 +142,7 @@
final ActivityManagerState.ActivityStack focusedStack
= mAmWmState.getAmState().getStackById(focusedStackId);
assertEquals("Launched activity must be resumed in focused stack",
- getActivityComponentName(LAUNCHING_ACTIVITY), focusedStack.mResumedActivity);
+ getActivityName(LAUNCHING_ACTIVITY), focusedStack.mResumedActivity);
// Check if the launch activity is in Vr virtual display id.
final List<ActivityDisplay> reportedDisplays = getDisplaysStates();
@@ -165,13 +168,13 @@
vrModeSession.enablePersistentVrMode();
// Launch the VR activity.
- launchActivity(VR_TEST_ACTIVITY_NAME);
- mAmWmState.computeState(new WaitForValidActivityState(VR_TEST_ACTIVITY_NAME));
- mAmWmState.assertVisibility(VR_TEST_ACTIVITY_NAME, true /* visible */);
+ launchActivity(VR_TEST_ACTIVITY);
+ mAmWmState.computeState(VR_TEST_ACTIVITY);
+ mAmWmState.assertVisibility(VR_TEST_ACTIVITY, true /* visible */);
// Launch the non-VR 2D activity and check where it ends up.
launchActivity(ALT_LAUNCHING_ACTIVITY);
- mAmWmState.computeState(new WaitForValidActivityState(ALT_LAUNCHING_ACTIVITY));
+ mAmWmState.computeState(ALT_LAUNCHING_ACTIVITY);
// Ensure that the subsequent activity is visible
mAmWmState.assertVisibility(ALT_LAUNCHING_ACTIVITY, true /* visible */);
@@ -183,7 +186,7 @@
final ActivityManagerState.ActivityStack focusedStack
= mAmWmState.getAmState().getStackById(focusedStackId);
assertEquals("Launched activity must be resumed in focused stack",
- getActivityComponentName(ALT_LAUNCHING_ACTIVITY),
+ getActivityName(ALT_LAUNCHING_ACTIVITY),
focusedStack.mResumedActivity);
// Check if the launch activity is in Vr virtual display id.
@@ -209,20 +212,19 @@
}
// Launch the non-VR 2D activity and check where it ends up.
- launchActivity(RESIZEABLE_ACTIVITY_NAME);
- mAmWmState.computeState(new WaitForValidActivityState(RESIZEABLE_ACTIVITY_NAME));
+ launchActivity(RESIZEABLE_ACTIVITY);
+ mAmWmState.computeState(RESIZEABLE_ACTIVITY);
// Ensure that the subsequent activity is visible
- mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true /* visible */);
+ mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */);
// Check that activity is launched in focused stack on primary display.
- mAmWmState.assertFocusedActivity("Launched activity must be focused",
- RESIZEABLE_ACTIVITY_NAME);
+ mAmWmState.assertFocusedActivity("Launched activity must be focused", RESIZEABLE_ACTIVITY);
final int frontStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY_ID);
final ActivityManagerState.ActivityStack frontStack
= mAmWmState.getAmState().getStackById(frontStackId);
assertEquals("Launched activity must be resumed in front stack",
- getActivityComponentName(RESIZEABLE_ACTIVITY_NAME), frontStack.mResumedActivity);
+ getActivityName(RESIZEABLE_ACTIVITY), frontStack.mResumedActivity);
assertEquals("Front stack must be on primary display",
DEFAULT_DISPLAY_ID, frontStack.mDisplayId);
}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/AnimationBackgroundTests.java b/tests/framework/base/activitymanager/src/android/server/am/AnimationBackgroundTests.java
index fd8ed2f..c8e3fa1 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/AnimationBackgroundTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/AnimationBackgroundTests.java
@@ -16,15 +16,16 @@
package android.server.am;
-
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.server.am.Components.ANIMATION_TEST_ACTIVITY;
+import static android.server.am.Components.LAUNCHING_ACTIVITY;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
-import static android.server.am.ActivityAndWindowManagersState.DEFAULT_DISPLAY_ID;
-
/**
* Build/Install/Run:
* atest CtsActivityManagerDeviceTestCases:AnimationBackgroundTests
@@ -33,9 +34,9 @@
@Test
public void testAnimationBackground_duringAnimation() throws Exception {
- launchActivityOnDisplay(LAUNCHING_ACTIVITY, DEFAULT_DISPLAY_ID);
+ launchActivityOnDisplay(LAUNCHING_ACTIVITY, DEFAULT_DISPLAY);
getLaunchActivityBuilder()
- .setTargetActivityName("AnimationTestActivity")
+ .setTargetActivity(ANIMATION_TEST_ACTIVITY)
.setWaitForLaunched(false)
.execute();
@@ -51,9 +52,9 @@
@Test
public void testAnimationBackground_gone() throws Exception {
- launchActivityOnDisplay(LAUNCHING_ACTIVITY, DEFAULT_DISPLAY_ID);
- getLaunchActivityBuilder().setTargetActivityName("AnimationTestActivity").execute();
- mAmWmState.computeState(new WaitForValidActivityState.Builder("AnimationTestActivity").build());
+ launchActivityOnDisplay(LAUNCHING_ACTIVITY, DEFAULT_DISPLAY);
+ getLaunchActivityBuilder().setTargetActivity(ANIMATION_TEST_ACTIVITY).execute();
+ mAmWmState.computeState(ANIMATION_TEST_ACTIVITY);
assertFalse("window animation background needs to be gone", mAmWmState.getWmState()
.getStandardStackByWindowingMode(WINDOWING_MODE_FULLSCREEN)
.isWindowAnimationBackgroundSurfaceShowing());
diff --git a/tests/framework/base/activitymanager/src/android/server/am/DeprecatedTargetSdkTest.java b/tests/framework/base/activitymanager/src/android/server/am/DeprecatedTargetSdkTest.java
index 42edc5f..167ba4b 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/DeprecatedTargetSdkTest.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/DeprecatedTargetSdkTest.java
@@ -16,8 +16,13 @@
package android.server.am;
+import static android.server.am.ComponentNameUtils.getWindowName;
+import static android.server.am.UiDeviceUtils.pressBackButton;
+import static android.server.am.deprecatedsdk.Components.MAIN_ACTIVITY;
+
import static org.junit.Assert.assertTrue;
+import android.content.ComponentName;
import android.support.test.runner.AndroidJUnit4;
import org.junit.After;
@@ -32,11 +37,10 @@
*/
@RunWith(AndroidJUnit4.class)
public class DeprecatedTargetSdkTest extends ActivityManagerTestBase {
- private static final String AM_START_COMMAND = "am start -n %s/%s.%s";
- private static final String AM_FORCE_STOP = "am force-stop %s";
- private static final int ACTIVITY_TIMEOUT_MILLIS = 1000;
- private static final int WINDOW_TIMEOUT_MILLIS = 1000;
+ /** @see com.android.server.am.DeprecatedTargetSdkVersionDialog */
+ private static final String DEPRECATED_TARGET_SDK_VERSION_DIALOG =
+ "DeprecatedTargetSdkVersionDialog";
@After
@Override
@@ -44,49 +48,31 @@
super.tearDown();
// Ensure app process is stopped.
- forceStopPackage("android.server.am.deprecatedsdk");
- forceStopPackage("android.server.am");
+ stopTestPackage(MAIN_ACTIVITY);
}
@Test
public void testCompatibilityDialog() throws Exception {
// Launch target app.
- startActivity("android.server.am.deprecatedsdk", "MainActivity");
- verifyWindowDisplayed("MainActivity", ACTIVITY_TIMEOUT_MILLIS);
- verifyWindowDisplayed("DeprecatedTargetSdkVersionDialog", WINDOW_TIMEOUT_MILLIS);
+ launchActivity(MAIN_ACTIVITY);
+ assertActivityDisplayed(MAIN_ACTIVITY);
+ assertWindowDisplayed(DEPRECATED_TARGET_SDK_VERSION_DIALOG);
// Go back to dismiss the warning dialog.
- executeShellCommand("input keyevent 4");
+ pressBackButton();
// Go back again to formally stop the app. If we just kill the process, it'll attempt to
// resume rather than starting from scratch (as far as ActivityStack is concerned) and it
// won't invoke the warning dialog.
- executeShellCommand("input keyevent 4");
+ pressBackButton();
}
- private void forceStopPackage(String packageName) {
- final String forceStopCmd = String.format(AM_FORCE_STOP, packageName);
- executeShellCommand(forceStopCmd);
+ private void assertActivityDisplayed(final ComponentName activityName) throws Exception {
+ assertWindowDisplayed(getWindowName(activityName));
}
- private void startActivity(String packageName, String activityName){
- executeShellCommand(getStartCommand(packageName, activityName));
- }
-
- private String getStartCommand(String packageName, String activityName) {
- return String.format(AM_START_COMMAND, packageName, packageName, activityName);
- }
-
- private void verifyWindowDisplayed(String windowName, long timeoutMillis) {
- boolean success = false;
-
- // Verify that compatibility dialog is shown within 1000ms.
- final long timeoutTimeMillis = System.currentTimeMillis() + timeoutMillis;
- while (!success && System.currentTimeMillis() < timeoutTimeMillis) {
- final String output = executeShellCommand("dumpsys window");
- success = output.contains(windowName);
- }
-
- assertTrue(windowName + " was not displayed", success);
+ private void assertWindowDisplayed(final String windowName) throws Exception {
+ mAmWmState.waitForValidState(WaitForValidActivityState.forWindow(windowName));
+ assertTrue(windowName + "is visible", mAmWmState.getWmState().isWindowVisible(windowName));
}
}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/DisplaySizeTest.java b/tests/framework/base/activitymanager/src/android/server/am/DisplaySizeTest.java
index ee1dc1e..58c5048 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/DisplaySizeTest.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/DisplaySizeTest.java
@@ -19,6 +19,7 @@
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
import static android.server.am.ComponentNameUtils.getActivityName;
import static android.server.am.ComponentNameUtils.getWindowName;
+import static android.server.am.UiDeviceUtils.pressBackButton;
import static android.server.am.displaysize.Components.SMALLEST_WIDTH_ACTIVITY;
import static org.junit.Assert.assertTrue;
diff --git a/tests/framework/base/activitymanager/src/android/server/am/KeyguardLockedTests.java b/tests/framework/base/activitymanager/src/android/server/am/KeyguardLockedTests.java
index 1eadf59..ecdb6e8 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/KeyguardLockedTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/KeyguardLockedTests.java
@@ -18,12 +18,12 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.server.am.UiDeviceUtils.pressBackButton;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
-import android.app.KeyguardManager;
-
import org.junit.Before;
import org.junit.Test;
@@ -55,7 +55,6 @@
assertTrue(mKeyguardManager.isDeviceLocked());
assertTrue(mKeyguardManager.isDeviceSecure());
assertTrue(mKeyguardManager.isKeyguardSecure());
- mAmWmState.waitForKeyguardShowingAndNotOccluded();
mAmWmState.assertKeyguardShowingAndNotOccluded();
lockScreenSession.unlockDevice()
.enterAndConfirmLockCredential();
@@ -71,7 +70,6 @@
try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
lockScreenSession.setLockCredential()
.gotoKeyguard();
- mAmWmState.waitForKeyguardShowingAndNotOccluded();
mAmWmState.assertKeyguardShowingAndNotOccluded();
launchActivity("DismissKeyguardActivity");
lockScreenSession.enterAndConfirmLockCredential();
@@ -86,7 +84,6 @@
try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
lockScreenSession.setLockCredential()
.gotoKeyguard();
- mAmWmState.waitForKeyguardShowingAndNotOccluded();
mAmWmState.assertKeyguardShowingAndNotOccluded();
launchActivity(SHOW_WHEN_LOCKED_ACTIVITY);
mAmWmState.computeState(new WaitForValidActivityState(SHOW_WHEN_LOCKED_ACTIVITY));
@@ -105,7 +102,6 @@
try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
lockScreenSession.setLockCredential()
.gotoKeyguard();
- mAmWmState.waitForKeyguardShowingAndNotOccluded();
mAmWmState.assertKeyguardShowingAndNotOccluded();
launchActivity(SHOW_WHEN_LOCKED_ACTIVITY);
mAmWmState.computeState(new WaitForValidActivityState(SHOW_WHEN_LOCKED_ACTIVITY));
@@ -161,7 +157,6 @@
try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
lockScreenSession.setLockCredential()
.gotoKeyguard();
- mAmWmState.waitForKeyguardShowingAndNotOccluded();
assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
// Enter PiP on an activity on top of the keyguard, and ensure that it prompts the user
@@ -202,7 +197,6 @@
lockScreenSession.gotoKeyguard();
mAmWmState.computeState(true);
- mAmWmState.waitForKeyguardShowingAndOccluded();
mAmWmState.assertKeyguardShowingAndOccluded();
mAmWmState.assertVisibility(SHOW_WHEN_LOCKED_ACTIVITY, true);
mAmWmState.assertVisibility(PIP_ACTIVITY, false);
@@ -223,7 +217,6 @@
mAmWmState.assertVisibility(PIP_ACTIVITY, true);
lockScreenSession.gotoKeyguard();
- mAmWmState.waitForKeyguardShowingAndNotOccluded();
mAmWmState.assertKeyguardShowingAndNotOccluded();
mAmWmState.assertVisibility(PIP_ACTIVITY, false);
}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java
index 1024bc3..12ac93c 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java
@@ -18,6 +18,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.server.am.UiDeviceUtils.pressHomeButton;
import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
@@ -177,7 +178,7 @@
try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
launchActivitiesInSplitScreen(
- getLaunchActivityBuilder().setTargetActivityName(LAUNCHING_ACTIVITY),
+ getLaunchActivityBuilder().setTargetActivityName(LAUNCHING_ACTIVITY_NAME),
getLaunchActivityBuilder().setTargetActivityName("ShowWhenLockedActivity")
.setRandomData(true)
.setMultipleTask(false)
@@ -292,7 +293,6 @@
try (final LockScreenSession lockScreenSession = new LockScreenSession();
final RotationSession rotationSession = new RotationSession()) {
lockScreenSession.gotoKeyguard();
- mAmWmState.waitForKeyguardShowingAndNotOccluded();
mAmWmState.assertKeyguardShowingAndNotOccluded();
executeShellCommand(getAmStartCmd("ShowWhenLockedActivity"));
mAmWmState.computeState(new WaitForValidActivityState("ShowWhenLockedActivity"));
@@ -358,7 +358,6 @@
try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
final LogSeparator logSeparator = clearLogcat();
lockScreenSession.gotoKeyguard();
- mAmWmState.waitForKeyguardShowingAndNotOccluded();
mAmWmState.assertKeyguardShowingAndNotOccluded();
launchActivity("ShowWhenLockedAttrActivity");
mAmWmState.computeState(new WaitForValidActivityState("ShowWhenLockedAttrActivity"));
diff --git a/tests/framework/base/activitymanager/src/android/server/am/PrereleaseSdkTest.java b/tests/framework/base/activitymanager/src/android/server/am/PrereleaseSdkTest.java
index 54d9b5c..027f805 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/PrereleaseSdkTest.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/PrereleaseSdkTest.java
@@ -16,6 +16,8 @@
package android.server.am;
+import static android.server.am.UiDeviceUtils.pressBackButton;
+
import static org.junit.Assert.assertTrue;
import org.junit.After;
diff --git a/tests/framework/base/activitymanager/src/android/server/am/StartActivityTests.java b/tests/framework/base/activitymanager/src/android/server/am/StartActivityTests.java
index 788267d..bcab43f 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/StartActivityTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/StartActivityTests.java
@@ -16,6 +16,7 @@
package android.server.am;
+import static android.server.am.Components.TEST_ACTIVITY;
import static android.server.am.app27.Components.SDK_27_LAUNCHING_ACTIVITY;
import static org.junit.Assert.assertFalse;
@@ -37,10 +38,6 @@
@Presubmit
@FlakyTest
public class StartActivityTests extends ActivityManagerTestBase {
- private static final String SDK_CURRENT_PACKAGE = "android.server.am";
-
- private static final ComponentName TEST_ACTIVITY = ComponentName.createRelative(
- SDK_CURRENT_PACKAGE, ".TestActivity");
@Rule
public final ActivityTestRule<TestActivity2> mTestActivity2Rule =
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleClientTestBase.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleClientTestBase.java
index a5673a6..421b542 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleClientTestBase.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleClientTestBase.java
@@ -24,6 +24,9 @@
final ActivityTestRule mSecondActivityTestRule = new ActivityTestRule(SecondActivity.class,
true /* initialTouchMode */, false /* launchActivity */);
+ final ActivityTestRule mTranslucentActivityTestRule = new ActivityTestRule(
+ TranslucentActivity.class, true /* initialTouchMode */, false /* launchActivity */);
+
private final ActivityLifecycleMonitor mLifecycleMonitor = ActivityLifecycleMonitorRegistry
.getInstance();
private LifecycleLog mLifecycleLog;
@@ -80,4 +83,8 @@
// Test activity
public static class SecondActivity extends Activity {
}
+
+ // Translucent test activity
+ public static class TranslucentActivity extends Activity {
+ }
}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java
index b785b6b..0ed41bf 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java
@@ -1,8 +1,17 @@
package android.server.am.lifecycle;
+import static android.support.test.runner.lifecycle.Stage.CREATED;
import static android.support.test.runner.lifecycle.Stage.DESTROYED;
+import static android.support.test.runner.lifecycle.Stage.PAUSED;
+import static android.support.test.runner.lifecycle.Stage.PRE_ON_CREATE;
import static android.support.test.runner.lifecycle.Stage.RESUMED;
+import static android.support.test.runner.lifecycle.Stage.STARTED;
import static android.support.test.runner.lifecycle.Stage.STOPPED;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+import static org.junit.Assert.fail;
import android.app.Activity;
import android.content.Intent;
@@ -15,6 +24,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
+
/**
* Build/Install/Run:
* atest CtsActivityManagerDeviceTestCases:ActivityLifecycleTests
@@ -60,7 +71,7 @@
@FlakyTest(bugId = 72956507)
@Test
- public void testRelaunch() throws Exception {
+ public void testRelaunchResumed() throws Exception {
final Activity activity = mFirstActivityTestRule.launchActivity(new Intent());
waitAndAssertActivityStates(state(activity, RESUMED));
@@ -68,6 +79,89 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(activity::recreate);
waitAndAssertActivityStates(state(activity, RESUMED));
- LifecycleVerifier.assertRelaunchSequence(FirstActivity.class, getLifecycleLog());
+ LifecycleVerifier.assertRelaunchSequence(FirstActivity.class, getLifecycleLog(), RESUMED);
+ }
+
+ @FlakyTest(bugId = 72956507)
+ @Test
+ public void testRelaunchPaused() throws Exception {
+ final Activity pausedActivity = mFirstActivityTestRule.launchActivity(new Intent());
+ final Activity topTranslucentActivity =
+ mTranslucentActivityTestRule.launchActivity(new Intent());
+
+ waitAndAssertActivityStates(state(pausedActivity, PAUSED),
+ state(topTranslucentActivity, RESUMED));
+
+ getLifecycleLog().clear();
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(pausedActivity::recreate);
+ waitAndAssertActivityStates(state(pausedActivity, PAUSED));
+
+ LifecycleVerifier.assertRelaunchSequence(FirstActivity.class, getLifecycleLog(), PAUSED);
+ }
+
+ @FlakyTest(bugId = 72956507)
+ @Test
+ public void testRelaunchStopped() throws Exception {
+ final Activity stoppedActivity = mFirstActivityTestRule.launchActivity(new Intent());
+ final Activity topActivity = mSecondActivityTestRule.launchActivity(new Intent());
+
+ waitAndAssertActivityStates(state(stoppedActivity, STOPPED), state(topActivity, RESUMED));
+
+ getLifecycleLog().clear();
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(stoppedActivity::recreate);
+ waitAndAssertActivityStates(state(stoppedActivity, STOPPED));
+
+ LifecycleVerifier.assertRelaunchSequence(FirstActivity.class, getLifecycleLog(), STOPPED);
+ }
+
+ @FlakyTest(bugId = 72956507)
+ @Test
+ public void testRelaunchConfigurationChangedWhileBecomingVisible() throws Exception {
+ final Activity becomingVisibleActivity = mFirstActivityTestRule.launchActivity(new Intent());
+ final Activity translucentActivity =
+ mTranslucentActivityTestRule.launchActivity(new Intent());
+ final Activity topOpaqueActivity = mSecondActivityTestRule.launchActivity(new Intent());
+
+ waitAndAssertActivityStates(state(becomingVisibleActivity, STOPPED),
+ state(translucentActivity, STOPPED), state(topOpaqueActivity, RESUMED));
+
+ getLifecycleLog().clear();
+ try (final RotationSession rotationSession = new RotationSession()) {
+ final int current = rotationSession.get();
+ // Set new rotation to cause a configuration change.
+ switch (current) {
+ case ROTATION_0:
+ case ROTATION_180:
+ rotationSession.set(ROTATION_90);
+ break;
+ case ROTATION_90:
+ case ROTATION_270:
+ rotationSession.set(ROTATION_0);
+ break;
+ default:
+ fail("Unknown rotation:" + current);
+ }
+
+ // Assert that the top activity was relaunched.
+ waitAndAssertActivityStates(state(topOpaqueActivity, RESUMED));
+ LifecycleVerifier.assertRelaunchSequence(
+ SecondActivity.class, getLifecycleLog(), RESUMED);
+
+ // Finish the top activity
+ getLifecycleLog().clear();
+ mSecondActivityTestRule.finishActivity();
+
+ // Assert that the translucent activity and the activity visible behind it were
+ // relaunched.
+ waitAndAssertActivityStates(state(becomingVisibleActivity, PAUSED),
+ state(translucentActivity, RESUMED));
+
+ LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
+ Arrays.asList(DESTROYED, PRE_ON_CREATE, CREATED, STARTED, RESUMED, PAUSED),
+ "becomingVisiblePaused");
+ LifecycleVerifier.assertSequence(TranslucentActivity.class, getLifecycleLog(),
+ Arrays.asList(DESTROYED, PRE_ON_CREATE, CREATED, STARTED, RESUMED),
+ "becomingVisibleResumed");
+ }
}
}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleVerifier.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleVerifier.java
index bbb3ad8..9a966f3 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleVerifier.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/LifecycleVerifier.java
@@ -71,13 +71,27 @@
}
static void assertRelaunchSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog) {
+ LifecycleLog lifecycleLog, Stage startState) {
+ final List<Stage> expectedTransitions;
+ if (startState == PAUSED) {
+ expectedTransitions = Arrays.asList(
+ STOPPED, DESTROYED, PRE_ON_CREATE, CREATED, STARTED, RESUMED, PAUSED);
+ } else if (startState == STOPPED) {
+ expectedTransitions = Arrays.asList(
+ DESTROYED, PRE_ON_CREATE, CREATED, STARTED, RESUMED, PAUSED, STOPPED);
+ } else {
+ expectedTransitions = Arrays.asList(
+ PAUSED, STOPPED, DESTROYED, PRE_ON_CREATE, CREATED, STARTED, RESUMED);
+ }
+ assertSequence(activityClass, lifecycleLog, expectedTransitions, "relaunch");
+ }
+
+ static void assertSequence(Class<? extends Activity> activityClass,
+ LifecycleLog lifecycleLog, List<Stage> expectedTransitions, String transition) {
final List<Stage> observedTransitions = lifecycleLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
- final String errorMessage = errorDuringTransition(activityClass, "relaunch");
+ final String errorMessage = errorDuringTransition(activityClass, transition);
- final List<Stage> expectedTransitions =
- Arrays.asList(PAUSED, STOPPED, DESTROYED, PRE_ON_CREATE, CREATED, STARTED, RESUMED);
assertEquals(errorMessage, expectedTransitions, observedTransitions);
}
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityAndWindowManagersState.java b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityAndWindowManagersState.java
index 0095033..4fd76a3 100644
--- a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityAndWindowManagersState.java
+++ b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityAndWindowManagersState.java
@@ -31,11 +31,14 @@
import static android.server.am.StateLogger.logAlways;
import static android.server.am.StateLogger.logE;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.lessThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -79,14 +82,6 @@
private ActivityManagerState mAmState = new ActivityManagerState();
private WindowManagerState mWmState = new WindowManagerState();
- /** TODO(b/73349193): Use {@link #computeState(ComponentName...)} instead. */
- @Deprecated
- public void computeState(String... simpleActivityNames) throws Exception {
- computeState(true, Arrays.stream(simpleActivityNames)
- .map(WaitForValidActivityState::new)
- .toArray(WaitForValidActivityState[]::new));
- }
-
/**
* Compute AM and WM state of device, check sanity and bounds.
* WM state will include only visible windows, stack and task bounds will be compared.
@@ -146,22 +141,7 @@
waitForValidState(false /* compareTaskAndStackBounds */, waitForActivityVisible);
}
- /**
- * Wait for the activity to appear in proper stack and for valid state in AM and WM.
- * TODO(b/73349193): Use {@link #waitForValidState(WaitForValidActivityState...)} instead.
- *
- * @param simpleActivityName name of activity to wait for.
- * @param stackId id of the stack where provided activity should be found.
- */
- @Deprecated
- void waitForValidState(String simpleActivityName, int stackId) throws Exception {
- waitForValidState(false /* compareTaskAndStackBounds */,
- new WaitForValidActivityState.Builder(simpleActivityName)
- .setStackId(stackId)
- .build());
- }
-
- /** TODO(b/73349193): Use {@link #waitForValidState(WaitForValidActivityState...)} instead. */
+ // TODO(b/73349193): Use {@link #waitForValidState(WaitForValidActivityState...)} instead.
@Deprecated
void waitForValidState(String simpleActivityName, int windowingMode, int activityType)
throws Exception {
@@ -342,7 +322,7 @@
"***Waiting for Activity State: " + activityState);
}
- /** TODO(b/73349193): Use {@link #waitForActivityState(ComponentName, String)} instead. */
+ // TODO(b/73349193): Use {@link #waitForActivityState(ComponentName, String)} instead.
@Deprecated
void waitForActivityState(String activityName, String activityState)
throws Exception {
@@ -588,7 +568,7 @@
}
void assertSanity() throws Exception {
- assertTrue("Must have stacks", mAmState.getStackCount() > 0);
+ assertThat("Must have stacks", mAmState.getStackCount(), greaterThan(0));
if (!mAmState.getKeyguardControllerState().keyguardShowing) {
assertEquals("There should be one and only one resumed activity in the system.",
1, mAmState.getResumedActivitiesCount());
@@ -612,12 +592,6 @@
assertTrue(msg, mWmState.containsStack(windowingMode, activityType));
}
- @Deprecated
- void assertDoesNotContainStack(String msg, int stackId) throws Exception {
- assertFalse(msg, mAmState.containsStack(stackId));
- assertFalse(msg, mWmState.containsStack(stackId));
- }
-
void assertDoesNotContainStack(String msg, int windowingMode, int activityType)
throws Exception {
assertFalse(msg, mAmState.containsStack(windowingMode, activityType));
@@ -687,13 +661,6 @@
assertEquals(msg, getActivityName(activityName), mAmState.getResumedActivity());
}
- /** TODO(b/73349193): Use {@link #assertResumedActivity(String, ComponentName)} instead. */
- @Deprecated
- void assertResumedActivity(String msg, String activityName) throws Exception {
- final String componentName = getActivityComponentName(activityName);
- assertEquals(msg, componentName, mAmState.getResumedActivity());
- }
-
void assertNotResumedActivity(String msg, String activityName) throws Exception {
final String componentName = getActivityComponentName(activityName);
if (mAmState.getResumedActivity().equals(componentName)) {
@@ -715,7 +682,7 @@
assertEquals(msg, windowName, mWmState.getFrontWindow());
}
- /** TODO(b/73349193): Use {@link #assertVisibility(ComponentName, boolean)} instead. */
+ // TODO(b/73349193): Use {@link #assertVisibility(ComponentName, boolean)} instead.
@Deprecated
public void assertVisibility(String activityName, boolean visible) {
final String activityComponentName = getActivityComponentName(activityName);
@@ -732,14 +699,10 @@
final boolean activityVisible = mAmState.isActivityVisible(activityComponentName);
final boolean windowVisible = mWmState.isWindowVisible(windowName);
- if (visible) {
- assertTrue("Activity=" + activityComponentName + " must be visible.", activityVisible);
- assertTrue("Window=" + windowName + " must be visible.", windowVisible);
- } else {
- assertFalse("Activity=" + activityComponentName + " must NOT be visible.",
- activityVisible);
- assertFalse("Window=" + windowName + " must NOT be visible.", windowVisible);
- }
+ assertEquals("Activity=" + activityComponentName + " must" + (visible ? "" : " NOT")
+ + " be visible.", visible, activityVisible);
+ assertEquals("Window=" + windowName + " must" + (visible ? "" : " NOT") + " be visible.",
+ visible, windowVisible);
}
void assertHomeActivityVisible(boolean visible) {
@@ -843,7 +806,7 @@
/**
* Check task bounds when docked to top/left.
*/
- void assertDockedTaskBounds(int taskWidth, int taskHeight, String activityName) {
+ void assertDockedTaskBounds(int taskWidth, int taskHeight, ComponentName activityName) {
// Task size can be affected by default minimal size.
int defaultMinimalTaskSize = defaultMinimalTaskSize(
mAmState.getStandardStackByWindowingMode(
@@ -852,7 +815,7 @@
int targetHeight = Math.max(taskHeight, defaultMinimalTaskSize);
assertEquals(new Rect(0, 0, targetWidth, targetHeight),
- mAmState.getTaskByActivityName(activityName).getBounds());
+ mAmState.getTaskByActivity(activityName).getBounds());
}
void assertValidBounds(boolean compareTaskAndStackBounds) {
@@ -958,16 +921,16 @@
assertEquals("Task width must be equal to stack width taskId="
+ taskId + ", stackId=" + stackId,
aStackBounds.width(), wTaskBounds.width());
- assertTrue("Task height must be greater than stack height "
+ assertThat("Task height must be greater than stack height "
+ "taskId=" + taskId + ", stackId=" + stackId,
- aStackBounds.height() < wTaskBounds.height());
+ aStackBounds.height(), lessThan(wTaskBounds.height()));
assertEquals("Task and stack x position must be equal taskId="
+ taskId + ", stackId=" + stackId,
wTaskBounds.left, wStackBounds.left);
} else {
- assertTrue("Task width must be greater than stack width taskId="
+ assertThat("Task width must be greater than stack width taskId="
+ taskId + ", stackId=" + stackId,
- aStackBounds.width() < wTaskBounds.width());
+ aStackBounds.width(), lessThan(wTaskBounds.width()));
assertEquals("Task height must be equal to stack height taskId="
+ taskId + ", stackId=" + stackId,
aStackBounds.height(), wTaskBounds.height());
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityLauncher.java b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityLauncher.java
new file mode 100644
index 0000000..1be32de
--- /dev/null
+++ b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityLauncher.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.server.am;
+
+import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT;
+
+import android.app.ActivityOptions;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+
+/** Utility class which contains common code for launching activities. */
+public class ActivityLauncher {
+ private static final String TAG = ActivityLauncher.class.getSimpleName();
+
+ /** Key for boolean extra, indicates whether it should launch an activity. */
+ public static final String KEY_LAUNCH_ACTIVITY = "launch_activity";
+ /**
+ * Key for boolean extra, indicates whether it the activity should be launched to side in
+ * split-screen.
+ */
+ public static final String KEY_LAUNCH_TO_SIDE = "launch_to_the_side";
+ /**
+ * Key for boolean extra, indicates if launch intent should include random data to be different
+ * from other launch intents.
+ */
+ public static final String KEY_RANDOM_DATA = "random_data";
+ /**
+ * Key for boolean extra, indicates if launch intent should have
+ * {@link Intent#FLAG_ACTIVITY_NEW_TASK}.
+ */
+ public static final String KEY_NEW_TASK = "new_task";
+ /**
+ * Key for boolean extra, indicates if launch intent should have
+ * {@link Intent#FLAG_ACTIVITY_MULTIPLE_TASK}.
+ */
+ public static final String KEY_MULTIPLE_TASK = "multiple_task";
+ /**
+ * Key for boolean extra, indicates if launch intent should have
+ * {@link Intent#FLAG_ACTIVITY_REORDER_TO_FRONT}.
+ */
+ public static final String KEY_REORDER_TO_FRONT = "reorder_to_front";
+ /**
+ * Key for string extra with string representation of target component.
+ */
+ public static final String KEY_TARGET_COMPONENT = "target_component";
+ /**
+ * Key for string extra with target activity name.
+ */
+ public static final String KEY_TARGET_ACTIVITY = "target_activity";
+ /**
+ * Key for string extra with target package name. If {@link #KEY_TARGET_ACTIVITY} is provided
+ * and this extra is not, then current application's package name will be used.
+ */
+ public static final String KEY_TARGET_PACKAGE = "target_package";
+ /**
+ * Key for int extra with target display id where the activity should be launched. Adding this
+ * automatically applies {@link Intent#FLAG_ACTIVITY_NEW_TASK} and
+ * {@link Intent#FLAG_ACTIVITY_MULTIPLE_TASK} to the intent.
+ */
+ public static final String KEY_DISPLAY_ID = "display_id";
+ /**
+ * Key for boolean extra, indicates if launch should be done from application context of the one
+ * passed in {@link #launchActivityFromExtras(Context, Bundle)}.
+ */
+ public static final String KEY_USE_APPLICATION_CONTEXT = "use_application_context";
+ /**
+ * Key for boolean extra, indicates if instrumentation context will be used for launch. This
+ * means that {@link PendingIntent} should be used instead of a regular one, because application
+ * switch will not be allowed otherwise.
+ */
+ public static final String KEY_USE_INSTRUMENTATION = "use_instrumentation";
+ /**
+ * Key for boolean extra, indicates if any exceptions thrown during launch other then
+ * {@link SecurityException} should be suppressed. A {@link SecurityException} is never thrown,
+ * it's always written to logs.
+ */
+ public static final String KEY_SUPPRESS_EXCEPTIONS = "suppress_exceptions";
+
+
+ /** Perform an activity launch configured by provided extras. */
+ public static void launchActivityFromExtras(final Context context, Bundle extras) {
+ if (extras == null || !extras.getBoolean(KEY_LAUNCH_ACTIVITY)) {
+ return;
+ }
+
+ Log.i(TAG, "launchActivityFromExtras: extras=" + extras);
+
+ final Intent newIntent = new Intent();
+ final String targetComponent = extras.getString(KEY_TARGET_COMPONENT);
+ final String targetActivity = extras.getString(KEY_TARGET_ACTIVITY);
+ if (!TextUtils.isEmpty(targetComponent)) {
+ newIntent.setComponent(ComponentName.unflattenFromString(targetComponent));
+ } else if (targetActivity != null) {
+ final String extraPackageName = extras.getString(KEY_TARGET_PACKAGE);
+ final String packageName = extraPackageName != null ? extraPackageName
+ : context.getApplicationContext().getPackageName();
+ newIntent.setComponent(new ComponentName(packageName,
+ packageName + "." + targetActivity));
+ } else {
+ newIntent.setComponent(new ComponentName("android.server.am",
+ "android.server.am.TestActivity"));
+ }
+
+ if (extras.getBoolean(KEY_LAUNCH_TO_SIDE)) {
+ newIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_LAUNCH_ADJACENT);
+ if (extras.getBoolean(KEY_RANDOM_DATA)) {
+ final Uri data = new Uri.Builder()
+ .path(String.valueOf(System.currentTimeMillis()))
+ .build();
+ newIntent.setData(data);
+ }
+ }
+ if (extras.getBoolean(KEY_MULTIPLE_TASK)) {
+ newIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
+ if (extras.getBoolean(KEY_NEW_TASK)) {
+ newIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
+ }
+
+ if (extras.getBoolean(KEY_REORDER_TO_FRONT)) {
+ newIntent.addFlags(FLAG_ACTIVITY_REORDER_TO_FRONT);
+ }
+
+ ActivityOptions options = null;
+ final int displayId = extras.getInt(KEY_DISPLAY_ID, -1);
+ if (displayId != -1) {
+ options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(displayId);
+ newIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
+ final Bundle optionsBundle = options != null ? options.toBundle() : null;
+
+ final Context launchContext = extras.getBoolean(KEY_USE_APPLICATION_CONTEXT) ?
+ context.getApplicationContext() : context;
+
+ try {
+ if (extras.getBoolean(KEY_USE_INSTRUMENTATION)) {
+ // Using PendingIntent for Instrumentation launches, because otherwise we won't
+ // be allowed to switch the current activity with ours with different uid.
+ // android.permission.STOP_APP_SWITCHES is needed to do this directly.
+ final PendingIntent pendingIntent = PendingIntent.getActivity(launchContext, 0,
+ newIntent, 0, optionsBundle);
+ pendingIntent.send();
+ } else {
+ launchContext.startActivity(newIntent, optionsBundle);
+ }
+ } catch (SecurityException e) {
+ Log.e(TAG, "SecurityException launching activity");
+ } catch (PendingIntent.CanceledException e) {
+ if (extras.getBoolean(KEY_SUPPRESS_EXCEPTIONS)) {
+ Log.e(TAG, "Exception launching activity with pending intent");
+ } else {
+ throw new RuntimeException(e);
+ }
+ Log.e(TAG, "SecurityException launching activity");
+ } catch (Exception e) {
+ if (extras.getBoolean(KEY_SUPPRESS_EXCEPTIONS)) {
+ Log.e(TAG, "Exception launching activity");
+ } else {
+ throw e;
+ }
+ }
+ }
+}
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerState.java b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerState.java
index 4ff510b..345365f 100644
--- a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerState.java
+++ b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerState.java
@@ -300,8 +300,8 @@
}
/** Get the stack position on its display. */
- int getStackIndexByActivityName(String activityName) {
- final String fullName = getActivityComponentName(activityName);
+ int getStackIndexByActivity(ComponentName activityName) {
+ final String fullName = getActivityName(activityName);
for (ActivityDisplay display : mDisplays) {
for (int i = display.mStacks.size() - 1; i >= 0; --i) {
@@ -498,10 +498,8 @@
getActivityComponentName(activityName), WINDOWING_MODE_UNDEFINED);
}
- /** TODO(b/73349193): Add getTaskByActicityOfWidowingMode(Component, int). */
- @Deprecated
- ActivityTask getTaskByActivityName(String activityName, int windowingMode) {
- return getTaskByActivityInternal(getActivityComponentName(activityName), windowingMode);
+ ActivityTask getTaskByActivity(ComponentName activityName, int windowingMode) {
+ return getTaskByActivityInternal(getActivityName(activityName), windowingMode);
}
private ActivityTask getTaskByActivityInternal(String fullName, int windowingMode) {
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
index 4813ac6..4e39e2a 100644
--- a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
+++ b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
@@ -33,6 +33,20 @@
import static android.content.pm.PackageManager.FEATURE_SCREEN_PORTRAIT;
import static android.content.pm.PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE;
import static android.content.pm.PackageManager.FEATURE_WATCH;
+import static android.server.am.ActivityLauncher.KEY_DISPLAY_ID;
+import static android.server.am.ActivityLauncher.KEY_LAUNCH_ACTIVITY;
+import static android.server.am.ActivityLauncher.KEY_LAUNCH_TO_SIDE;
+import static android.server.am.ActivityLauncher.KEY_MULTIPLE_TASK;
+import static android.server.am.ActivityLauncher.KEY_NEW_TASK;
+import static android.server.am.ActivityLauncher.KEY_RANDOM_DATA;
+import static android.server.am.ActivityLauncher.KEY_REORDER_TO_FRONT;
+import static android.server.am.ActivityLauncher.KEY_SUPPRESS_EXCEPTIONS;
+import static android.server.am.ActivityLauncher.KEY_TARGET_ACTIVITY;
+import static android.server.am.ActivityLauncher.KEY_TARGET_COMPONENT;
+import static android.server.am.ActivityLauncher.KEY_TARGET_PACKAGE;
+import static android.server.am.ActivityLauncher.KEY_USE_APPLICATION_CONTEXT;
+import static android.server.am.ActivityLauncher.KEY_USE_INSTRUMENTATION;
+import static android.server.am.ActivityLauncher.launchActivityFromExtras;
import static android.server.am.ComponentNameUtils.getActivityName;
import static android.server.am.ComponentNameUtils.getLogTag;
import static android.server.am.ComponentNameUtils.getSimpleClassName;
@@ -40,10 +54,14 @@
import static android.server.am.StateLogger.log;
import static android.server.am.StateLogger.logAlways;
import static android.server.am.StateLogger.logE;
-import static android.view.KeyEvent.KEYCODE_APP_SWITCH;
-import static android.view.KeyEvent.KEYCODE_MENU;
-import static android.view.KeyEvent.KEYCODE_SLEEP;
-import static android.view.KeyEvent.KEYCODE_WAKEUP;
+import static android.server.am.UiDeviceUtils.pressAppSwitchButton;
+import static android.server.am.UiDeviceUtils.pressBackButton;
+import static android.server.am.UiDeviceUtils.pressEnterButton;
+import static android.server.am.UiDeviceUtils.pressHomeButton;
+import static android.server.am.UiDeviceUtils.pressSleepButton;
+import static android.server.am.UiDeviceUtils.pressUnlockButton;
+import static android.server.am.UiDeviceUtils.pressWakeupButton;
+import static android.server.am.UiDeviceUtils.waitForDeviceIdle;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -51,18 +69,17 @@
import static java.lang.Integer.toHexString;
import android.app.ActivityManager;
-import android.app.KeyguardManager;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Bitmap;
+import android.os.Bundle;
import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
+import android.os.SystemClock;
import android.provider.Settings;
import android.server.am.settings.SettingsSession;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.test.InstrumentationRegistry;
-import android.support.test.uiautomator.UiDevice;
import android.view.Display;
import com.android.compatibility.common.util.SystemUtil;
@@ -82,7 +99,6 @@
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
-import java.util.function.BooleanSupplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -114,9 +130,8 @@
private static final String AM_MOVE_TOP_ACTIVITY_TO_PINNED_STACK_COMMAND_FORMAT =
"am stack move-top-activity-to-pinned-stack %1d 0 0 500 500";
- static final String LAUNCHING_ACTIVITY = "LaunchingActivity";
- static final String ALT_LAUNCHING_ACTIVITY = "AltLaunchingActivity";
- static final String BROADCAST_RECEIVER_ACTIVITY = "BroadcastReceiverActivity";
+ // TODO(b/73349193): Remove this.
+ static final String LAUNCHING_ACTIVITY_NAME = "LaunchingActivity";
/** Broadcast shell command for finishing {@link BroadcastReceiverActivity}. */
static final String FINISH_ACTIVITY_BROADCAST
@@ -151,9 +166,8 @@
protected Context mContext;
protected ActivityManager mAm;
- protected UiDevice mDevice;
- /** TODO(b/73349193): Use {@link #getAmStartCmd(ComponentName, String...)} instead. */
+ // TODO(b/73349193): Use {@link #getAmStartCmd(ComponentName, String...)} instead.
@Deprecated
protected static String getAmStartCmd(final String activityName) {
return "am start -n " + getActivityComponentName(activityName);
@@ -169,7 +183,7 @@
return getAmStartCmdInternal(getActivityName(activityName), keyValuePairs);
}
- /** TODO(b/73349193): Use {@link #getAmStartCmd(ComponentName, String...)} instead. */
+ // TODO(b/73349193): Use {@link #getAmStartCmd(ComponentName, String...)} instead.
@Deprecated
protected static String getAmStartCmd(final String activityName,
final String... keyValuePairs) {
@@ -204,7 +218,7 @@
return getAmStartCmdInternal(getActivityName(activityName), displayId, keyValuePair);
}
- /** TODO(b/73349193): Use {@link #getAmStartCmd(ComponentName, String...)} instead. */
+ // TODO(b/73349193): Use {@link #getAmStartCmd(ComponentName, String...)} instead.
@Deprecated
protected static String getAmStartCmd(final String activityName, final int displayId,
final String... keyValuePair) {
@@ -224,6 +238,12 @@
keyValuePairs);
}
+ protected static String getAmStartCmdInNewTask(final ComponentName activityName) {
+ return "am start -n " + getActivityName(activityName) + " -f 0x18000000";
+ }
+
+ /** TODO(b/73349193): Use {@link #getAmStartCmdInNewTask(ComponentName)} instead. */
+ @Deprecated
protected static String getAmStartCmdInNewTask(final String activityName) {
return "am start -n " + getActivityComponentName(activityName) + " -f 0x18000000";
}
@@ -308,7 +328,6 @@
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getContext();
mAm = mContext.getSystemService(ActivityManager.class);
- mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
setDefaultComponentName();
executeShellCommand("pm grant " + mContext.getPackageName()
+ " android.permission.MANAGE_ACTIVITY_STACKS");
@@ -369,23 +388,13 @@
return InstrumentationRegistry.getInstrumentation().getUiAutomation().takeScreenshot();
}
- /** TODO(b/73349193): Remove this method. */
- @Deprecated
- protected void launchActivityInComponent(final String componentName,
- final String targetActivityName, final String... keyValuePairs) throws Exception {
- final String originalComponentName = ActivityManagerTestBase.componentName;
- setComponentName(componentName);
- launchActivity(targetActivityName, keyValuePairs);
- setComponentName(originalComponentName);
- }
-
protected void launchActivity(final ComponentName activityName, final String... keyValuePairs)
throws Exception {
executeShellCommand(getAmStartCmd(activityName, keyValuePairs));
mAmWmState.waitForValidState(new WaitForValidActivityState(activityName));
}
- /** TODO(b/73349193): Use {@link #launchActivity(ComponentName, String...)} instead. */
+ // TODO(b/73349193): Use {@link #launchActivity(ComponentName, String...)} instead.
@Deprecated
protected void launchActivity(final String targetActivityName, final String... keyValuePairs)
throws Exception {
@@ -398,17 +407,9 @@
executeShellCommand(getAmStartCmd(targetActivityName, keyValuePairs));
}
- /** TODO(b/73349193): Use {@link #launchActivity(ComponentName, String...)} instead. */
- @Deprecated
- protected void launchActivityNoWait(final String targetActivityName,
- final String... keyValuePairs) throws Exception {
- executeShellCommand(getAmStartCmd(targetActivityName, keyValuePairs));
- }
-
- @Deprecated
- protected void launchActivityInNewTask(final String targetActivityName) throws Exception {
- executeShellCommand(getAmStartCmdInNewTask(targetActivityName));
- mAmWmState.waitForValidState(targetActivityName);
+ protected void launchActivityInNewTask(final ComponentName activityName) throws Exception {
+ executeShellCommand(getAmStartCmdInNewTask(activityName));
+ mAmWmState.waitForValidState(activityName);
}
/**
@@ -460,7 +461,7 @@
.build());
}
- /** TODO(b/73349193): Use {@link #launchActivity(ComponentName, int, String...)} instead. */
+ // TODO(b/73349193): Use {@link #launchActivity(ComponentName, int, String...)} instead.
@Deprecated
protected void launchActivity(String activityName, int windowingMode,
final String... keyValuePairs) throws Exception {
@@ -478,7 +479,7 @@
mAmWmState.waitForValidState(new WaitForValidActivityState(targetActivityName));
}
- /** TODO(b/73349193): Use {@link #launchActivityOnDisplay(ComponentName, int, String...)} */
+ // TODO(b/73349193): Use {@link #launchActivityOnDisplay(ComponentName, int, String...)}
@Deprecated
protected void launchActivityOnDisplay(String targetActivityName, int displayId,
String... keyValuePairs) throws Exception {
@@ -491,51 +492,37 @@
* Launches {@param activityName} into split-screen primary windowing mode and also makes
* the recents activity visible to the side of it.
*/
- protected void launchActivityInSplitScreenWithRecents(String activityName) throws Exception {
+ protected void launchActivityInSplitScreenWithRecents(
+ ComponentName activityName) throws Exception {
launchActivityInSplitScreenWithRecents(activityName, SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT);
}
- protected void launchActivityInSplitScreenWithRecents(String activityName, int createMode)
- throws Exception {
+ protected void launchActivityInSplitScreenWithRecents(
+ ComponentName activityName, int createMode) throws Exception {
launchActivity(activityName);
- final int taskId = mAmWmState.getAmState().getTaskByActivityName(activityName).mTaskId;
+ final int taskId = mAmWmState.getAmState().getTaskByActivity(activityName).mTaskId;
mAm.setTaskWindowingModeSplitScreenPrimary(taskId, createMode, true /* onTop */,
false /* animate */, null /* initialBounds */, true /* showRecents */);
- mAmWmState.waitForValidState(activityName,
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD);
+ mAmWmState.waitForValidState(
+ new WaitForValidActivityState.Builder(activityName)
+ .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
+ .setActivityType(ACTIVITY_TYPE_STANDARD)
+ .build());
mAmWmState.waitForRecentsActivityVisible();
}
/**
- * TODO(b/73349193): Use
- * {@link #launchActivitiesInSplitScreen(LaunchActivityBuilder, LaunchActivityBuilder)
- */
- @Deprecated
- protected void launchActivitiesInSplitScreen(String primaryActivity, String secondaryActivity)
- throws Exception {
- launchActivitiesInSplitScreen(
- getLaunchActivityBuilder().setTargetActivityName(primaryActivity),
- getLaunchActivityBuilder().setTargetActivityName(secondaryActivity));
- }
-
- /**
* Launches {@param primaryActivity} into split-screen primary windowing mode
* and {@param secondaryActivity} to the side in split-screen secondary windowing mode.
*/
protected void launchActivitiesInSplitScreen(LaunchActivityBuilder primaryActivity,
LaunchActivityBuilder secondaryActivity) throws Exception {
// Launch split-screen primary.
- String tmpLaunchingActivityName = primaryActivity.mLaunchingActivityName;
primaryActivity
- // TODO(b/70618153): Work around issues with the activity launch builder where
- // launching activity doesn't work. We don't really need launching activity in this
- // case and should probably change activity launcher to work without a launching
- // activity.
- .setLaunchingActivityName(primaryActivity.mTargetActivityName)
+ .setUseInstrumentation()
.setWaitForLaunched(true)
.execute();
- primaryActivity.setLaunchingActivityName(tmpLaunchingActivityName);
final int taskId = mAmWmState.getAmState().getTaskByActivityName(
primaryActivity.mTargetActivityName).mTaskId;
@@ -545,17 +532,13 @@
mAmWmState.waitForRecentsActivityVisible();
// Launch split-screen secondary
- tmpLaunchingActivityName = secondaryActivity.mLaunchingActivityName;
+ // Recents become focused, so we can just launch new task in focused stack
secondaryActivity
- // TODO(b/70618153): Work around issues with the activity launch builder where
- // launching activity doesn't work. We don't really need launching activity in this
- // case and should probably change activity launcher to work without a launching
- // activity.
- .setLaunchingActivityName(secondaryActivity.mTargetActivityName)
+ .setUseInstrumentation()
.setWaitForLaunched(true)
- .setToSide(true)
+ .setNewTask(true)
+ .setMultipleTask(true)
.execute();
- secondaryActivity.setLaunchingActivityName(tmpLaunchingActivityName);
}
protected void setActivityTaskWindowingMode(final ComponentName activityName,
@@ -568,7 +551,7 @@
.build());
}
- /** TODO(b/73349193): Use {@link #setActivityTaskWindowingMode(ComponentName, int)} instead. */
+ // TODO(b/73349193): Use {@link #setActivityTaskWindowingMode(ComponentName, int)} instead.
@Deprecated
protected void setActivityTaskWindowingMode(String activityName, int windowingMode)
throws Exception {
@@ -577,17 +560,24 @@
mAmWmState.waitForValidState(activityName, windowingMode, ACTIVITY_TYPE_STANDARD);
}
- protected void moveActivityToStack(String activityName, int stackId) throws Exception {
+ protected void moveActivityToStack(ComponentName activityName, int stackId) throws Exception {
final int taskId = getActivityTaskId(activityName);
final String cmd = AM_MOVE_TASK + taskId + " " + stackId + " true";
executeShellCommand(cmd);
- mAmWmState.waitForValidState(activityName, stackId);
+ mAmWmState.waitForValidState(new WaitForValidActivityState.Builder(activityName)
+ .setStackId(stackId)
+ .build());
}
- protected void resizeActivityTask(String activityName, int left, int top, int right, int bottom)
+ protected void resizeActivityTask(
+ ComponentName activityName, int left, int top, int right, int bottom)
throws Exception {
- final int taskId = getActivityTaskId(activityName);
+ resizeActivityTask(getActivityTaskId(activityName), left, top, right, bottom);
+ }
+
+ private void resizeActivityTask(int taskId, int left, int top, int right, int bottom)
+ throws Exception {
final String cmd = "am task resize "
+ taskId + " " + left + " " + top + " " + right + " " + bottom;
executeShellCommand(cmd);
@@ -606,57 +596,12 @@
stackTop, stackWidth, stackHeight));
}
- protected void pressHomeButton() {
- mDevice.pressHome();
- }
-
- protected void pressBackButton() {
- mDevice.pressBack();
- }
-
- protected void pressAppSwitchButton() throws Exception {
- mDevice.pressKeyCode(KEYCODE_APP_SWITCH);
+ protected void pressAppSwitchButtonAndWaitForRecents() throws Exception {
+ pressAppSwitchButton();
mAmWmState.waitForRecentsActivityVisible();
mAmWmState.waitForAppTransitionIdle();
}
- protected void pressWakeupButton() {
- final PowerManager pm = mContext.getSystemService(PowerManager.class);
- retryPressKeyCode(KEYCODE_WAKEUP, () -> pm != null && pm.isInteractive(),
- "***Waiting for device wakeup...");
- }
-
- protected void pressUnlockButton() {
- final KeyguardManager kgm = mContext.getSystemService(KeyguardManager.class);
- retryPressKeyCode(KEYCODE_MENU, () -> kgm != null && !kgm.isKeyguardLocked(),
- "***Waiting for device unlock...");
- }
-
- protected void pressSleepButton() {
- final PowerManager pm = mContext.getSystemService(PowerManager.class);
- retryPressKeyCode(KEYCODE_SLEEP, () -> pm != null && !pm.isInteractive(),
- "***Waiting for device sleep...");
- }
-
- private void retryPressKeyCode(int keyCode, BooleanSupplier waitFor, String msg) {
- int retry = 1;
- do {
- mDevice.pressKeyCode(keyCode);
- if (waitFor.getAsBoolean()) {
- return;
- }
- logAlways(msg + " retry=" + retry);
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- logE("Sleep interrupted: " + msg, e);
- }
- } while (retry++ < 5);
- if (!waitFor.getAsBoolean()) {
- logE(msg + " FAILED");
- }
- }
-
// Utility method for debugging, not used directly here, but useful, so kept around.
protected void printStacksAndTasks() {
String output = executeShellCommand(AM_STACK_LIST);
@@ -670,7 +615,7 @@
return getWindowTaskId(getWindowName(activityName));
}
- /** TODO(b/73349193): Use {@link #getActivityTaskId(ComponentName)} instead. */
+ // TODO(b/73349193): Use {@link #getActivityTaskId(ComponentName)} instead.
@Deprecated
protected int getActivityTaskId(final String activityName) {
return getWindowTaskId(getActivityWindowName(activityName));
@@ -848,10 +793,10 @@
}
public LockScreenSession enterAndConfirmLockCredential() throws Exception {
- mDevice.waitForIdle(3000);
+ waitForDeviceIdle(3000);
runCommandAndPrintOutput("input text " + LOCK_CREDENTIAL);
- mDevice.pressEnter();
+ pressEnterButton();
return this;
}
@@ -869,12 +814,7 @@
pressSleepButton();
for (int retry = 1; isDisplayOn() && retry <= 5; retry++) {
logAlways("***Waiting for display to turn off... retry=" + retry);
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- logAlways(e.toString());
- // Well I guess we are not waiting...
- }
+ SystemClock.sleep(TimeUnit.SECONDS.toMillis(1));
}
return this;
}
@@ -939,7 +879,7 @@
protected class RotationSession extends SettingsSession<Integer> {
private final SettingsSession<Integer> mUserRotation;
- RotationSession() throws Exception {
+ public RotationSession() throws Exception {
// Save accelerometer_rotation preference.
super(Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION),
Settings.System::getInt, Settings.System::putInt);
@@ -1066,11 +1006,7 @@
return;
}
logAlways(waitingMessage + ": " + resultString);
- try {
- Thread.sleep(RETRY_INTERVAL);
- } catch (InterruptedException e) {
- logE(waitingMessage + ": interrupted", e);
- }
+ SystemClock.sleep(RETRY_INTERVAL);
}
fail(resultString);
}
@@ -1122,36 +1058,37 @@
}
}
- void assertActivityLifecycle(
- String activityName, boolean relaunched, LogSeparator logSeparator) {
+ void assertActivityLifecycle(ComponentName activityName, boolean relaunched,
+ LogSeparator logSeparator) {
+ final String logTag = getLogTag(activityName);
new RetryValidator() {
@Nullable
@Override
protected String validate() {
final ActivityLifecycleCounts lifecycleCounts =
- new ActivityLifecycleCounts(activityName, logSeparator);
+ new ActivityLifecycleCounts(logTag, logSeparator);
if (relaunched) {
if (lifecycleCounts.mDestroyCount < 1) {
- return activityName + " must have been destroyed. mDestroyCount="
+ return logTag + " must have been destroyed. mDestroyCount="
+ lifecycleCounts.mDestroyCount;
}
if (lifecycleCounts.mCreateCount < 1) {
- return activityName + " must have been (re)created. mCreateCount="
+ return logTag + " must have been (re)created. mCreateCount="
+ lifecycleCounts.mCreateCount;
}
return null;
}
if (lifecycleCounts.mDestroyCount > 0) {
- return activityName + " must *NOT* have been destroyed. mDestroyCount="
+ return logTag + " must *NOT* have been destroyed. mDestroyCount="
+ lifecycleCounts.mDestroyCount;
}
if (lifecycleCounts.mCreateCount > 0) {
- return activityName + " must *NOT* have been (re)created. mCreateCount="
+ return logTag + " must *NOT* have been (re)created. mCreateCount="
+ lifecycleCounts.mCreateCount;
}
if (lifecycleCounts.mConfigurationChangedCount < 1) {
- return activityName + " must have received configuration changed. "
+ return logTag + " must have received configuration changed. "
+ "mConfigurationChangedCount="
+ lifecycleCounts.mConfigurationChangedCount;
}
@@ -1160,23 +1097,24 @@
}.assertValidator("***Waiting for valid lifecycle state");
}
- protected void assertRelaunchOrConfigChanged(String activityName, int numRelaunch,
+ protected void assertRelaunchOrConfigChanged(ComponentName activityName, int numRelaunch,
int numConfigChange, LogSeparator logSeparator) {
+ final String logTag = getLogTag(activityName);
new RetryValidator() {
@Nullable
@Override
protected String validate() {
final ActivityLifecycleCounts lifecycleCounts =
- new ActivityLifecycleCounts(activityName, logSeparator);
+ new ActivityLifecycleCounts(logTag, logSeparator);
if (lifecycleCounts.mDestroyCount != numRelaunch) {
- return activityName + " has been destroyed " + lifecycleCounts.mDestroyCount
+ return logTag + " has been destroyed " + lifecycleCounts.mDestroyCount
+ " time(s), expecting " + numRelaunch;
} else if (lifecycleCounts.mCreateCount != numRelaunch) {
- return activityName + " has been (re)created " + lifecycleCounts.mCreateCount
+ return logTag + " has been (re)created " + lifecycleCounts.mCreateCount
+ " time(s), expecting " + numRelaunch;
} else if (lifecycleCounts.mConfigurationChangedCount != numConfigChange) {
- return activityName + " has received "
+ return logTag + " has received "
+ lifecycleCounts.mConfigurationChangedCount
+ " onConfigurationChanged() calls, expecting " + numConfigChange;
}
@@ -1185,7 +1123,7 @@
}.assertValidator("***Waiting for relaunch or config changed");
}
- protected void assertActivityDestroyed(String activityName, LogSeparator logSeparator) {
+ protected void assertActivityDestroyed(ComponentName activityName, LogSeparator logSeparator) {
new RetryValidator() {
@Nullable
@@ -1195,13 +1133,16 @@
new ActivityLifecycleCounts(activityName, logSeparator);
if (lifecycleCounts.mDestroyCount != 1) {
- return activityName + " has been destroyed " + lifecycleCounts.mDestroyCount
+ return getActivityName(activityName) + " has been destroyed "
+ + lifecycleCounts.mDestroyCount
+ " time(s), expecting single destruction.";
- } else if (lifecycleCounts.mCreateCount != 0) {
- return activityName + " has been (re)created " + lifecycleCounts.mCreateCount
- + " time(s), not expecting any.";
- } else if (lifecycleCounts.mConfigurationChangedCount != 0) {
- return activityName + " has received "
+ }
+ if (lifecycleCounts.mCreateCount != 0) {
+ return getActivityName(activityName) + " has been (re)created "
+ + lifecycleCounts.mCreateCount + " time(s), not expecting any.";
+ }
+ if (lifecycleCounts.mConfigurationChangedCount != 0) {
+ return getActivityName(activityName) + " has received "
+ lifecycleCounts.mConfigurationChangedCount
+ " onConfigurationChanged() calls, not expecting any.";
}
@@ -1214,7 +1155,7 @@
assertSingleLaunch(getLogTag(activityName), logSeparator);
}
- /** TODO(b/73349193): Use {@link #assertSingleLaunch(ComponentName, LogSeparator)} instead. */
+ // TODO(b/73349193): Use {@link #assertSingleLaunch(ComponentName, LogSeparator)} instead.
@Deprecated
void assertSingleLaunch(String logTag, LogSeparator logSeparator) {
new ActivityLifecycleCountsValidator(logTag, logSeparator, 1 /* createCount */,
@@ -1224,10 +1165,10 @@
}
void assertSingleLaunchAndStop(ComponentName activityName, LogSeparator logSeparator) {
- assertSingleStartAndStop(getLogTag(activityName), logSeparator);
+ assertSingleLaunchAndStop(getLogTag(activityName), logSeparator);
}
- /** TODO(b/73349193): Use {@link #assertSingleLaunchAndStop(ComponentName, LogSeparator)}. */
+ // TODO(b/73349193): Use {@link #assertSingleLaunchAndStop(ComponentName, LogSeparator)}.
@Deprecated
void assertSingleLaunchAndStop(String logTag, LogSeparator logSeparator) {
new ActivityLifecycleCountsValidator(logTag, logSeparator, 1 /* createCount */,
@@ -1240,7 +1181,7 @@
assertSingleStartAndStop(getLogTag(activityName), logSeparator);
}
- /** TODO(b/73349193): Use {@link #assertSingleStartAndStop(ComponentName, LogSeparator)}. */
+ // TODO(b/73349193): Use {@link #assertSingleStartAndStop(ComponentName, LogSeparator)}.
@Deprecated
void assertSingleStartAndStop(String logTag, LogSeparator logSeparator) {
new ActivityLifecycleCountsValidator(logTag, logSeparator, 0 /* createCount */,
@@ -1250,15 +1191,9 @@
}
void assertSingleStart(ComponentName activityName, LogSeparator logSeparator) {
- assertSingleStart(getLogTag(activityName), logSeparator);
- }
-
- /** TODO(b/73349193): Use {@link #assertSingleStart(ComponentName, LogSeparator)} instead. */
- @Deprecated
- void assertSingleStart(String logTag, LogSeparator logSeparator) {
- new ActivityLifecycleCountsValidator(logTag, logSeparator, 0 /* createCount */,
- 1 /* startCount */, 1 /* resumeCount */, 0 /* pauseCount */, 0 /* stopCount */,
- 0 /* destroyCount */)
+ new ActivityLifecycleCountsValidator(getLogTag(activityName), logSeparator,
+ 0 /* createCount */, 1 /* startCount */, 1 /* resumeCount */, 0 /* pauseCount */,
+ 0 /* stopCount */, 0 /* destroyCount */)
.assertValidator("***Waiting for activity start and resume");
}
@@ -1326,28 +1261,30 @@
}
}
- ReportedSizes getLastReportedSizesForActivity(String activityName, LogSeparator logSeparator) {
- int retriesLeft = 5;
- ReportedSizes result;
- do {
- result = readLastReportedSizes(activityName, logSeparator);
- if (result == null) {
- log("***Waiting for sizes to be reported...");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- log(e.toString());
- // Well I guess we are not waiting...
- }
- } else {
- break;
- }
- } while (retriesLeft-- > 0);
- return result;
+ @Nullable
+ ReportedSizes getLastReportedSizesForActivity(
+ ComponentName activityName, LogSeparator logSeparator) {
+ return getLastReportedSizesForActivity(getLogTag(activityName), logSeparator);
}
- private ReportedSizes readLastReportedSizes(String activityName, LogSeparator logSeparator) {
- final String[] lines = getDeviceLogsForComponents(logSeparator, activityName);
+ // TODO(b/73349193): Use {@link #getLastReportedSizesForActivity(ComponentName, LogSeparator)}.
+ @Deprecated
+ @Nullable
+ ReportedSizes getLastReportedSizesForActivity(String activityName, LogSeparator logSeparator) {
+ for (int retry = 1; retry <= 5; retry++ ) {
+ final ReportedSizes result = readLastReportedSizes(logSeparator, activityName);
+ if (result != null) {
+ return result;
+ }
+ logAlways("***Waiting for sizes to be reported... retry=" + retry);
+ SystemClock.sleep(1000);
+ }
+ logE("***Waiting for activity size failed: activityName=" + activityName);
+ return null;
+ }
+
+ private ReportedSizes readLastReportedSizes(LogSeparator logSeparator, String logTag) {
+ final String[] lines = getDeviceLogsForComponents(logSeparator, logTag);
for (int i = lines.length - 1; i >= 0; i--) {
final String line = lines[i].trim();
final Matcher matcher = sNewConfigPattern.matcher(line);
@@ -1369,26 +1306,19 @@
}
/** Waits for at least one onMultiWindowModeChanged event. */
- ActivityLifecycleCounts waitForOnMultiWindowModeChanged(
- String activityName, LogSeparator logSeparator) {
- int retriesLeft = 5;
+ ActivityLifecycleCounts waitForOnMultiWindowModeChanged(ComponentName activityName,
+ LogSeparator logSeparator) {
+ int retry = 1;
ActivityLifecycleCounts result;
do {
result = new ActivityLifecycleCounts(activityName, logSeparator);
- if (result.mMultiWindowModeChangedCount < 1) {
- log("***waitForOnMultiWindowModeChanged...");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- log(e.toString());
- // Well I guess we are not waiting...
- }
- } else {
- break;
+ if (result.mMultiWindowModeChangedCount >= 1) {
+ return result;
}
- } while (retriesLeft-- > 0);
+ logAlways("***waitForOnMultiWindowModeChanged... retry=" + retry);
+ SystemClock.sleep(TimeUnit.SECONDS.toMillis(1));
+ } while (retry++ <= 5);
return result;
-
}
// TODO: Now that our test are device side, we can convert these to a more direct communication
@@ -1414,6 +1344,8 @@
this(getLogTag(componentName), logSeparator);
}
+ // TODO(b/73349193): Use {@link ActivityLifecycleCounts(ComponentName, LogSeparator)}.
+ @Deprecated
ActivityLifecycleCounts(String logTag, LogSeparator logSeparator) {
int lineIndex = 0;
waitForIdle();
@@ -1525,7 +1457,7 @@
private boolean mMultipleTask;
private int mDisplayId = INVALID_DISPLAY_ID;
// A proxy activity that launches other activities including mTargetActivityName
- private String mLaunchingActivityName = LAUNCHING_ACTIVITY;
+ private String mLaunchingActivityName = LAUNCHING_ACTIVITY_NAME;
private ComponentName mLaunchingActivity;
private boolean mReorderToFront;
private boolean mWaitForLaunched;
@@ -1535,6 +1467,11 @@
private String mBroadcastReceiverPackage;
private String mBroadcastReceiverAction;
+ private enum LauncherType {
+ INSTRUMENTATION, LAUNCHING_ACTIVITY, BROADCAST_RECEIVER
+ }
+ private LauncherType mLauncherType = LauncherType.LAUNCHING_ACTIVITY;
+
public LaunchActivityBuilder(ActivityAndWindowManagersState amWmState) {
mAmWmState = amWmState;
mWaitForLaunched = true;
@@ -1578,34 +1515,29 @@
return this;
}
- /** TODO(b/73349193): Use {@link #setTargetActivity(ComponentName)} instead. */
+ // TODO(b/73349193): Use {@link #setTargetActivity(ComponentName)} instead.
@Deprecated
public LaunchActivityBuilder setTargetActivityName(String name) {
mTargetActivityName = name;
return this;
}
- /** TODO(b/73349193): Use {@link #setTargetActivity(ComponentName)} instead. */
- @Deprecated
- public LaunchActivityBuilder setTargetPackage(String pkg) {
- mTargetPackage = pkg;
- return this;
- }
-
public LaunchActivityBuilder setDisplayId(int id) {
mDisplayId = id;
return this;
}
- /** TODO(b/73349193): Use {@link #setLaunchingActivity(ComponentName)} instead. */
+ // TODO(b/73349193): Use {@link #setLaunchingActivity(ComponentName)} instead.
@Deprecated
public LaunchActivityBuilder setLaunchingActivityName(String name) {
mLaunchingActivityName = name;
+ mLauncherType = LauncherType.LAUNCHING_ACTIVITY;
return this;
}
public LaunchActivityBuilder setLaunchingActivity(ComponentName component) {
mLaunchingActivity = component;
+ mLauncherType = LauncherType.LAUNCHING_ACTIVITY;
return this;
}
@@ -1614,11 +1546,21 @@
return this;
}
- /** Use broadcast receiver instead of launching activity. */
+ /** Use broadcast receiver as a launchpad for activities. */
public LaunchActivityBuilder setUseBroadcastReceiver(final ComponentName broadcastReceiver,
final String broadcastAction) {
mBroadcastReceiverPackage = broadcastReceiver.getPackageName();
mBroadcastReceiverAction = broadcastAction;
+ mLauncherType = LauncherType.BROADCAST_RECEIVER;
+ return this;
+ }
+
+ /** Use {@link android.app.Instrumentation} as a launchpad for activities. */
+ public LaunchActivityBuilder setUseInstrumentation() {
+ mLauncherType = LauncherType.INSTRUMENTATION;
+ // Calling startActivity() from outside of an Activity context requires the
+ // FLAG_ACTIVITY_NEW_TASK flag.
+ setNewTask(true);
return this;
}
@@ -1628,6 +1570,44 @@
}
public void execute() throws Exception {
+ switch (mLauncherType) {
+ case INSTRUMENTATION:
+ launchUsingInstrumentation();
+ break;
+ case LAUNCHING_ACTIVITY:
+ case BROADCAST_RECEIVER:
+ launchUsingShellCommand();
+ }
+
+ if (mWaitForLaunched) {
+ mAmWmState.waitForValidState(false /* compareTaskAndStackBounds */, mTargetPackage,
+ new WaitForValidActivityState.Builder(mTargetActivityName).build());
+ }
+ }
+
+ /** Launch an activity using instrumentation. */
+ private void launchUsingInstrumentation() {
+ final Bundle b = new Bundle();
+ b.putBoolean(KEY_USE_INSTRUMENTATION, true);
+ b.putBoolean(KEY_LAUNCH_ACTIVITY, true);
+ b.putBoolean(KEY_LAUNCH_TO_SIDE, mToSide);
+ b.putBoolean(KEY_RANDOM_DATA, mRandomData);
+ b.putBoolean(KEY_NEW_TASK, mNewTask);
+ b.putBoolean(KEY_MULTIPLE_TASK, mMultipleTask);
+ b.putBoolean(KEY_REORDER_TO_FRONT, mReorderToFront);
+ b.putString(KEY_TARGET_ACTIVITY, mTargetActivityName);
+ b.putString(KEY_TARGET_PACKAGE, mTargetPackage);
+ b.putInt(KEY_DISPLAY_ID, mDisplayId);
+ b.putBoolean(KEY_USE_APPLICATION_CONTEXT, mUseApplicationContext);
+ b.putString(KEY_TARGET_COMPONENT, mComponent != null ? getActivityName(mComponent)
+ : null);
+ b.putBoolean(KEY_SUPPRESS_EXCEPTIONS, mSuppressExceptions);
+ final Context context = InstrumentationRegistry.getContext();
+ launchActivityFromExtras(context, b);
+ }
+
+ /** Build and execute a shell command to launch an activity. */
+ private void launchUsingShellCommand() {
StringBuilder commandBuilder = new StringBuilder();
if (mBroadcastReceiverPackage != null && mBroadcastReceiverAction != null) {
// Use broadcast receiver to launch the target.
@@ -1646,51 +1626,47 @@
}
// Add a flag to ensure we actually mean to launch an activity.
- commandBuilder.append(" --ez launch_activity true");
+ commandBuilder.append(" --ez " + KEY_LAUNCH_ACTIVITY + " true");
if (mToSide) {
- commandBuilder.append(" --ez launch_to_the_side true");
+ commandBuilder.append(" --ez " + KEY_LAUNCH_TO_SIDE + " true");
}
if (mRandomData) {
- commandBuilder.append(" --ez random_data true");
+ commandBuilder.append(" --ez " + KEY_RANDOM_DATA + " true");
}
if (mNewTask) {
- commandBuilder.append(" --ez new_task true");
+ commandBuilder.append(" --ez " + KEY_NEW_TASK + " true");
}
if (mMultipleTask) {
- commandBuilder.append(" --ez multiple_task true");
+ commandBuilder.append(" --ez " + KEY_MULTIPLE_TASK + " true");
}
if (mReorderToFront) {
- commandBuilder.append(" --ez reorder_to_front true");
+ commandBuilder.append(" --ez " + KEY_REORDER_TO_FRONT + " true");
}
if (mTargetActivityName != null) {
- commandBuilder.append(" --es target_activity ").append(mTargetActivityName);
- commandBuilder.append(" --es package_name ").append(mTargetPackage);
+ commandBuilder.append(" --es " + KEY_TARGET_ACTIVITY + " ")
+ .append(mTargetActivityName);
+ commandBuilder.append(" --es " + KEY_TARGET_PACKAGE + " ").append(mTargetPackage);
}
if (mDisplayId != INVALID_DISPLAY_ID) {
- commandBuilder.append(" --ei display_id ").append(mDisplayId);
+ commandBuilder.append(" --ei " + KEY_DISPLAY_ID + " ").append(mDisplayId);
}
if (mUseApplicationContext) {
- commandBuilder.append(" --ez use_application_context true");
+ commandBuilder.append(" --ez " + KEY_USE_APPLICATION_CONTEXT + " true");
}
if (mComponent != null) {
// {@link ActivityLauncher} parses this extra string by
// {@link ComponentName#unflattenFromString(String)}.
- commandBuilder.append(" --es target_component ")
+ commandBuilder.append(" --es " + KEY_TARGET_COMPONENT + " ")
.append(getActivityName(mComponent));
}
if (mSuppressExceptions) {
- commandBuilder.append(" --ez suppress_exceptions true");
+ commandBuilder.append(" --ez " + KEY_SUPPRESS_EXCEPTIONS + " true");
}
executeShellCommand(commandBuilder.toString());
-
- if (mWaitForLaunched) {
- mAmWmState.waitForValidState(false /* compareTaskAndStackBounds */, mTargetPackage,
- new WaitForValidActivityState.Builder(mTargetActivityName).build());
- }
}
}
}
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/UiDeviceUtils.java b/tests/framework/base/activitymanager/util/src/android/server/am/UiDeviceUtils.java
new file mode 100644
index 0000000..4b364b8
--- /dev/null
+++ b/tests/framework/base/activitymanager/util/src/android/server/am/UiDeviceUtils.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.am;
+
+import static android.server.am.StateLogger.logE;
+import static android.support.test.InstrumentationRegistry.getContext;
+import static android.view.KeyEvent.KEYCODE_APP_SWITCH;
+import static android.view.KeyEvent.KEYCODE_MENU;
+import static android.view.KeyEvent.KEYCODE_SLEEP;
+import static android.view.KeyEvent.KEYCODE_WAKEUP;
+import static android.view.KeyEvent.KEYCODE_WINDOW;
+
+import android.app.KeyguardManager;
+import android.graphics.Point;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.uiautomator.UiDevice;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import java.util.function.BooleanSupplier;
+
+/**
+ * Helper class to interact with {@link UiDevice}.
+ *
+ * All references to {@link UiDevice} and {@link KeyEvent} should be here for easy debugging.
+ */
+public class UiDeviceUtils {
+
+ private static final String TAG = "UiDeviceUtils";
+ private static final boolean DEBUG = false;
+
+ static void waitForDeviceIdle(long timeout) {
+ if (DEBUG) Log.d(TAG, "waitForDeviceIdle: timeout=" + timeout);
+ getDevice().waitForIdle(timeout);
+ }
+
+ public static void wakeUpDevice() throws RemoteException {
+ if (DEBUG) Log.d(TAG, "wakeUpDevice");
+ getDevice().wakeUp();
+ }
+
+ public static void dragPointer(Point from, Point to, int steps) {
+ if (DEBUG) Log.d(TAG, "dragPointer: from=" + from + " to=" + to + " steps=" + steps);
+ getDevice().drag(from.x, from.y, to.x, to.y, steps);
+ }
+
+ static void pressEnterButton() {
+ if (DEBUG) Log.d(TAG, "pressEnterButton");
+ getDevice().pressEnter();
+ }
+
+ static void pressHomeButton() {
+ if (DEBUG) Log.d(TAG, "pressHomeButton");
+ getDevice().pressHome();
+ }
+
+ static void pressBackButton() {
+ if (DEBUG) Log.d(TAG, "pressBackButton");
+ getDevice().pressBack();
+ }
+
+ public static void pressMenuButton() {
+ if (DEBUG) Log.d(TAG, "pressMenuButton");
+ getDevice().pressMenu();
+ }
+
+ static void pressSleepButton() {
+ if (DEBUG) Log.d(TAG, "pressSleepButton");
+ final PowerManager pm = getContext().getSystemService(PowerManager.class);
+ retryPressKeyCode(KEYCODE_SLEEP, () -> pm != null && !pm.isInteractive(),
+ "***Waiting for device sleep...");
+ }
+
+ static void pressWakeupButton() {
+ if (DEBUG) Log.d(TAG, "pressWakeupButton");
+ final PowerManager pm = getContext().getSystemService(PowerManager.class);
+ retryPressKeyCode(KEYCODE_WAKEUP, () -> pm != null && pm.isInteractive(),
+ "***Waiting for device wakeup...");
+ }
+
+ static void pressUnlockButton() {
+ if (DEBUG) Log.d(TAG, "pressUnlockButton");
+ final KeyguardManager kgm = getContext().getSystemService(KeyguardManager.class);
+ retryPressKeyCode(KEYCODE_MENU, () -> kgm != null && !kgm.isKeyguardLocked(),
+ "***Waiting for device unlock...");
+ }
+
+ static void pressWindowButton() {
+ if (DEBUG) Log.d(TAG, "pressWindowButton");
+ pressKeyCode(KEYCODE_WINDOW);
+ }
+
+ static void pressAppSwitchButton() {
+ if (DEBUG) Log.d(TAG, "pressAppSwitchButton");
+ pressKeyCode(KEYCODE_APP_SWITCH);
+ }
+
+ private static void retryPressKeyCode(int keyCode, BooleanSupplier waitFor, String msg) {
+ int retry = 1;
+ do {
+ pressKeyCode(keyCode);
+ if (waitFor.getAsBoolean()) {
+ return;
+ }
+ Log.d(TAG, msg + " retry=" + retry);
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ logE("Sleep interrupted: " + msg, e);
+ }
+ } while (retry++ < 5);
+ if (!waitFor.getAsBoolean()) {
+ logE(msg + " FAILED");
+ }
+ }
+
+ private static void pressKeyCode(int keyCode) {
+ getDevice().pressKeyCode(keyCode);
+ }
+
+ private static UiDevice getDevice() {
+ return UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ }
+}
diff --git a/tests/framework/base/windowmanager/frametestapp/src/android/server/wm/frametestapp/DialogTestActivity.java b/tests/framework/base/windowmanager/frametestapp/src/android/server/wm/frametestapp/DialogTestActivity.java
index e303f66..8410a8f 100644
--- a/tests/framework/base/windowmanager/frametestapp/src/android/server/wm/frametestapp/DialogTestActivity.java
+++ b/tests/framework/base/windowmanager/frametestapp/src/android/server/wm/frametestapp/DialogTestActivity.java
@@ -19,15 +19,11 @@
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
-import android.graphics.Rect;
-import android.os.Bundle;
import android.view.Gravity;
-import android.view.View;
import android.view.Window;
-import android.view.WindowInsets;
import android.view.WindowManager;
-public class DialogTestActivity extends Activity implements View.OnApplyWindowInsetsListener{
+public class DialogTestActivity extends Activity {
private static final String DIALOG_WINDOW_NAME = "TestDialog";
@@ -39,28 +35,16 @@
private AlertDialog mDialog;
- private Rect mOutsets = new Rect();
-
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- View content = new View(this);
- content.setOnApplyWindowInsetsListener(this);
- setContentView(content);
- }
-
@Override
protected void onStop() {
super.onStop();
mDialog.dismiss();
}
- public WindowInsets onApplyWindowInsets(View v, WindowInsets in) {
- if (in.isRound()) {
- mOutsets = new Rect(in.getSystemWindowInsetLeft(), in.getSystemWindowInsetTop(),
- in.getSystemWindowInsetRight(), in.getSystemWindowInsetBottom());
- }
+ @Override
+ protected void onResume() {
+ super.onResume();
setupTest(getIntent());
- return in;
}
private void setupTest(Intent intent) {
@@ -141,23 +125,23 @@
private void testExplicitSize() {
doLayoutParamTest((WindowManager.LayoutParams params) -> {
- params.width = 200 - mOutsets.left - mOutsets.right;
- params.height = 200 - mOutsets.bottom - mOutsets.top;
+ params.width = 200;
+ params.height = 200;
});
}
private void testExplicitSizeTopLeftGravity() {
doLayoutParamTest((WindowManager.LayoutParams params) -> {
- params.width = 200 - mOutsets.left - mOutsets.right;
- params.height = 200 - mOutsets.bottom - mOutsets.top;
+ params.width = 200;
+ params.height = 200;
params.gravity = Gravity.TOP | Gravity.LEFT;
});
}
private void testExplicitSizeBottomRightGravity() {
doLayoutParamTest((WindowManager.LayoutParams params) -> {
- params.width = 200 - mOutsets.left - mOutsets.right;
- params.height = 200 - mOutsets.bottom - mOutsets.top;
+ params.width = 200;
+ params.height = 200;
params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
});
}
@@ -182,6 +166,8 @@
doLayoutParamTest((WindowManager.LayoutParams params) -> {
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.MATCH_PARENT;
+ params.x = 100;
+ params.y = 100;
});
}
@@ -191,6 +177,8 @@
params.height = WindowManager.LayoutParams.MATCH_PARENT;
params.gravity = Gravity.LEFT | Gravity.TOP;
params.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+ params.x = 100;
+ params.y = 100;
});
}
@@ -204,9 +192,9 @@
doLayoutParamTest((WindowManager.LayoutParams params) -> {
params.gravity = Gravity.LEFT | Gravity.TOP;
params.horizontalMargin = .25f;
- params.verticalMargin = .25f;
- params.width = 200 - mOutsets.left - mOutsets.right;
- params.height = 200 - mOutsets.bottom - mOutsets.top;
+ params.verticalMargin = .35f;
+ params.width = 200;
+ params.height = 200;
params.x = 0;
params.y = 0;
});
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java b/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java
index 14c0179..2ab39e7 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java
@@ -23,6 +23,9 @@
import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
import static android.server.am.ActivityManagerTestBase.executeShellCommand;
import static android.server.am.StateLogger.log;
+import static android.server.am.UiDeviceUtils.dragPointer;
+import static android.server.am.UiDeviceUtils.pressMenuButton;
+import static android.server.am.UiDeviceUtils.wakeUpDevice;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -37,8 +40,6 @@
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.FlakyTest;
-import android.support.test.uiautomator.UiDevice;
import android.util.Log;
import org.junit.After;
@@ -117,7 +118,6 @@
protected Context mContext;
protected ActivityManager mAm;
- private UiDevice mDevice;
private Map<String, String> mSourceResults;
private Map<String, String> mTargetResults;
@@ -140,7 +140,6 @@
mContext = InstrumentationRegistry.getContext();
mAm = mContext.getSystemService(ActivityManager.class);
- mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mSourcePackageName = SOURCE_PACKAGE_NAME;
mTargetPackageName = TARGET_PACKAGE_NAME;
@@ -249,7 +248,7 @@
}
private void injectInput(Point from, Point to, int steps) throws Exception {
- mDevice.drag(from.x, from.y, to.x, to.y, steps);
+ dragPointer(from, to, steps);
}
private String findTaskInfo(String name) {
@@ -327,12 +326,12 @@
private void unlockDevice() {
// Wake up the device, if necessary.
try {
- mDevice.wakeUp();
+ wakeUpDevice();
} catch (RemoteException e) {
throw new RuntimeException(e);
}
// Unlock the screen.
- mDevice.pressMenu();
+ pressMenuButton();
}
private void assertDropResult(String sourceMode, String targetMode, String expectedDropResult)
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeEvent.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeEvent.java
index 7c605f4..b9126ab 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeEvent.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeEvent.java
@@ -16,19 +16,53 @@
package com.android.cts.mockime;
+import android.inputmethodservice.AbstractInputMethodService;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.view.View;
/**
* An immutable object that stores event happened in the {@link MockIme}.
*/
public final class ImeEvent {
+ private enum ReturnType {
+ Null,
+ KnownUnsupportedType,
+ Boolean,
+ }
+
+ private static ReturnType getReturnTypeFromObject(@Nullable Object object) {
+ if (object == null) {
+ return ReturnType.Null;
+ }
+ if (object instanceof AbstractInputMethodService.AbstractInputMethodImpl) {
+ return ReturnType.KnownUnsupportedType;
+ }
+ if (object instanceof View) {
+ return ReturnType.KnownUnsupportedType;
+ }
+ if (object instanceof Boolean) {
+ return ReturnType.Boolean;
+ }
+ throw new UnsupportedOperationException("Unsupported return type=" + object);
+ }
+
ImeEvent(@NonNull String eventName, int nestLevel, @NonNull String threadName, int threadId,
boolean isMainThread, long enterTimestamp, long exitTimestamp, long enterWallTime,
long exitWallTime, @NonNull ImeState enterState, @Nullable ImeState exitState,
- @NonNull Bundle arguments) {
+ @NonNull Bundle arguments, @Nullable Object returnValue) {
+ this(eventName, nestLevel, threadName, threadId, isMainThread, enterTimestamp,
+ exitTimestamp, enterWallTime, exitWallTime, enterState, exitState, arguments,
+ returnValue, getReturnTypeFromObject(returnValue));
+ }
+
+ private ImeEvent(@NonNull String eventName, int nestLevel, @NonNull String threadName,
+ int threadId, boolean isMainThread, long enterTimestamp, long exitTimestamp,
+ long enterWallTime, long exitWallTime, @NonNull ImeState enterState,
+ @Nullable ImeState exitState, @NonNull Bundle arguments, @Nullable Object returnValue,
+ @NonNull ReturnType returnType) {
mEventName = eventName;
mNestLevel = nestLevel;
mThreadName = threadName;
@@ -41,6 +75,8 @@
mEnterState = enterState;
mExitState = exitState;
mArguments = arguments;
+ mReturnValue = returnValue;
+ mReturnType = returnType;
}
@NonNull
@@ -58,6 +94,7 @@
bundle.putBundle("mEnterState", mEnterState.toBundle());
bundle.putBundle("mExitState", mExitState != null ? mExitState.toBundle() : null);
bundle.putBundle("mArguments", mArguments);
+ bundle.putString("mReturnType", mReturnType.name());
return bundle;
}
@@ -75,9 +112,22 @@
final ImeState enterState = ImeState.fromBundle(bundle.getBundle("mEnterState"));
final ImeState exitState = ImeState.fromBundle(bundle.getBundle("mExitState"));
final Bundle arguments = bundle.getBundle("mArguments");
+ final Object result;
+ final ReturnType returnType = ReturnType.valueOf(bundle.getString("mReturnType"));
+ switch (returnType) {
+ case Null:
+ case KnownUnsupportedType:
+ result = null;
+ break;
+ case Boolean:
+ result = bundle.getBoolean("mReturnValue");
+ break;
+ default:
+ throw new UnsupportedOperationException("Unsupported type=" + returnType);
+ }
return new ImeEvent(eventName, nestLevel, threadName,
threadId, isMainThread, enterTimestamp, exitTimestamp, enterWallTime, exitWallTime,
- enterState, exitState, arguments);
+ enterState, exitState, arguments, result, returnType);
}
/**
@@ -183,6 +233,22 @@
}
/**
+ * @return result value of this event.
+ * @throws NullPointerException if the return value is {@code null}
+ * @throws ClassCastException if the return value is non-{@code null} object that is different
+ * from {@link Boolean}
+ */
+ public boolean getReturnBooleanValue() {
+ if (mReturnType == ReturnType.Null) {
+ throw new NullPointerException();
+ }
+ if (mReturnType != ReturnType.Boolean) {
+ throw new ClassCastException();
+ }
+ return (Boolean) mReturnValue;
+ }
+
+ /**
* @return {@code true} if the event is issued when the event starts, not when the event
* finishes.
*/
@@ -207,4 +273,8 @@
private final ImeState mExitState;
@NonNull
private final Bundle mArguments;
+ @Nullable
+ private final Object mReturnValue;
+ @NonNull
+ private final ReturnType mReturnType;
}
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
index 7196f5b..ac46df3 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
@@ -46,6 +46,7 @@
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
+import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowInsets;
@@ -410,6 +411,11 @@
getTracer().onFinishInput(() -> super.onFinishInput());
}
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ return getTracer().onKeyDown(keyCode, event, () -> super.onKeyDown(keyCode, event));
+ }
+
@CallSuper
public boolean onEvaluateInputViewShown() {
return getTracer().onEvaluateInputViewShown(() -> {
@@ -544,7 +550,7 @@
// Send enter event
sendEventInternal(new ImeEvent(eventName, nestLevel, mThreadName,
mThreadId, mIsMainThread, enterTimestamp, 0, enterWallTime,
- 0, enterState, null, arguments));
+ 0, enterState, null, arguments, null));
++mNestLevel;
T result;
try {
@@ -558,7 +564,7 @@
// Send exit event
sendEventInternal(new ImeEvent(eventName, nestLevel, mThreadName,
mThreadId, mIsMainThread, enterTimestamp, exitTimestamp, enterWallTime,
- exitWallTime, enterState, exitState, arguments));
+ exitWallTime, enterState, exitState, arguments, result));
return result;
}
@@ -612,6 +618,13 @@
recordEventInternal("onFinishInput", runnable);
}
+ public boolean onKeyDown(int keyCode, KeyEvent event, @NonNull BooleanSupplier supplier) {
+ final Bundle arguments = new Bundle();
+ arguments.putInt("keyCode", keyCode);
+ arguments.putParcelable("event", event);
+ return recordEventInternal("onKeyDown", supplier::getAsBoolean, arguments);
+ }
+
public boolean onShowInputRequested(int flags, boolean configChange,
@NonNull BooleanSupplier supplier) {
final Bundle arguments = new Bundle();
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodManagerTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodManagerTest.java
index 695e4a5..50da9f2 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodManagerTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodManagerTest.java
@@ -18,45 +18,40 @@
import static android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
+import static android.view.inputmethod.cts.util.TestUtils.runOnMainSync;
import static android.view.inputmethod.cts.util.TestUtils.waitOnMainUntil;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.support.annotation.NonNull;
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.text.TextUtils;
-import android.view.KeyEvent;
import android.view.View;
-import android.view.Window;
-import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import android.view.inputmethod.cts.util.TestActivity;
import android.widget.EditText;
+import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
-import com.android.compatibility.common.util.PollingCheck;
-
-import org.junit.After;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
@MediumTest
@@ -67,10 +62,6 @@
private Context mContext;
private InputMethodManager mImManager;
- @Rule
- public ActivityTestRule<InputMethodCtsActivity> mActivityRule =
- new ActivityTestRule<>(InputMethodCtsActivity.class);
-
@Before
public void setup() {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
@@ -78,40 +69,55 @@
mImManager = mContext.getSystemService(InputMethodManager.class);
}
- @After
- public void teardown() {
- mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+ @Test
+ public void testIsActive() throws Throwable {
+ final AtomicReference<EditText> focusedEditTextRef = new AtomicReference<>();
+ final AtomicReference<EditText> nonFocusedEditTextRef = new AtomicReference<>();
+ TestActivity.startSync(activity -> {
+ final LinearLayout layout = new LinearLayout(activity);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+ final EditText focusedEditText = new EditText(activity);
+ layout.addView(focusedEditText);
+ focusedEditTextRef.set(focusedEditText);
+ focusedEditText.requestFocus();
+
+ final EditText nonFocusedEditText = new EditText(activity);
+ layout.addView(nonFocusedEditText);
+ nonFocusedEditTextRef.set(nonFocusedEditText);
+
+ return layout;
+ });
+ waitOnMainUntil(() -> mImManager.isActive(), TIMEOUT);
+ assertTrue(mImManager.isAcceptingText());
+ assertTrue(mImManager.isActive(focusedEditTextRef.get()));
+ assertFalse(mImManager.isActive(nonFocusedEditTextRef.get()));
}
@Test
- public void testInputMethodManager() throws Throwable {
- final InputMethodCtsActivity activity = mActivityRule.getActivity();
- assumeTrue(mContext.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_INPUT_METHODS));
+ public void testIsAcceptingText() throws Throwable {
+ final AtomicReference<EditText> focusedFakeEditTextRef = new AtomicReference<>();
+ TestActivity.startSync(activity -> {
+ final LinearLayout layout = new LinearLayout(activity);
+ layout.setOrientation(LinearLayout.VERTICAL);
- Window window = activity.getWindow();
- final EditText view = window.findViewById(R.id.entry);
-
- PollingCheck.waitFor(1000, view::hasWindowFocus);
-
- mActivityRule.runOnUiThread(view::requestFocus);
- mInstrumentation.waitForIdleSync();
- assertTrue(view.isFocused());
-
- BaseInputConnection connection = new BaseInputConnection(view, false);
-
- PollingCheck.waitFor(mImManager::isActive);
-
- assertTrue(mImManager.isAcceptingText());
- assertTrue(mImManager.isActive(view));
-
- assertFalse(mImManager.isFullscreenMode());
- connection.reportFullscreenMode(true);
- // Only IMEs are allowed to report full-screen mode. Calling this method from the
- // application should have no effect.
- assertFalse(mImManager.isFullscreenMode());
-
- mInstrumentation.waitForIdleSync();
+ final EditText focusedFakeEditText = new EditText(activity) {
+ @Override
+ public InputConnection onCreateInputConnection(EditorInfo info) {
+ super.onCreateInputConnection(info);
+ return null;
+ }
+ };
+ layout.addView(focusedFakeEditText);
+ focusedFakeEditTextRef.set(focusedFakeEditText);
+ focusedFakeEditText.requestFocus();
+ return layout;
+ });
+ waitOnMainUntil(() -> mImManager.isActive(), TIMEOUT);
+ assertTrue(mImManager.isActive(focusedFakeEditTextRef.get()));
+ assertFalse("InputMethodManager#isAcceptingText() must return false "
+ + "if target View returns null from onCreateInputConnection().",
+ mImManager.isAcceptingText());
}
@Test
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java
index 3c9f838..0754e7f 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java
@@ -18,23 +18,30 @@
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE;
+import static android.view.inputmethod.cts.util.TestUtils.getOnMainSync;
import static android.view.inputmethod.cts.util.TestUtils.waitOnMainUntil;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.expectCommand;
import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
import static com.android.cts.mockime.ImeEventStreamTestUtils.notExpectEvent;
-import static com.android.cts.mockime.ImeEventStreamTestUtils.waitForInputViewLayoutStable;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
import android.app.Instrumentation;
import android.inputmethodservice.InputMethodService;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
+import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.inputmethod.cts.util.EndToEndImeTestBase;
import android.view.inputmethod.cts.util.TestActivity;
import android.widget.EditText;
import android.widget.LinearLayout;
+import com.android.cts.mockime.ImeCommand;
+import com.android.cts.mockime.ImeEvent;
import com.android.cts.mockime.ImeEventStream;
import com.android.cts.mockime.ImeSettings;
import com.android.cts.mockime.MockImeSession;
@@ -44,6 +51,8 @@
import org.junit.runner.RunWith;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Predicate;
/**
* Tests for {@link InputMethodService} methods.
@@ -52,10 +61,27 @@
@RunWith(AndroidJUnit4.class)
public class InputMethodServiceTest extends EndToEndImeTestBase {
private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
- private static final long LAYOUT_STABLE_THRESHOLD = TimeUnit.SECONDS.toMillis(3);
+ private static final long EXPECTED_TIMEOUT = TimeUnit.SECONDS.toMillis(2);
private Instrumentation mInstrumentation;
+ private static Predicate<ImeEvent> backKeyDownMatcher(boolean expectedReturnValue) {
+ return event -> {
+ if (!event.isEnterEvent()) {
+ // Skip enter event since we are interested in the return value.
+ return false;
+ }
+ if (!TextUtils.equals("onKeyDown", event.getEventName())) {
+ return false;
+ }
+ final int keyCode = event.getArguments().getInt("keyCode");
+ if (keyCode != KeyEvent.KEYCODE_BACK) {
+ return false;
+ }
+ return event.getReturnBooleanValue() == expectedReturnValue;
+ };
+ }
+
@Before
public void setup() {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
@@ -87,16 +113,30 @@
final TestActivity testActivity = createTestActivity(SOFT_INPUT_STATE_ALWAYS_VISIBLE);
expectEvent(stream, event -> "onStartInputView".equals(event.getEventName()), TIMEOUT);
- imeSession.callSetBackDisposition(InputMethodService.BACK_DISPOSITION_WILL_DISMISS);
- waitForInputViewLayoutStable(stream, LAYOUT_STABLE_THRESHOLD);
+ final ImeCommand command = imeSession.callSetBackDisposition(
+ InputMethodService.BACK_DISPOSITION_WILL_DISMISS);
+ expectCommand(stream, command, TIMEOUT);
+
+ testActivity.setIgnoreBackKey(true);
+ assertEquals(0,
+ (long) getOnMainSync(() -> testActivity.getOnBackPressedCallCount()));
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+ // InputMethodService#onKeyDown() should handle back key event.
+ // TODO: Also check InputMethodService#requestHideSelf()
+ expectEvent(stream, backKeyDownMatcher(true), TIMEOUT);
+
// keyboard will hide
expectEvent(stream, event -> "hideSoftInput".equals(event.getEventName()), TIMEOUT);
- // Activity should still be running since ime consumes the back key.
- waitOnMainUntil(() -> !testActivity.isFinishing(), LAYOUT_STABLE_THRESHOLD,
- "Activity should not be finishing.");
+ // Make sure TestActivity#onBackPressed() is NOT called.
+ try {
+ waitOnMainUntil(() -> testActivity.getOnBackPressedCallCount() > 0,
+ EXPECTED_TIMEOUT);
+ fail("Activity#onBackPressed() should not be called");
+ } catch (TimeoutException e){
+ // This is fine. We actually expect timeout.
+ }
}
}
@@ -111,16 +151,25 @@
final TestActivity testActivity = createTestActivity(SOFT_INPUT_STATE_ALWAYS_VISIBLE);
expectEvent(stream, event -> "onStartInputView".equals(event.getEventName()), TIMEOUT);
- imeSession.callSetBackDisposition(InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS);
- waitForInputViewLayoutStable(stream, LAYOUT_STABLE_THRESHOLD);
+ final ImeCommand command = imeSession.callSetBackDisposition(
+ InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS);
+ expectCommand(stream, command, TIMEOUT);
+
+ testActivity.setIgnoreBackKey(true);
+ assertEquals(0,
+ (long) getOnMainSync(() -> testActivity.getOnBackPressedCallCount()));
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
- // keyboard will hide.
- expectEvent(stream, event -> "hideSoftInput".equals(event.getEventName()), TIMEOUT);
+ // InputMethodService#onKeyDown() will not handle back key event.
+ // TODO: Also check InputMethodService#requestHideSelf()
+ expectEvent(stream, backKeyDownMatcher(false), TIMEOUT);
- // activity should've gone (or going) away since IME wont consume the back event.
- waitOnMainUntil(() -> testActivity.isFinishing(), LAYOUT_STABLE_THRESHOLD,
- "Activity should be finishing or finished.");
+ // keyboard will not hide
+ notExpectEvent(stream, event -> "hideSoftInput".equals(event.getEventName()),
+ EXPECTED_TIMEOUT);
+
+ // Activity#onBackPressed() should be called.
+ waitOnMainUntil(() -> testActivity.getOnBackPressedCallCount() > 0, TIMEOUT);
}
}
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/OnScreenPositionTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/OnScreenPositionTest.java
index 7e0998c..b320f88 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/OnScreenPositionTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/OnScreenPositionTest.java
@@ -65,6 +65,7 @@
final EditText editText = new EditText(activity);
editText.setPrivateImeOptions(TEST_MARKER);
editText.setHint("editText");
+ editText.requestFocus();
editTextRef.set(editText);
layout.addView(editText);
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/util/TestActivity.java b/tests/inputmethod/src/android/view/inputmethod/cts/util/TestActivity.java
index e89934a..c98ab6f 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/util/TestActivity.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/util/TestActivity.java
@@ -19,10 +19,13 @@
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
+import android.support.annotation.AnyThread;
import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
import android.support.test.InstrumentationRegistry;
import android.view.View;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
@@ -33,6 +36,32 @@
private Function<TestActivity, View> mInitializer = null;
+ private AtomicBoolean mIgnoreBackKey = new AtomicBoolean();
+
+ private long mOnBackPressedCallCount;
+
+ /**
+ * Controls how {@link #onBackPressed()} behaves.
+ *
+ * <p>TODO: Use {@link android.app.AppComponentFactory} instead to customise the behavior of
+ * {@link TestActivity}.</p>
+ *
+ * @param ignore {@code true} when {@link TestActivity} should do nothing when
+ * {@link #onBackPressed()} is called
+ */
+ @AnyThread
+ public void setIgnoreBackKey(boolean ignore) {
+ mIgnoreBackKey.set(ignore);
+ }
+
+ @UiThread
+ public long getOnBackPressedCallCount() {
+ return mOnBackPressedCallCount;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -43,6 +72,18 @@
}
/**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onBackPressed() {
+ ++mOnBackPressedCallCount;
+ if (mIgnoreBackKey.get()) {
+ return;
+ }
+ super.onBackPressed();
+ }
+
+ /**
* Launches {@link TestActivity} with the given initialization logic for content view.
*
* <p>As long as you are using {@link android.support.test.runner.AndroidJUnitRunner}, the test
diff --git a/tests/jank/Android.mk b/tests/jank/Android.mk
index d619003..df7aa54 100644
--- a/tests/jank/Android.mk
+++ b/tests/jank/Android.mk
@@ -23,6 +23,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsJankDeviceTestCases
+LOCAL_SDK_VERSION := current
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/tests/leanbackjank/Android.mk b/tests/leanbackjank/Android.mk
index 7f1177a..ab7eedc 100644
--- a/tests/leanbackjank/Android.mk
+++ b/tests/leanbackjank/Android.mk
@@ -24,6 +24,7 @@
./app/src/android/leanbackjank/app/IntentKeys.java
LOCAL_PACKAGE_NAME := CtsLeanbackJankTestCases
+LOCAL_SDK_VERSION := current
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/tests/leanbackjank/app/Android.mk b/tests/leanbackjank/app/Android.mk
index 04c3d3f..6ef8e87 100644
--- a/tests/leanbackjank/app/Android.mk
+++ b/tests/leanbackjank/app/Android.mk
@@ -23,6 +23,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsLeanbackJankApp
+LOCAL_SDK_VERSION := current
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/tests/libcore/javautilcollections/Android.mk b/tests/libcore/javautilcollections/Android.mk
index e2bcef5..5a0bbb9 100644
--- a/tests/libcore/javautilcollections/Android.mk
+++ b/tests/libcore/javautilcollections/Android.mk
@@ -15,10 +15,22 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
- guava-20.0-prebuilt:libs/guava-20.0.jar \
- guava-testlib-20.0-prebuilt:libs/guava-testlib-20.0.jar
-include $(BUILD_MULTI_PREBUILT)
+LOCAL_MODULE := guava-20.0-prebuilt
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_SRC_FILES := libs/guava-20.0.jar
+LOCAL_UNINSTALLABLE_MODULE := true
+LOCAL_SDK_VERSION := current
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := guava-testlib-20.0-prebuilt
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_SRC_FILES := libs/guava-testlib-20.0.jar
+LOCAL_UNINSTALLABLE_MODULE := true
+LOCAL_SDK_VERSION := current
+include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
@@ -29,6 +41,7 @@
guava-testlib-20.0-prebuilt
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsLibcoreJavaUtilCollectionsTestCases
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/libcore/jsr166/Android.mk b/tests/libcore/jsr166/Android.mk
index 9e11815..e355efd 100644
--- a/tests/libcore/jsr166/Android.mk
+++ b/tests/libcore/jsr166/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsLibcoreJsr166TestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_STATIC_JAVA_LIBRARIES := \
cts-core-test-runner \
diff --git a/tests/libcore/luni/Android.mk b/tests/libcore/luni/Android.mk
index 81b44d3..7dfcb61 100644
--- a/tests/libcore/luni/Android.mk
+++ b/tests/libcore/luni/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsLibcoreTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_STATIC_JAVA_LIBRARIES := \
apache-harmony-tests \
diff --git a/tests/libcore/ojluni/Android.mk b/tests/libcore/ojluni/Android.mk
index 079638e..8354615 100644
--- a/tests/libcore/ojluni/Android.mk
+++ b/tests/libcore/ojluni/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsLibcoreOjTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_STATIC_JAVA_LIBRARIES := \
core-ojtests-public
diff --git a/tests/libcore/okhttp/Android.mk b/tests/libcore/okhttp/Android.mk
index 91e9ef5..a706476 100644
--- a/tests/libcore/okhttp/Android.mk
+++ b/tests/libcore/okhttp/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsLibcoreOkHttpTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_STATIC_JAVA_LIBRARIES := \
bouncycastle-nojarjar \
diff --git a/tests/libcore/runner/Android.mk b/tests/libcore/runner/Android.mk
index 6ef3c03..e70ad50 100644
--- a/tests/libcore/runner/Android.mk
+++ b/tests/libcore/runner/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsLibcoreTestRunner
+LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := \
cts-core-test-runner
diff --git a/tests/libcore/wycheproof-bc/Android.mk b/tests/libcore/wycheproof-bc/Android.mk
index 801feac..61dc8c7 100644
--- a/tests/libcore/wycheproof-bc/Android.mk
+++ b/tests/libcore/wycheproof-bc/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsLibcoreWycheproofBCTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_STATIC_JAVA_LIBRARIES := \
cts-core-test-runner \
diff --git a/tests/libcore/wycheproof/Android.mk b/tests/libcore/wycheproof/Android.mk
index 652e36c..015b49d 100644
--- a/tests/libcore/wycheproof/Android.mk
+++ b/tests/libcore/wycheproof/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsLibcoreWycheproofConscryptTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_STATIC_JAVA_LIBRARIES := \
cts-core-test-runner \
diff --git a/tests/signature/api-check/Android.mk b/tests/signature/api-check/Android.mk
index 888ace3..9ee92c9 100644
--- a/tests/signature/api-check/Android.mk
+++ b/tests/signature/api-check/Android.mk
@@ -22,7 +22,7 @@
# don't include this package in any target
LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src/java)
LOCAL_MODULE := cts-api-signature-test
@@ -37,4 +37,13 @@
include $(BUILD_STATIC_JAVA_LIBRARY)
+include $(CLEAR_VARS)
+LOCAL_MODULE := libclassdescriptors
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := src/jni/classdescriptors.cpp
+LOCAL_HEADER_LIBRARIES := jni_headers libopenjdkjvmti_headers
+LOCAL_SDK_VERSION := current
+LOCAL_NDK_STL_VARIANT := c++_static
+include $(BUILD_SHARED_LIBRARY)
+
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/signature/api-check/android-test-base-27-api/AndroidManifest.xml b/tests/signature/api-check/android-test-base-27-api/AndroidManifest.xml
index 684872f..877e911 100644
--- a/tests/signature/api-check/android-test-base-27-api/AndroidManifest.xml
+++ b/tests/signature/api-check/android-test-base-27-api/AndroidManifest.xml
@@ -22,7 +22,7 @@
<uses-sdk android:minSdkVersion="25" android:targetSdkVersion="27"/>
- <application/>
+ <application android:debuggable="true"/>
<instrumentation android:name="repackaged.android.test.InstrumentationTestRunner"
android:targetPackage="android.signature.cts.api.android_test_base_27"
diff --git a/tests/signature/api-check/android-test-mock-current-api/AndroidManifest.xml b/tests/signature/api-check/android-test-mock-current-api/AndroidManifest.xml
index 5c88521..f0fc8e1 100644
--- a/tests/signature/api-check/android-test-mock-current-api/AndroidManifest.xml
+++ b/tests/signature/api-check/android-test-mock-current-api/AndroidManifest.xml
@@ -20,7 +20,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
- <application>
+ <application android:debuggable="true">
<uses-library android:name="android.test.mock"/>
</application>
diff --git a/tests/signature/api-check/android-test-runner-current-api/AndroidManifest.xml b/tests/signature/api-check/android-test-runner-current-api/AndroidManifest.xml
index 61de501..f81665e 100644
--- a/tests/signature/api-check/android-test-runner-current-api/AndroidManifest.xml
+++ b/tests/signature/api-check/android-test-runner-current-api/AndroidManifest.xml
@@ -20,7 +20,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
- <application>
+ <application android:debuggable="true">
<uses-library android:name="android.test.runner"/>
</application>
diff --git a/tests/signature/api-check/apache-http-legacy-27-api/Android.mk b/tests/signature/api-check/apache-http-legacy-27-api/Android.mk
new file mode 100644
index 0000000..0f2161a
--- /dev/null
+++ b/tests/signature/api-check/apache-http-legacy-27-api/Android.mk
@@ -0,0 +1,25 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsApacheHttpLegacy27ApiSignatureTestCases
+
+LOCAL_SIGNATURE_API_FILES := \
+ current.api \
+ apache-http-legacy-minus-current.api \
+
+include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/apache-http-legacy-27-api/AndroidManifest.xml b/tests/signature/api-check/apache-http-legacy-27-api/AndroidManifest.xml
new file mode 100644
index 0000000..ae69f52
--- /dev/null
+++ b/tests/signature/api-check/apache-http-legacy-27-api/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.signature.cts.api.apache_http_legacy_27">
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+
+ <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="27"/>
+
+ <application/>
+
+ <instrumentation android:name="repackaged.android.test.InstrumentationTestRunner"
+ android:targetPackage="android.signature.cts.api.apache_http_legacy_27"
+ android:label="Apache Http Legacy 27 API Signature Test"/>
+
+</manifest>
diff --git a/tests/signature/api-check/apache-http-legacy-27-api/AndroidTest.xml b/tests/signature/api-check/apache-http-legacy-27-api/AndroidTest.xml
new file mode 100644
index 0000000..3bbc90e
--- /dev/null
+++ b/tests/signature/api-check/apache-http-legacy-27-api/AndroidTest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Apache Http Legacy 27 API Signature test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="systems" />
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
+ <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="push" value="current.api->/data/local/tmp/signature-test/current.api" />
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="push" value="apache-http-legacy-minus-current.api->/data/local/tmp/signature-test/apache-http-legacy-minus-current.api" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsApacheHttpLegacy27ApiSignatureTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.signature.cts.api.apache_http_legacy_27" />
+ <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
+ <option name="class" value="android.signature.cts.api.SignatureTest" />
+ <option name="instrumentation-arg" key="base-api-files" value="current.api" />
+ <option name="instrumentation-arg" key="expected-api-files" value="apache-http-legacy-minus-current.api" />
+ <option name="runtime-hint" value="5s" />
+ </test>
+</configuration>
diff --git a/tests/signature/api-check/apache-http-legacy-current-api/Android.mk b/tests/signature/api-check/apache-http-legacy-current-api/Android.mk
index cf391bd..b382698 100644
--- a/tests/signature/api-check/apache-http-legacy-current-api/Android.mk
+++ b/tests/signature/api-check/apache-http-legacy-current-api/Android.mk
@@ -19,7 +19,6 @@
LOCAL_PACKAGE_NAME := CtsApacheHttpLegacyCurrentApiSignatureTestCases
LOCAL_SIGNATURE_API_FILES := \
- current.api \
apache-http-legacy-minus-current.api \
include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/apache-http-legacy-current-api/AndroidManifest.xml b/tests/signature/api-check/apache-http-legacy-current-api/AndroidManifest.xml
index eaf118b..f0fb7d8 100644
--- a/tests/signature/api-check/apache-http-legacy-current-api/AndroidManifest.xml
+++ b/tests/signature/api-check/apache-http-legacy-current-api/AndroidManifest.xml
@@ -20,7 +20,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
- <application/>
+ <application android:debuggable="true"/>
<instrumentation android:name="repackaged.android.test.InstrumentationTestRunner"
android:targetPackage="android.signature.cts.api.apache_http_legacy_current"
diff --git a/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml b/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
index 9002d39..418c881 100644
--- a/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
@@ -21,9 +21,6 @@
<option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="push" value="current.api->/data/local/tmp/signature-test/current.api" />
- </target_preparer>
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="push" value="apache-http-legacy-minus-current.api->/data/local/tmp/signature-test/apache-http-legacy-minus-current.api" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
@@ -34,8 +31,7 @@
<option name="package" value="android.signature.cts.api.apache_http_legacy_current" />
<option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
<option name="class" value="android.signature.cts.api.SignatureTest" />
- <option name="instrumentation-arg" key="base-api-files" value="current.api" />
- <option name="instrumentation-arg" key="expected-api-files" value="apache-http-legacy-minus-current.api" />
+ <option name="instrumentation-arg" key="unexpected-api-files" value="apache-http-legacy-minus-current.api" />
<option name="runtime-hint" value="5s" />
</test>
</configuration>
diff --git a/tests/signature/api-check/apache-http-legacy-uses-library-api/Android.mk b/tests/signature/api-check/apache-http-legacy-uses-library-api/Android.mk
new file mode 100644
index 0000000..1d801c5
--- /dev/null
+++ b/tests/signature/api-check/apache-http-legacy-uses-library-api/Android.mk
@@ -0,0 +1,25 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsApacheHttpLegacyUsesLibraryApiSignatureTestCases
+
+LOCAL_SIGNATURE_API_FILES := \
+ current.api \
+ apache-http-legacy-minus-current.api \
+
+include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidManifest.xml b/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidManifest.xml
new file mode 100644
index 0000000..f759c54
--- /dev/null
+++ b/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.signature.cts.api.apache_http_legacy_uses_library">
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+
+ <application>
+ <uses-library android:name="org.apache.http.legacy"/>
+ </application>
+
+ <instrumentation android:name="repackaged.android.test.InstrumentationTestRunner"
+ android:targetPackage="android.signature.cts.api.apache_http_legacy_uses_library"
+ android:label="Apache Http Legacy UsesLibrary API Signature Test"/>
+
+</manifest>
diff --git a/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidTest.xml b/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidTest.xml
new file mode 100644
index 0000000..bd2c566
--- /dev/null
+++ b/tests/signature/api-check/apache-http-legacy-uses-library-api/AndroidTest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Apache Http Legacy UsesLibrary API Signature test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="systems" />
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
+ <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="push" value="current.api->/data/local/tmp/signature-test/current.api" />
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="push" value="apache-http-legacy-minus-current.api->/data/local/tmp/signature-test/apache-http-legacy-minus-current.api" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsApacheHttpLegacyUsesLibraryApiSignatureTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.signature.cts.api.apache_http_legacy_uses_library" />
+ <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
+ <option name="class" value="android.signature.cts.api.SignatureTest" />
+ <option name="instrumentation-arg" key="base-api-files" value="current.api" />
+ <option name="instrumentation-arg" key="expected-api-files" value="apache-http-legacy-minus-current.api" />
+ <option name="runtime-hint" value="5s" />
+ </test>
+</configuration>
diff --git a/tests/signature/api-check/build_signature_apk.mk b/tests/signature/api-check/build_signature_apk.mk
index 3b0afd2..1bae842 100644
--- a/tests/signature/api-check/build_signature_apk.mk
+++ b/tests/signature/api-check/build_signature_apk.mk
@@ -21,7 +21,7 @@
# the list of api files needed
# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_TAGS := tests
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
@@ -30,9 +30,15 @@
LOCAL_STATIC_JAVA_LIBRARIES := cts-api-signature-test
+LOCAL_JNI_SHARED_LIBRARIES := libclassdescriptors
+LOCAL_MULTILIB := both
+
LOCAL_ADDITIONAL_DEPENDENCIES += \
$(addprefix $(COMPATIBILITY_TESTCASES_OUT_cts)/,$(LOCAL_SIGNATURE_API_FILES))
+LOCAL_DEX_PREOPT := false
+LOCAL_PROGUARD_ENABLED := disabled
+
include $(BUILD_CTS_PACKAGE)
LOCAL_SIGNATURE_API_FILES :=
diff --git a/tests/signature/api-check/current-api/AndroidManifest.xml b/tests/signature/api-check/current-api/AndroidManifest.xml
index 7dc5730..d6f474b 100644
--- a/tests/signature/api-check/current-api/AndroidManifest.xml
+++ b/tests/signature/api-check/current-api/AndroidManifest.xml
@@ -20,7 +20,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
- <application/>
+ <application android:debuggable="true"/>
<instrumentation android:name="repackaged.android.test.InstrumentationTestRunner"
android:targetPackage="android.signature.cts.api.current"
diff --git a/tests/signature/api-check/hidden-api/Android.mk b/tests/signature/api-check/hidden-api/Android.mk
new file mode 100644
index 0000000..25df1bc
--- /dev/null
+++ b/tests/signature/api-check/hidden-api/Android.mk
@@ -0,0 +1,43 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := cts-hidden-api-blacklist
+LOCAL_MODULE_STEM := blacklist.api
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH = $(TARGET_OUT_DATA_ETC)
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+include $(BUILD_SYSTEM)/base_rules.mk
+$(eval $(call copy-one-file,$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST),$(LOCAL_BUILT_MODULE)))
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcts_hiddenapi
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := hidden-api.cpp
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
+LOCAL_SDK_VERSION := current
+LOCAL_NDK_STL_VARIANT := c++_static
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := CtsHiddenApiDiscoveryTestCases
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+LOCAL_MULTILIB := both
+LOCAL_SIGNATURE_API_FILES := blacklist.api
+LOCAL_JNI_SHARED_LIBRARIES := libcts_hiddenapi
+LOCAL_NDK_STL_VARIANT := c++_static
+include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/hidden-api/AndroidManifest.xml b/tests/signature/api-check/hidden-api/AndroidManifest.xml
new file mode 100644
index 0000000..a68e11a
--- /dev/null
+++ b/tests/signature/api-check/hidden-api/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.signature.cts.api.hidden">
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+
+ <application/>
+
+ <instrumentation android:name="repackaged.android.test.InstrumentationTestRunner"
+ android:targetPackage="android.signature.cts.api.hidden"
+ android:label="Hidden API Signature Test"/>
+</manifest>
diff --git a/tests/signature/api-check/hidden-api/AndroidTest.xml b/tests/signature/api-check/hidden-api/AndroidTest.xml
new file mode 100644
index 0000000..df6d7ce
--- /dev/null
+++ b/tests/signature/api-check/hidden-api/AndroidTest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Hidden API Signature test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="systems" />
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
+ <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="push" value="blacklist.api->/data/local/tmp/signature-test/blacklist.api" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsHiddenApiDiscoveryTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.signature.cts.api.hidden" />
+ <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
+ <option name="class" value="android.signature.cts.api.HiddenApiTest" />
+ <option name="instrumentation-arg" key="hidden-api-files" value="blacklist.api" />
+ <option name="runtime-hint" value="30s" />
+ </test>
+</configuration>
diff --git a/tests/signature/api-check/hidden-api/hidden-api.cpp b/tests/signature/api-check/hidden-api/hidden-api.cpp
new file mode 100644
index 0000000..fd2a94d
--- /dev/null
+++ b/tests/signature/api-check/hidden-api/hidden-api.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+
+class ScopedUtfChars {
+ public:
+ ScopedUtfChars(JNIEnv* env, jstring s) : env_(env), string_(s) {
+ if (s == NULL) {
+ utf_chars_ = NULL;
+ } else {
+ utf_chars_ = env->GetStringUTFChars(s, NULL);
+ }
+ }
+
+ ~ScopedUtfChars() {
+ if (utf_chars_) {
+ env_->ReleaseStringUTFChars(string_, utf_chars_);
+ }
+ }
+
+ const char* c_str() const {
+ return utf_chars_;
+ }
+
+ private:
+ JNIEnv* env_;
+ jstring string_;
+ const char* utf_chars_;
+};
+
+extern "C" JNIEXPORT void JNICALL
+Java_android_signature_cts_api_HiddenApiTest_getField_1JNI(
+ JNIEnv* env, jclass, jclass klass, jstring name, jstring type) {
+ ScopedUtfChars utf_name(env, name);
+ ScopedUtfChars utf_type(env, type);
+ // Attempt to access the given instance field. It will succeed if it exists,
+ // and throw NoSuchFieldError if not.
+ env->GetFieldID(klass, utf_name.c_str(), utf_type.c_str());
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_android_signature_cts_api_HiddenApiTest_getStaticField_1JNI(
+ JNIEnv* env, jclass, jclass klass, jstring name, jstring type) {
+ ScopedUtfChars utf_name(env, name);
+ ScopedUtfChars utf_type(env, type);
+ // Attempt to access the given static field. It will succeed if it exists,
+ // and throw NoSuchFieldError if not.
+ env->GetStaticFieldID(klass, utf_name.c_str(), utf_type.c_str());
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_android_signature_cts_api_HiddenApiTest_getMethod_1JNI(
+ JNIEnv* env, jclass, jclass klass, jstring name, jstring signature) {
+ ScopedUtfChars utf_name(env, name);
+ ScopedUtfChars utf_signature(env, signature);
+ // Attempt to access the given instance method. It will succeed if it exists,
+ // and throw NoSuchMethodError if not.
+ env->GetMethodID(klass, utf_name.c_str(), utf_signature.c_str());
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_android_signature_cts_api_HiddenApiTest_getStaticMethod_1JNI(
+ JNIEnv* env, jclass, jclass klass, jstring name, jstring signature) {
+ ScopedUtfChars utf_name(env, name);
+ ScopedUtfChars utf_signature(env, signature);
+ // Attempt to access the given static method. It will succeed if it exists,
+ // and throw NoSuchMethodError if not.
+ env->GetStaticMethodID(klass, utf_name.c_str(), utf_signature.c_str());
+}
diff --git a/tests/signature/api-check/src/android/signature/cts/api/BootClassPathClassesProvider.java b/tests/signature/api-check/src/android/signature/cts/api/BootClassPathClassesProvider.java
deleted file mode 100644
index 02bd72e..0000000
--- a/tests/signature/api-check/src/android/signature/cts/api/BootClassPathClassesProvider.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.signature.cts.api;
-
-import android.signature.cts.ClassProvider;
-import dalvik.system.DexFile;
-import java.io.IOException;
-import java.util.Enumeration;
-import java.util.stream.Stream;
-
-@SuppressWarnings("deprecation")
-public class BootClassPathClassesProvider extends ClassProvider {
- @Override
- public Stream<Class<?>> getAllClasses() {
- Stream.Builder<Class<?>> builder = Stream.builder();
- for (String file : getBootJarPaths()) {
- try {
- DexFile dexFile = new DexFile(file);
- Enumeration<String> entries = dexFile.entries();
- while (entries.hasMoreElements()) {
- String className = entries.nextElement();
- Class<?> clazz = getClass(className);
- if (clazz != null) {
- builder.add(clazz);
- }
- }
- } catch (IOException e) {
- throw new RuntimeException("Failed to parse dex in " + file, e);
- } catch (ClassNotFoundException e) {
- throw new RuntimeException("Error while loading class in " + file, e);
- }
- }
- return builder.build();
- }
-
- private String[] getBootJarPaths() {
- return System.getProperty("java.boot.class.path").split(":");
- }
-}
\ No newline at end of file
diff --git a/tests/signature/api-check/src/android/signature/cts/api/HiddenApiTest.java b/tests/signature/api-check/src/android/signature/cts/api/HiddenApiTest.java
new file mode 100644
index 0000000..e1da5ac
--- /dev/null
+++ b/tests/signature/api-check/src/android/signature/cts/api/HiddenApiTest.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.signature.cts.api;
+
+import android.os.Bundle;
+import android.signature.cts.DexApiDocumentParser;
+import android.signature.cts.DexApiDocumentParser.DexField;
+import android.signature.cts.DexApiDocumentParser.DexMember;
+import android.signature.cts.DexApiDocumentParser.DexMethod;
+import android.signature.cts.FailureType;
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Stream;
+import java.text.ParseException;
+
+import static android.signature.cts.CurrentApi.API_FILE_DIRECTORY;
+
+/**
+ * Checks that it is not possible to access hidden APIs.
+ */
+public class HiddenApiTest extends AbstractApiTest {
+
+ private String[] hiddenApiFiles;
+
+ @Override
+ protected void initializeFromArgs(Bundle instrumentationArgs) throws Exception {
+ hiddenApiFiles = getCommaSeparatedList(instrumentationArgs, "hidden-api-files");
+ }
+
+ /**
+ * Tests that the device does not expose APIs on the provided lists of
+ * DEX signatures.
+ *
+ * Will check the entire API, and then report the complete list of failures
+ */
+ public void testSignature() {
+ System.loadLibrary("cts_hiddenapi");
+ runWithTestResultObserver(resultObserver -> {
+ parseDexApiFilesAsStream(hiddenApiFiles).forEach(dexMember -> {
+ checkSingleMember(dexMember, resultObserver);
+ });
+ });
+ }
+
+ /**
+ * Check that a DexMember cannot be discovered with reflection or JNI, and
+ * record results in the result
+ */
+ private void checkSingleMember(DexMember dexMember, TestResultObserver resultObserver) {
+ Class<?> klass = findClass(dexMember);
+ if (klass == null) {
+ // Class not found. Therefore its members are not visible.
+ return;
+ }
+
+ if (dexMember instanceof DexField) {
+ if (hasMatchingField_Reflection(klass, (DexField) dexMember)) {
+ resultObserver.notifyFailure(
+ FailureType.EXTRA_FIELD,
+ dexMember.toString(),
+ "Hidden field accessible through reflection");
+ }
+ if (hasMatchingField_JNI(klass, (DexField) dexMember)) {
+ resultObserver.notifyFailure(
+ FailureType.EXTRA_FIELD,
+ dexMember.toString(),
+ "Hidden field accessible through JNI");
+ }
+ } else if (dexMember instanceof DexMethod) {
+ if (hasMatchingMethod_Reflection(klass, (DexMethod) dexMember)) {
+ resultObserver.notifyFailure(
+ FailureType.EXTRA_METHOD,
+ dexMember.toString(),
+ "Hidden method accessible through reflection");
+ }
+ if (hasMatchingMethod_JNI(klass, (DexMethod) dexMember)) {
+ resultObserver.notifyFailure(
+ FailureType.EXTRA_METHOD,
+ dexMember.toString(),
+ "Hidden method accessible through JNI");
+ }
+ } else {
+ throw new IllegalStateException("Unexpected type of dex member");
+ }
+ }
+
+ private boolean typesMatch(Class<?>[] classes, List<String> typeNames) {
+ if (classes.length != typeNames.size()) {
+ return false;
+ }
+ for (int i = 0; i < classes.length; ++i) {
+ if (!classes[i].getTypeName().equals(typeNames.get(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private Class<?> findClass(DexMember dexMember) {
+ Class<?> klass = null;
+ try {
+ return Class.forName(dexMember.getJavaClassName());
+ } catch (ClassNotFoundException ex) {
+ return null;
+ }
+ }
+
+ private static boolean hasMatchingField_Reflection(Class<?> klass, DexField dexField) {
+ try {
+ klass.getDeclaredField(dexField.getName());
+ return true;
+ } catch (NoSuchFieldException ex) {
+ return false;
+ }
+ }
+
+ private static boolean hasMatchingField_JNI(Class<?> klass, DexField dexField) {
+ try {
+ getField_JNI(klass, dexField.getName(), dexField.getDexType());
+ return true;
+ } catch (NoSuchFieldError ex) {
+ }
+ try {
+ getStaticField_JNI(klass, dexField.getName(), dexField.getDexType());
+ return true;
+ } catch (NoSuchFieldError ex) {
+ }
+ return false;
+ }
+
+ private boolean hasMatchingMethod_Reflection(Class<?> klass, DexMethod dexMethod) {
+ List<String> methodParams = dexMethod.getJavaParameterTypes();
+
+ if (dexMethod.isConstructor()) {
+ for (Constructor constructor : klass.getDeclaredConstructors()) {
+ if (typesMatch(constructor.getParameterTypes(), methodParams)) {
+ return true;
+ }
+ }
+ } else {
+ for (Method method : klass.getDeclaredMethods()) {
+ if (method.getName().equals(dexMethod.getName())
+ && typesMatch(method.getParameterTypes(), methodParams)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private static boolean hasMatchingMethod_JNI(Class<?> klass, DexMethod dexMethod) {
+ try {
+ getMethod_JNI(klass, dexMethod.getName(), dexMethod.getDexSignature());
+ return true;
+ } catch (NoSuchMethodError ex) {
+ }
+ if (!dexMethod.isConstructor()) {
+ try {
+ getStaticMethod_JNI(klass, dexMethod.getName(), dexMethod.getDexSignature());
+ return true;
+ } catch (NoSuchMethodError ex) {
+ }
+ }
+ return false;
+ }
+
+ private static Stream<DexMember> parseDexApiFilesAsStream(String[] apiFiles) {
+ DexApiDocumentParser dexApiDocumentParser = new DexApiDocumentParser();
+ return Stream.of(apiFiles)
+ .map(name -> new File(API_FILE_DIRECTORY + "/" + name))
+ .flatMap(file -> readFile(file))
+ .flatMap(stream -> dexApiDocumentParser.parseAsStream(stream));
+ }
+
+ private static native boolean getField_JNI(Class<?> klass, String name, String type);
+ private static native boolean getStaticField_JNI(Class<?> klass, String name, String type);
+ private static native boolean getMethod_JNI(Class<?> klass, String name, String signature);
+ private static native boolean getStaticMethod_JNI(Class<?> klass, String name,
+ String signature);
+}
diff --git a/tests/signature/api-check/src/android/signature/cts/api/AbstractApiTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java
similarity index 100%
rename from tests/signature/api-check/src/android/signature/cts/api/AbstractApiTest.java
rename to tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java
diff --git a/tests/signature/api-check/src/android/signature/cts/api/AnnotationTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/AnnotationTest.java
similarity index 100%
rename from tests/signature/api-check/src/android/signature/cts/api/AnnotationTest.java
rename to tests/signature/api-check/src/java/android/signature/cts/api/AnnotationTest.java
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/BootClassPathClassesProvider.java b/tests/signature/api-check/src/java/android/signature/cts/api/BootClassPathClassesProvider.java
new file mode 100644
index 0000000..95f46df
--- /dev/null
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/BootClassPathClassesProvider.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.signature.cts.api;
+
+import android.os.Debug;
+import android.signature.cts.ClassProvider;
+import dalvik.system.BaseDexClassLoader;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+@SuppressWarnings("deprecation")
+public class BootClassPathClassesProvider extends ClassProvider {
+ private static boolean sJvmtiAttached = false;
+
+ @Override
+ public Stream<Class<?>> getAllClasses() {
+ if (!sJvmtiAttached) {
+ try {
+ Debug.attachJvmtiAgent(copyAgentToFile("classdescriptors").getAbsolutePath(), null,
+ BootClassPathClassesProvider.class.getClassLoader());
+ sJvmtiAttached = true;
+ initialize();
+ } catch (Exception e) {
+ throw new RuntimeException("Error while attaching JVMTI agent", e);
+ }
+ }
+ return Arrays.stream(getClassloaderDescriptors(Object.class.getClassLoader()))
+ .map(descriptor -> {
+ System.err.println("Class name = " + descriptor);
+ String classname = descriptor.replace('/', '.');
+ // omit L and ; at the front and at the end
+ return classname.substring(1, classname.length() - 1);
+ })
+ .map(classname -> {
+ try {
+ return getClass(classname);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Cannot load " + classname, e);
+ }
+ });
+ }
+
+ private static File copyAgentToFile(String lib) throws Exception {
+ ClassLoader cl = BootClassPathClassesProvider.class.getClassLoader();
+
+ File copiedAgent = File.createTempFile("agent", ".so");
+ try (InputStream is = new FileInputStream(
+ ((BaseDexClassLoader) cl).findLibrary(lib))) {
+ try (OutputStream os = new FileOutputStream(copiedAgent)) {
+ byte[] buffer = new byte[64 * 1024];
+
+ while (true) {
+ int numRead = is.read(buffer);
+ if (numRead == -1) {
+ break;
+ }
+ os.write(buffer, 0, numRead);
+ }
+ }
+ }
+ return copiedAgent;
+ }
+
+ private static native void initialize();
+
+ private static native String[] getClassloaderDescriptors(ClassLoader loader);
+}
diff --git a/tests/signature/api-check/src/android/signature/cts/api/SignatureTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java
similarity index 100%
rename from tests/signature/api-check/src/android/signature/cts/api/SignatureTest.java
rename to tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java
diff --git a/tests/signature/api-check/src/android/signature/cts/api/TestResultObserver.java b/tests/signature/api-check/src/java/android/signature/cts/api/TestResultObserver.java
similarity index 100%
rename from tests/signature/api-check/src/android/signature/cts/api/TestResultObserver.java
rename to tests/signature/api-check/src/java/android/signature/cts/api/TestResultObserver.java
diff --git a/tests/signature/api-check/src/jni/classdescriptors.cpp b/tests/signature/api-check/src/jni/classdescriptors.cpp
new file mode 100644
index 0000000..3da66f1
--- /dev/null
+++ b/tests/signature/api-check/src/jni/classdescriptors.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
+#include <jvmti.h>
+
+#include <string.h>
+
+namespace android {
+namespace signature {
+namespace cts {
+namespace api {
+
+static jvmtiEnv* jvmti_env;
+static jvmtiError (*get_descriptor_list)(jvmtiEnv* env, jobject loader, jint* cnt, char*** descs);
+
+template <typename T>
+static void Dealloc(T* t) {
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(t));
+}
+
+template <typename T, typename ...Rest>
+static void Dealloc(T* t, Rest... rs) {
+ Dealloc(t);
+ Dealloc(rs...);
+}
+
+static void DeallocParams(jvmtiParamInfo* params, jint n_params) {
+ for (jint i = 0; i < n_params; i++) {
+ Dealloc(params[i].name);
+ }
+}
+
+static void Cleanup(char** data, jint cnt) {
+ for (jint i = 0; i < cnt; i++) {
+ Dealloc(data[i]);
+ }
+ Dealloc(data);
+}
+
+extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm,
+ __attribute__((unused)) char* options,
+ __attribute__((unused)) void* reserved) {
+ jint jvmError = vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_2);
+ if (jvmError != JNI_OK) {
+ return jvmError;
+ }
+ return JVMTI_ERROR_NONE;
+}
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_android_signature_cts_api_BootClassPathClassesProvider_getClassloaderDescriptors(
+ JNIEnv* env, jclass, jobject loader) {
+ if (get_descriptor_list == nullptr) {
+ jclass rt_exception = env->FindClass("java/lang/RuntimeException");
+ env->ThrowNew(rt_exception, "get_class_loader_class_descriptor extension is not ready.");
+ return nullptr;
+ }
+ char** classes = nullptr;
+ jint cnt = -1;
+ jvmtiError error = get_descriptor_list(jvmti_env, loader, &cnt, &classes);
+ if (error != JVMTI_ERROR_NONE) {
+ jclass rt_exception = env->FindClass("java/lang/RuntimeException");
+ env->ThrowNew(rt_exception, "Error while executing get_class_loader_class_descriptor.");
+ return nullptr;
+ }
+
+ jobjectArray arr = env->NewObjectArray(cnt, env->FindClass("java/lang/String"), nullptr);
+ if (env->ExceptionCheck()) {
+ Cleanup(classes, cnt);
+ return nullptr;
+ }
+
+ for (jint i = 0; i < cnt; i++) {
+ env->SetObjectArrayElement(arr, i, env->NewStringUTF(classes[i]));
+ if (env->ExceptionCheck()) {
+ Cleanup(classes, cnt);
+ return nullptr;
+ }
+ }
+ Cleanup(classes, cnt);
+ return arr;
+}
+
+extern "C" JNIEXPORT void JNICALL Java_android_signature_cts_api_BootClassPathClassesProvider_initialize(JNIEnv* env, jclass) {
+ jint functionInfosCount = 0;
+ jvmtiExtensionFunctionInfo* functionInfos = nullptr;
+
+ jvmtiError err = jvmti_env->GetExtensionFunctions(&functionInfosCount, &functionInfos);
+ if (err != JVMTI_ERROR_NONE) {
+ jclass rt_exception = env->FindClass("java/lang/RuntimeException");
+ env->ThrowNew(rt_exception, "Failed to get JVMTI extension APIs");
+ return;
+ }
+
+ for (jint i = 0; i < functionInfosCount; i++) {
+ jvmtiExtensionFunctionInfo* curInfo = &functionInfos[i];
+ if (strcmp("com.android.art.class.get_class_loader_class_descriptors", curInfo->id) == 0) {
+ get_descriptor_list = reinterpret_cast<jvmtiError (*)(jvmtiEnv*, jobject, jint*, char***)>(curInfo->func);
+ }
+ DeallocParams(curInfo->params, curInfo->param_count);
+ Dealloc(curInfo->id, curInfo->short_description, curInfo->params, curInfo->errors);
+ }
+ Dealloc(functionInfos);
+
+ if (get_descriptor_list == nullptr) {
+ jclass rt_exception = env->FindClass("java/lang/RuntimeException");
+ env->ThrowNew(rt_exception, "Failed to find get_class_loader_class_descriptors extension");
+ return;
+ }
+}
+
+} // namespace api
+} // namespace cts
+} // namespace signature
+} // namespace android
diff --git a/tests/signature/api-check/system-annotation/AndroidManifest.xml b/tests/signature/api-check/system-annotation/AndroidManifest.xml
index 55318ed..7753fb9 100644
--- a/tests/signature/api-check/system-annotation/AndroidManifest.xml
+++ b/tests/signature/api-check/system-annotation/AndroidManifest.xml
@@ -20,7 +20,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
- <application/>
+ <application android:debuggable="true"/>
<instrumentation android:name="repackaged.android.test.InstrumentationTestRunner"
android:targetPackage="android.signature.cts.api.system_annotation"
diff --git a/tests/signature/api-check/system-api/AndroidTest.xml b/tests/signature/api-check/system-api/AndroidTest.xml
index 23254ae..5f70478 100644
--- a/tests/signature/api-check/system-api/AndroidTest.xml
+++ b/tests/signature/api-check/system-api/AndroidTest.xml
@@ -32,7 +32,7 @@
<option name="test-file-name" value="CtsSystemApiSignatureTestCases.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.signature.cts.api.systemt" />
+ <option name="package" value="android.signature.cts.api.system" />
<option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
<option name="class" value="android.signature.cts.api.SignatureTest" />
<option name="instrumentation-arg" key="base-api-files" value="current.api" />
diff --git a/tests/signature/runSignatureTests.sh b/tests/signature/runSignatureTests.sh
index 8e2204d..1350297 100755
--- a/tests/signature/runSignatureTests.sh
+++ b/tests/signature/runSignatureTests.sh
@@ -16,9 +16,14 @@
CtsAndroidTestMockCurrentApiSignatureTestCases
CtsAndroidTestRunnerCurrentApiSignatureTestCases
CtsAndroidTestBase27ApiSignatureTestCases
+
+CtsApacheHttpLegacy27ApiSignatureTestCases
CtsApacheHttpLegacyCurrentApiSignatureTestCases
+CtsApacheHttpLegacyUsesLibraryApiSignatureTestCases
CtsSystemApiAnnotationTestCases
+
+CtsHiddenApiDiscoveryTestCases
"
else
PACKAGES=${1+"$@"}
diff --git a/tests/signature/src/android/signature/cts/DexApiDocumentParser.java b/tests/signature/src/android/signature/cts/DexApiDocumentParser.java
new file mode 100644
index 0000000..7cb60fb
--- /dev/null
+++ b/tests/signature/src/android/signature/cts/DexApiDocumentParser.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.signature.cts;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import java.text.ParseException;
+
+/**
+ * Parses an API definition given as a text file with DEX signatures of class
+ * members. Constructs a {@link DexApiDocumentParser.DexMember} for every class
+ * member.
+ *
+ * <p>The definition file is converted into a {@link Stream} of
+ * {@link DexApiDocumentParser.DexMember}.
+ */
+public class DexApiDocumentParser {
+
+ public Stream<DexMember> parseAsStream(InputStream inputStream) {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+ return StreamSupport.stream(new DexApiSpliterator(reader), false);
+ }
+
+ private static class DexApiSpliterator implements Spliterator<DexMember> {
+ private final BufferedReader mReader;
+ private int mLineNum;
+
+ private static final Pattern REGEX_CLASS = Pattern.compile("^L[^->]*;$");
+ private static final Pattern REGEX_FIELD = Pattern.compile("^(L[^->]*;)->(.*):(.*)$");
+ private static final Pattern REGEX_METHOD =
+ Pattern.compile("^(L[^->]*;)->(.*)\\((.*)\\)(.*)$");
+
+ DexApiSpliterator(BufferedReader reader) {
+ mReader = reader;
+ mLineNum = 0;
+ }
+
+ @Override
+ public boolean tryAdvance(Consumer<? super DexMember> action) {
+ DexMember nextMember = null;
+ try {
+ nextMember = next();
+ } catch (IOException | ParseException ex) {
+ throw new RuntimeException(ex);
+ }
+ if (nextMember == null) {
+ return false;
+ }
+ action.accept(nextMember);
+ return true;
+ }
+
+ @Override
+ public Spliterator<DexMember> trySplit() {
+ return null;
+ }
+
+ @Override
+ public long estimateSize() {
+ return Long.MAX_VALUE;
+ }
+
+ @Override
+ public int characteristics() {
+ return ORDERED | DISTINCT | NONNULL | IMMUTABLE;
+ }
+
+ /**
+ * Parses lines of DEX signatures from `mReader`. The following three
+ * line formats are supported:
+ * 1) [class descriptor]
+ * - e.g. Lcom/example/MyClass;
+ * - these lines are ignored
+ * 2) [class descriptor]->[field name]:[field type]
+ * - e.g. Lcom/example/MyClass;->myField:I
+ * - these lines are parsed as field signatures
+ * 3) [class descriptor]->[method name]([method parameter types])[method return type]
+ * - e.g. Lcom/example/MyClass;->myMethod(Lfoo;Lbar;)J
+ * - these lines are parsed as method signatures
+ */
+ private DexMember next() throws IOException, ParseException {
+ while (true) {
+ // Read the next line from the input.
+ String line = mReader.readLine();
+ if (line == null) {
+ // End of stream.
+ return null;
+ }
+
+ // Increment the line number.
+ mLineNum = mLineNum + 1;
+
+ // Match line against regex patterns.
+ Matcher matchClass = REGEX_CLASS.matcher(line);
+ Matcher matchField = REGEX_FIELD.matcher(line);
+ Matcher matchMethod = REGEX_METHOD.matcher(line);
+
+ // Check that *exactly* one pattern matches.
+ int matchCount = (matchClass.matches() ? 1 : 0) + (matchField.matches() ? 1 : 0) +
+ (matchMethod.matches() ? 1 : 0);
+ if (matchCount == 0) {
+ throw new ParseException("Could not parse: \"" + line + "\"", mLineNum);
+ } else if (matchCount > 1) {
+ throw new ParseException("Ambiguous parse: \"" + line + "\"", mLineNum);
+ }
+
+ // Extract information from the line.
+ if (matchClass.matches()) {
+ // We ignore lines describing a class because classes are
+ // not being hidden.
+ } else if (matchField.matches()) {
+ return new DexField(
+ matchField.group(1), matchField.group(2), matchField.group(3));
+ } else if (matchMethod.matches()) {
+ return new DexMethod(
+ matchMethod.group(1),matchMethod.group(2),
+ parseDexTypeList(matchMethod.group(3)), matchMethod.group(4));
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+ }
+
+ private List<String> parseDexTypeList(String typeSequence) throws ParseException {
+ List<String> list = new ArrayList<String>();
+ while (!typeSequence.isEmpty()) {
+ String type = firstDexTypeFromList(typeSequence);
+ list.add(type);
+ typeSequence = typeSequence.substring(type.length());
+ }
+ return list;
+ }
+
+ /**
+ * Returns the first dex type in `typeList` or throws a ParserException
+ * if a dex type is not recognized. The input is not changed.
+ */
+ private String firstDexTypeFromList(String typeList) throws ParseException {
+ String dexDimension = "";
+ while (typeList.startsWith("[")) {
+ dexDimension += "[";
+ typeList = typeList.substring(1);
+ }
+
+ String type = null;
+ if (typeList.startsWith("V")
+ || typeList.startsWith("Z")
+ || typeList.startsWith("B")
+ || typeList.startsWith("C")
+ || typeList.startsWith("S")
+ || typeList.startsWith("I")
+ || typeList.startsWith("J")
+ || typeList.startsWith("F")
+ || typeList.startsWith("D")) {
+ type = typeList.substring(0, 1);
+ } else if (typeList.startsWith("L") && typeList.indexOf(";") > 0) {
+ type = typeList.substring(0, typeList.indexOf(";") + 1);
+ } else {
+ throw new ParseException(
+ "Unexpected dex type in \"" + typeList + "\"", mLineNum);
+ }
+
+ return dexDimension + type;
+ }
+ }
+
+ /**
+ * Represents one class member parsed from the reader of dex signatures.
+ */
+ public static abstract class DexMember {
+ private final String mName;
+ private final String mClassDescriptor;
+ private final String mType;
+
+ protected DexMember(String className, String name, String type) {
+ mName = name;
+ mClassDescriptor = className;
+ mType = type;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public String getDexClassName() {
+ return mClassDescriptor;
+ }
+
+ public String getJavaClassName() {
+ return dexToJavaType(mClassDescriptor);
+ }
+
+ public String getDexType() {
+ return mType;
+ }
+
+ public String getJavaType() {
+ return dexToJavaType(mType);
+ }
+
+ /**
+ * Converts `type` to a Java type.
+ */
+ protected static String dexToJavaType(String type) {
+ String javaDimension = "";
+ while (type.startsWith("[")) {
+ javaDimension += "[]";
+ type = type.substring(1);
+ }
+
+ String javaType = null;
+ if ("V".equals(type)) {
+ javaType = "void";
+ } else if ("Z".equals(type)) {
+ javaType = "boolean";
+ } else if ("B".equals(type)) {
+ javaType = "byte";
+ } else if ("C".equals(type)) {
+ javaType = "char";
+ } else if ("S".equals(type)) {
+ javaType = "short";
+ } else if ("I".equals(type)) {
+ javaType = "int";
+ } else if ("J".equals(type)) {
+ javaType = "long";
+ } else if ("F".equals(type)) {
+ javaType = "float";
+ } else if ("D".equals(type)) {
+ javaType = "double";
+ } else if (type.startsWith("L") && type.endsWith(";")) {
+ javaType = type.substring(1, type.length() - 1).replace('/', '.');
+ } else {
+ throw new IllegalStateException("Unexpected type " + type);
+ }
+
+ return javaType + javaDimension;
+ }
+ }
+
+ public static class DexField extends DexMember {
+ public DexField(String className, String name, String type) {
+ super(className, name, type);
+ }
+
+ @Override
+ public String toString() {
+ return getJavaType() + " " + getJavaClassName() + "." + getName();
+ }
+ }
+
+ public static class DexMethod extends DexMember {
+ private final List<String> mParamTypeList;
+
+ public DexMethod(String className, String name, List<String> paramTypeList,
+ String dexReturnType) {
+ super(className, name, dexReturnType);
+ mParamTypeList = paramTypeList;
+ }
+
+ public String getDexSignature() {
+ return "(" + String.join("", mParamTypeList) + ")" + getDexType();
+ }
+
+ public List<String> getJavaParameterTypes() {
+ return mParamTypeList
+ .stream()
+ .map(DexMember::dexToJavaType)
+ .collect(Collectors.toList());
+ }
+
+ public boolean isConstructor() {
+ return "<init>".equals(getName()) && "V".equals(getDexType());
+ }
+
+ @Override
+ public String toString() {
+ return getJavaType() + " " + getJavaClassName() + "." + getName()
+ + "(" + String.join(", ", getJavaParameterTypes()) + ")";
+ }
+ }
+}
diff --git a/tests/tests/alarmclock/service/src/android/alarmclock/service/MainInteractionSession.java b/tests/tests/alarmclock/service/src/android/alarmclock/service/MainInteractionSession.java
index 547203e..99c0b6f 100644
--- a/tests/tests/alarmclock/service/src/android/alarmclock/service/MainInteractionSession.java
+++ b/tests/tests/alarmclock/service/src/android/alarmclock/service/MainInteractionSession.java
@@ -90,7 +90,7 @@
case SET_TIMER_FOR_DISMISSAL:
intent = new Intent(AlarmClock.ACTION_SET_TIMER);
- intent.putExtra(AlarmClock.EXTRA_LENGTH, 10);
+ intent.putExtra(AlarmClock.EXTRA_LENGTH, 1);
break;
case SNOOZE_ALARM:
diff --git a/tests/tests/alarmclock/src/android/alarmclock/cts/DismissTimerTest.java b/tests/tests/alarmclock/src/android/alarmclock/cts/DismissTimerTest.java
index dff8835..5951e65 100644
--- a/tests/tests/alarmclock/src/android/alarmclock/cts/DismissTimerTest.java
+++ b/tests/tests/alarmclock/src/android/alarmclock/cts/DismissTimerTest.java
@@ -1,11 +1,38 @@
package android.alarmclock.cts;
import android.alarmclock.common.Utils;
+import android.content.Context;
+import android.media.AudioManager;
public class DismissTimerTest extends AlarmClockTestBase {
+ private int mSavedVolume;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // The timer may ring between expiration and dismissal; silence this.
+ final AudioManager audioManager = (AudioManager) getInstrumentation().getTargetContext()
+ .getSystemService(Context.AUDIO_SERVICE);
+ mSavedVolume = audioManager.getStreamVolume(AudioManager.STREAM_ALARM);
+ audioManager.setStreamVolume(AudioManager.STREAM_ALARM, 0, 0);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ final AudioManager audioManager = (AudioManager) getInstrumentation().getTargetContext()
+ .getSystemService(Context.AUDIO_SERVICE);
+ audioManager.setStreamVolume(AudioManager.STREAM_ALARM, mSavedVolume, 0);
+ }
+
public void testAll() throws Exception {
assertEquals(Utils.COMPLETION_RESULT, runTest(Utils.TestcaseType.SET_TIMER_FOR_DISMISSAL));
+ try {
+ Thread.sleep(1500);
+ } catch (InterruptedException ignored) {
+ }
assertEquals(Utils.COMPLETION_RESULT, runTest(Utils.TestcaseType.DISMISS_TIMER));
}
}
diff --git a/tests/tests/app.usage/Android.mk b/tests/tests/app.usage/Android.mk
index fa5c60e..3da4dd0 100644
--- a/tests/tests/app.usage/Android.mk
+++ b/tests/tests/app.usage/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsUsageStatsTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
# don't include this package in any target
LOCAL_MODULE_TAGS := optional
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
index 110534f..44beedb 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
@@ -16,7 +16,9 @@
package android.app.usage.cts;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import android.app.Activity;
import android.app.AppOpsManager;
@@ -38,7 +40,6 @@
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.Until;
-import android.test.InstrumentationTestCase;
import android.util.SparseLongArray;
import org.junit.Before;
@@ -202,13 +203,23 @@
UsageEvents.Event event = new UsageEvents.Event();
assertTrue(events.getNextEvent(event));
if (event.mEventType == UsageEvents.Event.STANDBY_BUCKET_CHANGED) {
- found |= event.mBucket == UsageStatsManager.STANDBY_BUCKET_RARE;
+ found |= event.getStandbyBucket() == UsageStatsManager.STANDBY_BUCKET_RARE;
}
}
assertTrue(found);
}
+ @Test
+ public void testGetAppStandbyBuckets() throws Exception {
+ mUiDevice.executeShellCommand("am set-standby-bucket " + mTargetPackage + " rare");
+ Map<String, Integer> bucketMap = mUsageStatsManager.getAppStandbyBuckets();
+ assertTrue("No bucket data returned", bucketMap.size() > 0);
+ final int bucket = bucketMap.getOrDefault(mTargetPackage, -1);
+ assertEquals("Incorrect bucket returned for " + mTargetPackage, bucket,
+ UsageStatsManager.STANDBY_BUCKET_RARE);
+ }
+
/**
* We can't run this test because we are unable to change the system time.
* It would be nice to add a shell command or other to allow the shell user
diff --git a/tests/tests/app/Android.mk b/tests/tests/app/Android.mk
index d087058..a77c038 100644
--- a/tests/tests/app/Android.mk
+++ b/tests/tests/app/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsAndroidAppTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
# don't include this package in any target
LOCAL_MODULE_TAGS := optional
diff --git a/tests/tests/appwidget/Android.mk b/tests/tests/appwidget/Android.mk
index da7194b..b6243fc 100644
--- a/tests/tests/appwidget/Android.mk
+++ b/tests/tests/appwidget/Android.mk
@@ -24,6 +24,7 @@
$(call all-java-files-under, common/src)
LOCAL_PACKAGE_NAME := CtsAppWidgetTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_STATIC_JAVA_LIBRARIES := \
mockito-target-minus-junit4 \
diff --git a/tests/tests/carrierapi/Android.mk b/tests/tests/carrierapi/Android.mk
index 8a64870..3adac15 100644
--- a/tests/tests/carrierapi/Android.mk
+++ b/tests/tests/carrierapi/Android.mk
@@ -30,6 +30,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsCarrierApiTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/tests/tests/content/Android.mk b/tests/tests/content/Android.mk
index 0bbbb02..39587eb 100644
--- a/tests/tests/content/Android.mk
+++ b/tests/tests/content/Android.mk
@@ -59,6 +59,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_MULTILIB := both
LOCAL_PACKAGE_NAME := CtsContentTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/tests/tests/content/CtsSyncAccountAccessOtherCertTests/Android.mk b/tests/tests/content/CtsSyncAccountAccessOtherCertTests/Android.mk
index 14dd2c9..01df0b5 100644
--- a/tests/tests/content/CtsSyncAccountAccessOtherCertTests/Android.mk
+++ b/tests/tests/content/CtsSyncAccountAccessOtherCertTests/Android.mk
@@ -28,6 +28,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsSyncAccountAccessOtherCertTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
diff --git a/tests/tests/content/SyncAccountAccessStubs/Android.mk b/tests/tests/content/SyncAccountAccessStubs/Android.mk
index c0b6fa2..9f015a3 100644
--- a/tests/tests/content/SyncAccountAccessStubs/Android.mk
+++ b/tests/tests/content/SyncAccountAccessStubs/Android.mk
@@ -23,6 +23,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsSyncAccountAccessStubs
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
index 1ba9753..2695fac 100644
--- a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
+++ b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
@@ -181,17 +181,6 @@
}
/**
- * Test ACTION_SHOW_ASSISTED_DIALING_SETTINGS, it will display the assisted dialing preferences.
- */
- public void testShowAssistedDialingSettings() {
- PackageManager packageManager = mContext.getPackageManager();
- if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
- Intent intent = new Intent(TelecomManager.ACTION_SHOW_ASSISTED_DIALING_SETTINGS);
- assertCanBeHandled(intent);
- }
- }
-
- /**
* Test ACTION_SHOW_CALL_SETTINGS, it will display the call preferences.
*/
public void testShowCallSettings() {
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
index 5140e69..edc7924 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
@@ -45,12 +45,12 @@
public class PackageManagerTest extends AndroidTestCase {
private PackageManager mPackageManager;
private static final String PACKAGE_NAME = "android.content.cts";
- private static final String CONTENT_PKG_NAME = "android.content.cts";
private static final String ACTIVITY_ACTION_NAME = "android.intent.action.PMTEST";
private static final String MAIN_ACTION_NAME = "android.intent.action.MAIN";
private static final String SERVICE_ACTION_NAME =
"android.content.pm.cts.activity.PMTEST_SERVICE";
- private static final String PERMISSION_NAME = "android.permission.INTERNET";
+ private static final String GRANTED_PERMISSION_NAME = "android.permission.INTERNET";
+ private static final String NOT_GRANTED_PERMISSION_NAME = "android.permission.HARDWARE_TEST";
private static final String ACTIVITY_NAME = "android.content.pm.cts.TestPmActivity";
private static final String SERVICE_NAME = "android.content.pm.cts.TestPmService";
private static final String RECEIVER_NAME = "android.content.pm.cts.PmTestReceiver";
@@ -230,7 +230,8 @@
assertTrue(mPackageManager.getPackageGids(PACKAGE_NAME).length > 0);
// Test getPermissionInfo
- assertEquals(PERMISSION_NAME, mPackageManager.getPermissionInfo(PERMISSION_NAME, 0).name);
+ assertEquals(GRANTED_PERMISSION_NAME,
+ mPackageManager.getPermissionInfo(GRANTED_PERMISSION_NAME, 0).name);
// Test getPermissionGroupInfo
assertEquals(PERMISSIONGROUP_NAME, mPackageManager.getPermissionGroupInfo(
@@ -388,17 +389,6 @@
mPackageManager.getComponentEnabledSetting(componentName));
}
- public void testOpPermission() {
- PermissionInfo permissionInfo = new PermissionInfo();
- String permissionName = "android.content.cts.permission.TEST_DYNAMIC.ADD";
- permissionInfo.name = permissionName;
- permissionInfo.labelRes = R.string.permlab_testDynamic;
- permissionInfo.nonLocalizedLabel = "Test Tree";
-
- // TODO: Bug ID 1561181.
- // Can't add permission in dynamic way
- }
-
public void testGetIcon() throws NameNotFoundException {
assertNotNull(mPackageManager.getApplicationIcon(PACKAGE_NAME));
assertNotNull(mPackageManager.getApplicationIcon(mPackageManager.getApplicationInfo(
@@ -415,11 +405,41 @@
assertNotNull(mPackageManager.getDrawable(PACKAGE_NAME, iconRes, appInfo));
}
- public void testCheckMethods() {
+ public void testCheckSignaturesMatch() {
+ // Compare the signature of this package to another package installed by this test suite
+ // (see AndroidTest.xml). Their signatures must match.
assertEquals(PackageManager.SIGNATURE_MATCH, mPackageManager.checkSignatures(PACKAGE_NAME,
- CONTENT_PKG_NAME));
+ "com.android.cts.stub"));
+ // This package's signature should match its own signature.
+ assertEquals(PackageManager.SIGNATURE_MATCH, mPackageManager.checkSignatures(PACKAGE_NAME,
+ PACKAGE_NAME));
+ }
+
+ public void testCheckSignaturesNoMatch() {
+ // This test package's signature shouldn't match the system's signature.
+ assertEquals(PackageManager.SIGNATURE_NO_MATCH, mPackageManager.checkSignatures(
+ PACKAGE_NAME, "android"));
+ }
+
+ public void testCheckSignaturesUnknownPackage() {
+ assertEquals(PackageManager.SIGNATURE_UNKNOWN_PACKAGE, mPackageManager.checkSignatures(
+ PACKAGE_NAME, "this.package.does.not.exist"));
+ }
+
+ public void testCheckPermissionGranted() {
assertEquals(PackageManager.PERMISSION_GRANTED,
- mPackageManager.checkPermission(PERMISSION_NAME, PACKAGE_NAME));
+ mPackageManager.checkPermission(GRANTED_PERMISSION_NAME, PACKAGE_NAME));
+ }
+
+ public void testCheckPermissionNotGranted() {
+ assertEquals(PackageManager.PERMISSION_DENIED,
+ mPackageManager.checkPermission(NOT_GRANTED_PERMISSION_NAME, PACKAGE_NAME));
+ }
+
+ public void testCheckPermissionSystem() {
+ // Everything will be granted to the system.
+ assertEquals(PackageManager.PERMISSION_GRANTED,
+ mPackageManager.checkPermission(NOT_GRANTED_PERMISSION_NAME, "android"));
}
public void testResolveMethods() {
diff --git a/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java b/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
index 78ce89a..144bdde 100644
--- a/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
+++ b/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
@@ -67,6 +67,7 @@
allowedDensities.add(DisplayMetrics.DENSITY_360);
allowedDensities.add(DisplayMetrics.DENSITY_400);
allowedDensities.add(DisplayMetrics.DENSITY_420);
+ allowedDensities.add(DisplayMetrics.DENSITY_440);
allowedDensities.add(DisplayMetrics.DENSITY_XXHIGH);
allowedDensities.add(DisplayMetrics.DENSITY_560);
allowedDensities.add(DisplayMetrics.DENSITY_XXXHIGH);
diff --git a/tests/tests/dreams/Android.mk b/tests/tests/dreams/Android.mk
index 11e4b21..f1a31d8 100644
--- a/tests/tests/dreams/Android.mk
+++ b/tests/tests/dreams/Android.mk
@@ -32,6 +32,7 @@
# Need access to ServiceManager - see b/13307221
#LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/tests/tests/graphics/res/drawable/animatedimagedrawable_automirrored.xml b/tests/tests/graphics/res/drawable/animatedimagedrawable_automirrored.xml
new file mode 100644
index 0000000..3d5b0cf
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/animatedimagedrawable_automirrored.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<animated-image xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/animated"
+ android:autoMirrored="true"
+ />
+
diff --git a/tests/tests/graphics/res/drawable/animatedimagedrawable_nosrc.xml b/tests/tests/graphics/res/drawable/animatedimagedrawable_nosrc.xml
new file mode 100644
index 0000000..0f7ac8f
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/animatedimagedrawable_nosrc.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<animated-image xmlns:android="http://schemas.android.com/apk/res/android"
+ />
+
diff --git a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
index 0d70947..1cc86a3 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
@@ -18,7 +18,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -39,7 +38,6 @@
import android.graphics.Shader;
import android.graphics.Typeface;
import android.graphics.Xfermode;
-import android.graphics.fonts.FontVariationAxis;
import android.os.LocaleList;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
@@ -1642,4 +1640,82 @@
p.setElegantTextHeight(false);
assertFalse(p.isElegantTextHeight());
}
+
+ @Test
+ public void testEqualsForTextMeasurment() {
+ Paint p1 = new Paint();
+ Paint p2 = new Paint();
+
+ assertTrue(p1.equalsForTextMeasurement(p2));
+ }
+
+ @Test
+ public void testEqualsForTextMeasurment_textSize() {
+ Paint p1 = new Paint();
+ Paint p2 = new Paint();
+
+ p1.setTextSize(p2.getTextSize() * 2.0f);
+ assertFalse(p1.equalsForTextMeasurement(p2));
+ p1.setTextSize(p2.getTextSize());
+ assertTrue(p1.equalsForTextMeasurement(p2));
+ }
+
+ @Test
+ public void testEqualsForTextMeasurment_textSkew() {
+ Paint p1 = new Paint();
+ Paint p2 = new Paint();
+
+ p1.setTextSkewX(p2.getTextSkewX() + 2.0f);
+ assertFalse(p1.equalsForTextMeasurement(p2));
+ p1.setTextSkewX(p2.getTextSkewX());
+ assertTrue(p1.equalsForTextMeasurement(p2));
+ }
+
+ @Test
+ public void testEqualsForTextMeasurment_textScale() {
+ Paint p1 = new Paint();
+ Paint p2 = new Paint();
+
+ p1.setTextScaleX(p2.getTextScaleX() * 2.0f);
+ assertFalse(p1.equalsForTextMeasurement(p2));
+ p1.setTextScaleX(p2.getTextScaleX());
+ assertTrue(p1.equalsForTextMeasurement(p2));
+ }
+
+ @Test
+ public void testEqualsForTextMeasurment_letterSpacing() {
+ Paint p1 = new Paint();
+ Paint p2 = new Paint();
+
+ p1.setLetterSpacing(p2.getLetterSpacing() + 2.0f);
+ assertFalse(p1.equalsForTextMeasurement(p2));
+ p1.setLetterSpacing(p2.getLetterSpacing());
+ assertTrue(p1.equalsForTextMeasurement(p2));
+ }
+
+ @Test
+ public void testEqualsForTextMeasurment_localeList() {
+ Paint p1 = new Paint();
+ Paint p2 = new Paint();
+
+ LocaleList enUS = LocaleList.forLanguageTags("en-US");
+ LocaleList jaJP = LocaleList.forLanguageTags("ja-JP");
+ LocaleList differentLocale = p2.getTextLocales().equals(enUS) ? jaJP : enUS;
+ p1.setTextLocales(differentLocale);
+ assertFalse(p1.equalsForTextMeasurement(p2));
+ p1.setTextLocales(p2.getTextLocales());
+ assertTrue(p1.equalsForTextMeasurement(p2));
+ }
+
+ @Test
+ public void testEqualsForTextMeasurment_typeface() {
+ Paint p1 = new Paint();
+ Paint p2 = new Paint();
+
+ p1.setTypeface(Typeface.DEFAULT);
+ p2.setTypeface(Typeface.SERIF);
+ assertFalse(p1.equalsForTextMeasurement(p2));
+ p1.setTypeface(p2.getTypeface());
+ assertTrue(p1.equalsForTextMeasurement(p2));
+ }
}
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedImageDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedImageDrawableTest.java
index 43aceb9..537b774 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedImageDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedImageDrawableTest.java
@@ -20,7 +20,6 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -29,17 +28,24 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
import android.graphics.ImageDecoder;
+import android.graphics.LightingColorFilter;
+import android.graphics.Paint;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.cts.R;
import android.graphics.drawable.AnimatedImageDrawable;
import android.graphics.drawable.Drawable;
-import android.graphics.cts.R;
import android.net.Uri;
import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
import android.widget.ImageView;
+import com.android.compatibility.common.util.BitmapUtils;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -48,6 +54,7 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.function.BiFunction;
@RunWith(AndroidJUnit4.class)
public class AnimatedImageDrawableTest {
@@ -83,6 +90,11 @@
mActivity = mActivityRule.getActivity();
}
+ @Test
+ public void testEmptyConstructor() {
+ new AnimatedImageDrawable();
+ }
+
private AnimatedImageDrawable createFromImageDecoder(int resId) {
Uri uri = null;
try {
@@ -333,12 +345,15 @@
public void testLoopCounts() throws Throwable {
for (int loopCount : new int[] { 3, 5, 7, 16 }) {
AnimatedImageDrawable drawable = createFromImageDecoder(RES_ID);
+ assertEquals(AnimatedImageDrawable.LOOP_INFINITE, drawable.getLoopCount());
+
Callback cb = new Callback(drawable);
mActivityRule.runOnUiThread(() -> {
setContentView(drawable);
drawable.registerAnimationCallback(cb);
drawable.setLoopCount(loopCount);
+ assertEquals(loopCount, drawable.getLoopCount());
drawable.start();
});
@@ -348,6 +363,9 @@
cb.waitForEnd(DURATION * 2);
cb.assertEnded(true);
+
+ drawable.setLoopCount(AnimatedImageDrawable.LOOP_INFINITE);
+ assertEquals(AnimatedImageDrawable.LOOP_INFINITE, drawable.getLoopCount());
}
}
@@ -377,6 +395,104 @@
}
@Test
+ public void testColorFilter() {
+ AnimatedImageDrawable drawable = createFromImageDecoder(RES_ID);
+
+ ColorFilter filter = new LightingColorFilter(0, Color.RED);
+ drawable.setColorFilter(filter);
+ assertEquals(filter, drawable.getColorFilter());
+
+ Bitmap actual = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ {
+ Canvas canvas = new Canvas(actual);
+ drawable.draw(canvas);
+ }
+
+ for (int i = 0; i < actual.getWidth(); ++i) {
+ for (int j = 0; j < actual.getHeight(); ++j) {
+ int color = actual.getPixel(i, j);
+ // The LightingColorFilter does not affect the transparent pixels,
+ // so all pixels should either remain transparent or turn red.
+ if (color != Color.RED && color != Color.TRANSPARENT) {
+ fail("pixel at " + i + ", " + j + " does not match expected. "
+ + "expected: " + Color.RED + " OR " + Color.TRANSPARENT
+ + " actual: " + color);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testPostProcess() {
+ // Compare post processing a Rect in the middle of the (not-animating)
+ // image with drawing manually. They should be exactly the same.
+ BiFunction<Integer, Integer, Rect> rectCreator = (width, height) -> {
+ int quarterWidth = width / 4;
+ int quarterHeight = height / 4;
+ return new Rect(quarterWidth, quarterHeight,
+ 3 * quarterWidth, 3 * quarterHeight);
+ };
+
+ AnimatedImageDrawable drawable = createFromImageDecoder(RES_ID);
+ Bitmap expected = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+
+ Paint paint = new Paint();
+ paint.setColor(Color.RED);
+
+ {
+ Rect r = rectCreator.apply(drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight());
+ Canvas canvas = new Canvas(expected);
+ drawable.draw(canvas);
+
+ for (int i = r.left; i < r.right; ++i) {
+ for (int j = r.top; j < r.bottom; ++j) {
+ assertNotEquals(Color.RED, expected.getPixel(i, j));
+ }
+ }
+
+ canvas.drawRect(r, paint);
+
+ for (int i = r.left; i < r.right; ++i) {
+ for (int j = r.top; j < r.bottom; ++j) {
+ assertEquals(Color.RED, expected.getPixel(i, j));
+ }
+ }
+ }
+
+
+ AnimatedImageDrawable testDrawable = null;
+ Uri uri = null;
+ try {
+ uri = getAsResourceUri(RES_ID);
+ ImageDecoder.Source source = ImageDecoder.createSource(mContentResolver, uri);
+ Drawable dr = ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
+ decoder.setPostProcessor((canvas) -> {
+ canvas.drawRect(rectCreator.apply(canvas.getWidth(),
+ canvas.getHeight()), paint);
+ return PixelFormat.TRANSLUCENT;
+ });
+ });
+ assertTrue(dr instanceof AnimatedImageDrawable);
+ testDrawable = (AnimatedImageDrawable) dr;
+ } catch (IOException e) {
+ fail("failed to create image from " + uri);
+ }
+
+ Bitmap actual = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+
+ {
+ Canvas canvas = new Canvas(actual);
+ testDrawable.draw(canvas);
+ }
+
+ BitmapUtils.compareBitmaps(expected, actual);
+ }
+
+ @Test
public void testCreateFromXml() throws XmlPullParserException, IOException {
XmlPullParser parser = mRes.getXml(R.drawable.animatedimagedrawable_tag);
Drawable drawable = Drawable.createFromXml(mRes, parser);
@@ -399,4 +515,37 @@
assertNotNull(drawable);
assertTrue(drawable instanceof AnimatedImageDrawable);
}
+
+ @Test(expected=XmlPullParserException.class)
+ public void testMissingSrcInflate() throws XmlPullParserException, IOException {
+ XmlPullParser parser = mRes.getXml(R.drawable.animatedimagedrawable_nosrc);
+ Drawable drawable = Drawable.createFromXml(mRes, parser);
+ }
+
+ @Test
+ public void testAutoMirrored() {
+ AnimatedImageDrawable drawable = createFromImageDecoder(RES_ID);
+ assertFalse(drawable.isAutoMirrored());
+
+ drawable.setAutoMirrored(true);
+ assertTrue(drawable.isAutoMirrored());
+
+ drawable.setAutoMirrored(false);
+ assertFalse(drawable.isAutoMirrored());
+ }
+
+ @Test
+ public void testAutoMirroredFromXml() throws XmlPullParserException, IOException {
+ XmlPullParser parser = mRes.getXml(R.drawable.animatedimagedrawable_tag);
+ Drawable drawable = Drawable.createFromXml(mRes, parser);
+ assertNotNull(drawable);
+ assertTrue(drawable instanceof AnimatedImageDrawable);
+ assertFalse(drawable.isAutoMirrored());
+
+ parser = mRes.getXml(R.drawable.animatedimagedrawable_automirrored);
+ drawable = Drawable.createFromXml(mRes, parser);
+ assertNotNull(drawable);
+ assertTrue(drawable instanceof AnimatedImageDrawable);
+ assertTrue(drawable.isAutoMirrored());
+ }
}
diff --git a/tests/tests/hardware/Android.mk b/tests/tests/hardware/Android.mk
index 3b6a0d1..4e8aaa7 100644
--- a/tests/tests/hardware/Android.mk
+++ b/tests/tests/hardware/Android.mk
@@ -41,6 +41,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsHardwareTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/keystore/Android.mk b/tests/tests/keystore/Android.mk
index 51c5d41..c741a04 100644
--- a/tests/tests/keystore/Android.mk
+++ b/tests/tests/keystore/Android.mk
@@ -48,6 +48,7 @@
#
# Uncomment when b/13282254 is fixed.
# LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_JAVA_LIBRARIES += android.test.runner.stubs
LOCAL_JAVA_LIBRARIES += android.test.base.stubs
diff --git a/tests/tests/libcorefileio/Android.mk b/tests/tests/libcorefileio/Android.mk
index 9d4345b..c56a3b7 100644
--- a/tests/tests/libcorefileio/Android.mk
+++ b/tests/tests/libcorefileio/Android.mk
@@ -28,6 +28,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsLibcoreFileIOTestCases
+LOCAL_SDK_VERSION := current
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/tests/tests/location2/Android.mk b/tests/tests/location2/Android.mk
index 326923f..d8b1ce4 100644
--- a/tests/tests/location2/Android.mk
+++ b/tests/tests/location2/Android.mk
@@ -33,6 +33,7 @@
LOCAL_PACKAGE_NAME := CtsLocation2TestCases
# uncomment when Location.EXTRA_NO_GPS_LOCATION is removed
-#LOCAL_SDK_VERSION := curren
+#LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/media/Android.mk b/tests/tests/media/Android.mk
index 0aab327..2491d44 100644
--- a/tests/tests/media/Android.mk
+++ b/tests/tests/media/Android.mk
@@ -72,6 +72,7 @@
# This test uses private APIs
#LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_JAVA_LIBRARIES += \
org.apache.http.legacy \
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index 5174db0..59e2361 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -787,6 +787,13 @@
}
}
+ public void testSetVoiceCallVolumeToZeroPermission() {
+ // Verify that only apps with MODIFY_PHONE_STATE can set VOICE_CALL_STREAM to 0
+ mAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, 0, 0);
+ assertTrue("MODIFY_PHONE_STATE is required in order to set voice call volume to 0",
+ mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL) != 0);
+ }
+
public void testMuteFixedVolume() throws Exception {
int[] streams = {
AudioManager.STREAM_VOICE_CALL,
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordTest.java b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
index 939d7ec..63b3356 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
@@ -39,6 +39,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.testng.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -804,6 +805,34 @@
}
}
+ @Test
+ public void testVoiceCallAudioSourcePermissions() throws Exception {
+ if (!hasMicrophone()) {
+ return;
+ }
+
+ // Make sure that VOICE_CALL, VOICE_DOWNLINK and VOICE_UPLINK audio sources cannot
+ // be used by apps that don't have the CAPTURE_AUDIO_OUTPUT permissions
+ final int[] voiceCallAudioSources = new int [] {MediaRecorder.AudioSource.VOICE_CALL,
+ MediaRecorder.AudioSource.VOICE_DOWNLINK,
+ MediaRecorder.AudioSource.VOICE_UPLINK};
+
+ for (int source : voiceCallAudioSources) {
+ // AudioRecord.Builder should fail when trying to use
+ // one of the voice call audio sources.
+ assertThrows(UnsupportedOperationException.class,
+ () -> {
+ new AudioRecord.Builder()
+ .setAudioSource(source)
+ .setAudioFormat(new AudioFormat.Builder()
+ .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
+ .setSampleRate(8000)
+ .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
+ .build())
+ .build(); });
+ }
+ }
+
private void printMicrophoneInfo(MicrophoneInfo microphone) {
Log.i(TAG, "deviceId:" + microphone.getDescription());
Log.i(TAG, "portId:" + microphone.getId());
diff --git a/tests/tests/media/src/android/media/cts/RoutingTest.java b/tests/tests/media/src/android/media/cts/RoutingTest.java
index ddb534a..2afad1e 100644
--- a/tests/tests/media/src/android/media/cts/RoutingTest.java
+++ b/tests/tests/media/src/android/media/cts/RoutingTest.java
@@ -136,6 +136,66 @@
audioTrack.release();
}
+ public void test_audioTrack_incallMusicRoutingPermissions() {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
+ // Can't do it so skip this test
+ return;
+ }
+
+ // only apps with MODIFY_PHONE_STATE permission can route playback
+ // to the uplink stream during a phone call, so this test makes sure that
+ // audio is re-routed to default device when the permission is missing
+
+ AudioDeviceInfo telephonyDevice = getTelephonyDeviceAndSetInCommunicationMode();
+ if (telephonyDevice == null) {
+ // Can't do it so skip this test
+ return;
+ }
+
+ AudioTrack audioTrack = null;
+
+ try {
+ audioTrack = allocAudioTrack();
+ assertNotNull(audioTrack);
+
+ audioTrack.setPreferredDevice(telephonyDevice);
+ assertEquals(AudioDeviceInfo.TYPE_TELEPHONY, audioTrack.getPreferredDevice().getType());
+
+ audioTrack.play();
+ assertTrue(audioTrack.getRoutedDevice().getType() != AudioDeviceInfo.TYPE_TELEPHONY);
+
+ } finally {
+ if (audioTrack != null) {
+ audioTrack.stop();
+ audioTrack.release();
+ }
+ mAudioManager.setMode(AudioManager.MODE_NORMAL);
+ }
+ }
+
+ private AudioDeviceInfo getTelephonyDeviceAndSetInCommunicationMode() {
+ // get the output device for telephony
+ AudioDeviceInfo telephonyDevice = null;
+ AudioDeviceInfo[] deviceList = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
+ for (int index = 0; index < deviceList.length; index++) {
+ if (deviceList[index].getType() == AudioDeviceInfo.TYPE_TELEPHONY) {
+ telephonyDevice = deviceList[index];
+ }
+ }
+
+ if (telephonyDevice == null) {
+ return null;
+ }
+
+ // simulate an in call state using MODE_IN_COMMUNICATION since
+ // AudioManager.setMode requires MODIFY_PHONE_STATE permission
+ // for setMode with MODE_IN_CALL.
+ mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
+ assertEquals(AudioManager.MODE_IN_COMMUNICATION, mAudioManager.getMode());
+
+ return telephonyDevice;
+ }
+
/*
* tests if the Looper for the current thread has been prepared,
* If not, it makes one, prepares it and returns it.
@@ -634,6 +694,43 @@
mediaPlayer.release();
}
+ public void test_mediaPlayer_incallMusicRoutingPermissions() {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
+ // Can't do it so skip this test
+ return;
+ }
+
+ // only apps with MODIFY_PHONE_STATE permission can route playback
+ // to the uplink stream during a phone call, so this test makes sure that
+ // audio is re-routed to default device when the permission is missing
+
+ AudioDeviceInfo telephonyDevice = getTelephonyDeviceAndSetInCommunicationMode();
+ if (telephonyDevice == null) {
+ // Can't do it so skip this test
+ return;
+ }
+
+ MediaPlayer mediaPlayer = null;
+
+ try {
+ mediaPlayer = allocMediaPlayer();
+
+ mediaPlayer.setPreferredDevice(telephonyDevice);
+ assertEquals(AudioDeviceInfo.TYPE_TELEPHONY, mediaPlayer.getPreferredDevice().getType());
+
+ // Sleep for 1s to ensure the output device open
+ SystemClock.sleep(1000);
+ assertTrue(mediaPlayer.getRoutedDevice().getType() != AudioDeviceInfo.TYPE_TELEPHONY);
+
+ } finally {
+ if (mediaPlayer != null) {
+ mediaPlayer.stop();
+ mediaPlayer.release();
+ }
+ mAudioManager.setMode(AudioManager.MODE_NORMAL);
+ }
+ }
+
private MediaRecorder allocMediaRecorder() throws Exception {
final String outputPath = new File(Environment.getExternalStorageDirectory(),
"record.out").getAbsolutePath();
diff --git a/tests/tests/net/Android.mk b/tests/tests/net/Android.mk
index e348406..e67bb8f 100644
--- a/tests/tests/net/Android.mk
+++ b/tests/tests/net/Android.mk
@@ -49,6 +49,7 @@
# uncomment when b/13249961 is fixed
#LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/tests/tests/os/Android.mk b/tests/tests/os/Android.mk
index 274bc06..9cd0b87 100644
--- a/tests/tests/os/Android.mk
+++ b/tests/tests/os/Android.mk
@@ -49,6 +49,7 @@
# uncomment when b/13282254 is fixed
#LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_JAVA_LIBRARIES += android.test.runner.stubs
LOCAL_JAVA_LIBRARIES += android.test.base.stubs
diff --git a/tests/tests/permission/Android.mk b/tests/tests/permission/Android.mk
index 171283e..1a4eec6 100644
--- a/tests/tests/permission/Android.mk
+++ b/tests/tests/permission/Android.mk
@@ -43,6 +43,7 @@
# uncomment when b/13249777 is fixed
#LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_JAVA_LIBRARIES += android.test.runner.stubs
LOCAL_JAVA_LIBRARIES += android.test.base.stubs
diff --git a/tests/tests/permission/src/android/permission/cts/AppOpsTest.java b/tests/tests/permission/src/android/permission/cts/AppOpsTest.java
index 970ada7..7285fd0 100644
--- a/tests/tests/permission/src/android/permission/cts/AppOpsTest.java
+++ b/tests/tests/permission/src/android/permission/cts/AppOpsTest.java
@@ -27,8 +27,14 @@
import static com.android.compatibility.common.util.AppOpsUtils.rejectedOperationLogged;
import static com.android.compatibility.common.util.AppOpsUtils.setOpMode;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
import android.Manifest.permission;
import android.app.AppOpsManager;
+import android.app.AppOpsManager.OnOpChangedListener;
import android.content.Context;
import android.os.Process;
import android.test.InstrumentationTestCase;
@@ -159,12 +165,12 @@
}
}
- public void testCheckPackagePassesTest() throws Exception {
+ public void testCheckPackagePassesCheck() throws Exception {
mAppOps.checkPackage(mMyUid, mOpPackageName);
mAppOps.checkPackage(Process.SYSTEM_UID, "android");
}
- public void testCheckPackageDoesntPassTest() throws Exception {
+ public void testCheckPackageDoesntPassCheck() throws Exception {
try {
// Package name doesn't match UID.
mAppOps.checkPackage(Process.SYSTEM_UID, mOpPackageName);
@@ -187,6 +193,41 @@
}
}
+ public void testWatchingMode() throws Exception {
+ OnOpChangedListener watcher = mock(OnOpChangedListener.class);
+ try {
+ setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_ALLOWED);
+
+ mAppOps.startWatchingMode(OPSTR_READ_SMS, mOpPackageName, watcher);
+
+ // Make a change to the app op's mode.
+ reset(watcher);
+ setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_ERRORED);
+ verify(watcher).onOpChanged(OPSTR_READ_SMS, mOpPackageName);
+
+ // Make another change to the app op's mode.
+ reset(watcher);
+ setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_ALLOWED);
+ verify(watcher).onOpChanged(OPSTR_READ_SMS, mOpPackageName);
+
+ // Set mode to the same value as before - expect no call to the listener.
+ reset(watcher);
+ setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_ALLOWED);
+ verifyZeroInteractions(watcher);
+
+ mAppOps.stopWatchingMode(watcher);
+
+ // Make a change to the app op's mode. Since we already stopped watching the mode, the
+ // listener shouldn't be called.
+ reset(watcher);
+ setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_ERRORED);
+ verifyZeroInteractions(watcher);
+ } finally {
+ // Clean up registered watcher.
+ mAppOps.stopWatchingMode(watcher);
+ }
+ }
+
@SmallTest
public void testAllOpsHaveOpString() {
Set<String> opStrs = new HashSet<>();
diff --git a/tests/tests/permission2/Android.mk b/tests/tests/permission2/Android.mk
index d1190a3..3df1bc9 100755
--- a/tests/tests/permission2/Android.mk
+++ b/tests/tests/permission2/Android.mk
@@ -24,7 +24,7 @@
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_JAVA_LIBRARIES := telephony-common android.test.base.stubs
+LOCAL_JAVA_LIBRARIES := android.test.base.stubs
LOCAL_STATIC_JAVA_LIBRARIES := \
compatibility-device-util \
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 8bf4467..7cf9971 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -53,6 +53,7 @@
<protected-broadcast android:name="android.intent.action.UID_REMOVED" />
<protected-broadcast android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
<protected-broadcast android:name="android.intent.action.CONFIGURATION_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.SPLIT_CONFIGURATION_CHANGED" />
<protected-broadcast android:name="android.intent.action.LOCALE_CHANGED" />
<protected-broadcast android:name="android.intent.action.BATTERY_CHANGED" />
<protected-broadcast android:name="android.intent.action.BATTERY_LOW" />
@@ -159,6 +160,8 @@
<protected-broadcast
android:name="android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED" />
<protected-broadcast
+ android:name="android.bluetooth.headset.profile.action.ACTIVE_DEVICE_CHANGED" />
+ <protected-broadcast
android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
@@ -171,8 +174,14 @@
<protected-broadcast
android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
<protected-broadcast
+ android:name="android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED" />
+ <protected-broadcast
android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
+ android:name="android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED" />
+ <protected-broadcast
android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED" />
@@ -319,10 +328,15 @@
<protected-broadcast android:name="com.android.server.usb.ACTION_OPEN_IN_APPS" />
<protected-broadcast android:name="com.android.server.am.DELETE_DUMPHEAP" />
<protected-broadcast android:name="com.android.server.net.action.SNOOZE_WARNING" />
+ <protected-broadcast android:name="com.android.server.net.action.SNOOZE_RAPID" />
<protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.USER_DISMISSED_NOTIFICATION" />
<protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.CONNECT_TO_NETWORK" />
<protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.PICK_WIFI_NETWORK" />
<protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.PICK_NETWORK_AFTER_FAILURE" />
+ <protected-broadcast android:name="com.android.server.wifi.wakeup.DISMISS_NOTIFICATION" />
+ <protected-broadcast android:name="com.android.server.wifi.wakeup.OPEN_WIFI_PREFERENCES" />
+ <protected-broadcast android:name="com.android.server.wifi.wakeup.OPEN_WIFI_SETTINGS" />
+ <protected-broadcast android:name="com.android.server.wifi.wakeup.TURN_OFF_WIFI_WAKE" />
<protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
@@ -506,6 +520,7 @@
<protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
<protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED" />
<protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED" />
+ <protected-broadcast android:name="android.app.action.APP_BLOCK_STATE_CHANGED" />
<protected-broadcast android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS" />
<protected-broadcast android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS" />
@@ -550,8 +565,6 @@
<protected-broadcast android:name="android.intent.action.DEVICE_LOCKED_CHANGED" />
<!-- Added in O -->
- <!-- TODO: temporary broadcast used by AutoFillManagerServiceImpl; will be removed -->
- <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" />
@@ -564,8 +577,20 @@
<protected-broadcast android:name="android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED" />
<protected-broadcast android:name="com.android.server.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER" />
+ <!-- Time zone rules update intents fired by the system server -->
+ <protected-broadcast android:name="com.android.intent.action.timezone.RULES_UPDATE_OPERATION" />
+ <protected-broadcast android:name="com.android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK" />
+
<!-- Made protected in P (was introduced in JB-MR2) -->
<protected-broadcast android:name="android.intent.action.GET_RESTRICTION_ENTRIES" />
+ <protected-broadcast android:name="android.telephony.euicc.action.OTA_STATUS_CHANGED" />
+
+ <!-- Added in P -->
+ <protected-broadcast android:name="android.app.action.PROFILE_OWNER_CHANGED" />
+ <protected-broadcast android:name="android.app.action.TRANSFER_OWNERSHIP_COMPLETE" />
+ <protected-broadcast android:name="android.app.action.AFFILIATED_PROFILE_TRANSFER_OWNERSHIP_COMPLETE" />
+ <protected-broadcast android:name="android.app.action.DATA_SHARING_RESTRICTION_CHANGED" />
+ <protected-broadcast android:name="android.app.action.STATSD_STARTED" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
@@ -957,6 +982,23 @@
android:description="@string/permdesc_manageOwnCalls"
android:protectionLevel="normal" />
+ <!-- Allows a calling app to continue a call which was started in another app. An example is a
+ video calling app that wants to continue a voice call on the user's mobile network.<p>
+ When the handover of a call from one app to another takes place, there are two devices
+ which are involved in the handover; the initiating and receiving devices. The initiating
+ device is where the request to handover the call was started, and the receiving device is
+ where the handover request is confirmed by the other party.<p>
+ This permission protects access to the
+ {@link android.telecom.TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)} which
+ the receiving side of the handover uses to accept a handover.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.ACCEPT_HANDOVER"
+ android:permissionGroup="android.permission-group.PHONE"
+ android.label="@string/permlab_acceptHandover"
+ android:description="@string/permdesc_acceptHandovers"
+ android:protectionLevel="dangerous" />
+
<!-- ====================================================================== -->
<!-- Permissions for accessing the device microphone -->
<!-- ====================================================================== -->
@@ -1378,6 +1420,12 @@
<permission android:name="android.permission.MANAGE_LOWPAN_INTERFACES"
android:protectionLevel="signature|privileged" />
+ <!-- @hide Allows internal management of Wi-Fi connectivity state when on
+ permission review mode.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_WIFI_WHEN_PERMISSION_REVIEW_REQUIRED"
+ android:protectionLevel="signature" />
+
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
<!-- ======================================= -->
@@ -1425,6 +1473,12 @@
android:label="@string/permlab_nfc"
android:protectionLevel="normal" />
+ <!-- Allows applications to receive NFC transaction events.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.NFC_TRANSACTION_EVENT"
+ android:protectionLevel="normal" />
+
<!-- @SystemApi Allows an internal user to use privileged ConnectivityManager APIs.
@hide -->
<permission android:name="android.permission.CONNECTIVITY_INTERNAL"
@@ -1455,6 +1509,11 @@
<permission android:name="android.permission.NFC_HANDOVER_STATUS"
android:protectionLevel="signature|privileged" />
+ <!-- @hide Allows internal management of Bluetooth state when on permission review mode.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_BLUETOOTH_WHEN_PERMISSION_REVIEW_REQUIRED"
+ android:protectionLevel="signature" />
+
<!-- ================================== -->
<!-- Permissions for accessing accounts -->
<!-- ================================== -->
@@ -1739,15 +1798,39 @@
<permission android:name="android.permission.SEND_EMBMS_INTENTS"
android:protectionLevel="signature|privileged" />
+
+ <!-- Allows internal management of the sensor framework
+ @hide -->
+ <permission android:name="android.permission.MANAGE_SENSORS"
+ android:protectionLevel="signature" />
+
<!-- Must be required by an ImsService to ensure that only the
system can bind to it.
- <p>Protection level: signature|privileged
+ <p>Protection level: signature|privileged|vendorPrivileged
@SystemApi
@hide
-->
<permission android:name="android.permission.BIND_IMS_SERVICE"
android:protectionLevel="signature|privileged|vendorPrivileged" />
+ <!-- Must be required by a telephony data service to ensure that only the
+ system can bind to it.
+ <p>Protection level: signature
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_TELEPHONY_DATA_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a NetworkService to ensure that only the
+ system can bind to it.
+ <p>Protection level: signature
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_TELEPHONY_NETWORK_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to manage embedded subscriptions (those on a eUICC)
through EuiccManager APIs.
<p>Protection level: signature|privileged|development
@@ -2300,6 +2383,11 @@
<permission android:name="android.permission.RECOVERY"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to read system update info.
+ @hide -->
+ <permission android:name="android.permission.READ_SYSTEM_UPDATE_INFO"
+ android:protectionLevel="signature" />
+
<!-- Allows the system to bind to an application's task services
@hide -->
<permission android:name="android.permission.BIND_JOB_SERVICE"
@@ -2675,6 +2763,30 @@
<permission android:name="android.permission.BIND_AUTOFILL_SERVICE"
android:protectionLevel="signature" />
+ <!-- Alternative version of android.permission.BIND_AUTOFILL_FIELD_CLASSIFICATION_SERVICE.
+ This permission was renamed during the O previews but it was supported on the final O
+ release, so we need to carry it over.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_AUTOFILL"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by an {@link android.service.autofill.AutofillFieldClassificationService}
+ to ensure that only the system can bind to it.
+ @hide This is not a third-party API (intended for OEMs and system apps).
+ -->
+ <permission android:name="android.permission.BIND_AUTOFILL_FIELD_CLASSIFICATION_SERVICE"
+ android:protectionLevel="signature" />
+
+ <!-- Must be required by a android.service.textclassifier.TextClassifierService,
+ to ensure that only the system can bind to it.
+ @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_TEXTCLASSIFIER_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- Must be required by hotword enrollment application,
to ensure that only the system can interact with it.
@hide <p>Not for use by third-party applications.</p> -->
@@ -2823,6 +2935,14 @@
<permission android:name="android.permission.INSTALL_SELF_UPDATES"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to install updates. This is a limited version
+ of {@link android.Manifest.permission#INSTALL_PACKAGES}.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.INSTALL_PACKAGE_UPDATES"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows an application to clear user data.
<p>Not for use by third-party applications
@hide
@@ -2855,11 +2975,16 @@
<permission android:name="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS"
android:protectionLevel="signature" />
- <!-- @SystemApi Allows an application to delete cache files.
- <p>Not for use by third-party applications. -->
+ <!-- @SystemApi Old permission for deleting an app's cache files, no longer used,
+ but signals for us to quietly ignore calls instead of throwing an exception. -->
<permission android:name="android.permission.DELETE_CACHE_FILES"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an application to delete cache files.
+ @hide -->
+ <permission android:name="android.permission.INTERNAL_DELETE_CACHE_FILES"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to delete packages.
<p>Not for use by third-party applications.
<p>Starting in {@link android.os.Build.VERSION_CODES#N}, user confirmation is requested
@@ -2949,6 +3074,13 @@
<permission android:name="android.permission.BRIGHTNESS_SLIDER_USAGE"
android:protectionLevel="signature|privileged|development" />
+ <!-- Allows an application to collect ambient light stats.
+ <p>Not for use by third party applications.</p>
+ TODO: Make a system API
+ @hide -->
+ <permission android:name="android.permission.ACCESS_AMBIENT_LIGHT_STATS"
+ android:protectionLevel="signature|privileged|development" />
+
<!-- Allows an application to modify the display brightness configuration
@hide
@SystemApi -->
@@ -3177,10 +3309,14 @@
<permission android:name="android.permission.BIND_APPWIDGET"
android:protectionLevel="signature|privileged" />
+ <!-- @hide Allows sysui to manage user grants of slice permissions. -->
+ <permission android:name="android.permission.MANAGE_SLICE_PERMISSIONS"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to bind app's slices and get their
content. This content will be surfaced to the
user and not to leave the device.
- <p>Not for use by third-party applications. -->
+ <p>Not for use by third-party applications.-->
<permission android:name="android.permission.BIND_SLICE"
android:protectionLevel="signature|privileged|development" />
@@ -3674,20 +3810,41 @@
<permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"
android:protectionLevel="signature|development|instant|appop" />
- <!-- @hide Allows system components to access all app shortcuts. -->
+ <!-- @SystemApi Allows to access all app shortcuts.
+ @hide -->
<permission android:name="android.permission.ACCESS_SHORTCUTS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|textClassifier" />
+
+ <!-- @SystemApi Allows unlimited calls to shortcut mutation APIs.
+ @hide -->
+ <permission android:name="android.permission.UNLIMITED_SHORTCUTS_API_CALLS"
+ android:protectionLevel="signature|textClassifier" />
<!-- @SystemApi Allows an application to read the runtime profiles of other apps.
@hide <p>Not for use by third-party applications. -->
<permission android:name="android.permission.READ_RUNTIME_PROFILES"
android:protectionLevel="signature|privileged" />
+ <!-- @hide Allows audio policy management. -->
+ <permission android:name="android.permission.MANAGE_AUDIO_POLICY"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to turn on / off quiet mode.
@hide <p>Not for use by third-party applications. -->
<permission android:name="android.permission.MODIFY_QUIET_MODE"
android:protectionLevel="signature|privileged" />
+ <!-- Allows internal management of the camera framework
+ @hide -->
+ <permission android:name="android.permission.MANAGE_CAMERA"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an application to control remote animations. See
+ {@link ActivityOptions#makeRemoteAnimation}
+ @hide <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"
+ android:protectionLevel="signature|privileged" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
@@ -3736,6 +3893,7 @@
android:excludeFromRecents="true"
android:label="@string/user_owner_label"
android:exported="true"
+ android:visibleToInstantApps="true"
>
</activity>
<activity-alias android:name="com.android.internal.app.ForwardIntentToParent"
@@ -3881,6 +4039,14 @@
android:excludeFromRecents="true">
</activity>
+ <activity android:name="com.android.internal.app.HarmfulAppWarningActivity"
+ android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
+ android:excludeFromRecents="true"
+ android:process=":ui"
+ android:label="@string/harmful_app_warning_title"
+ android:exported="false">
+ </activity>
+
<receiver android:name="com.android.server.BootReceiver"
android:systemUserOnly="true">
<intent-filter android:priority="1000">
@@ -3960,6 +4126,14 @@
</intent-filter>
</receiver>
+ <receiver android:name="com.android.server.updates.CarrierIdInstallReceiver"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="com.android.internal.intent.action.UPDATE_CARRIER_ID_DB" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
<receiver android:name="com.android.server.MasterClearReceiver"
android:permission="android.permission.MASTER_CLEAR">
<intent-filter
@@ -4048,6 +4222,16 @@
<service android:name="com.android.server.display.BrightnessIdleJob"
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
+
+ <service
+ android:name="com.android.server.autofill.AutofillCompatAccessibilityService"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+ android:exported="true">
+ <meta-data
+ android:name="android.accessibilityservice"
+ android:resource="@xml/autofill_compat_accessibility_service" />
+ </service>
+
</application>
</manifest>
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index 68b0b84..4b8aedfc 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -117,10 +117,8 @@
}
// OEMs cannot change permission protection flags
- final int expectedProtectionFlags = expectedPermission.protectionLevel
- & PermissionInfo.PROTECTION_MASK_FLAGS;
- final int declaredProtectionFlags = declaredPermission.protectionLevel
- & PermissionInfo.PROTECTION_MASK_FLAGS;
+ final int expectedProtectionFlags = expectedPermission.getProtectionFlags();
+ final int declaredProtectionFlags = declaredPermission.getProtectionFlags();
if (expectedProtectionFlags != declaredProtectionFlags) {
offendingList.add(
String.format(
@@ -262,6 +260,9 @@
case "setup": {
protectionLevel |= PermissionInfo.PROTECTION_FLAG_SETUP;
} break;
+ case "textClassifier": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER;
+ } break;
case "instant": {
protectionLevel |= PermissionInfo.PROTECTION_FLAG_INSTANT;
} break;
diff --git a/tests/tests/proto/Android.mk b/tests/tests/proto/Android.mk
index 37faee6..595df7c 100644
--- a/tests/tests/proto/Android.mk
+++ b/tests/tests/proto/Android.mk
@@ -33,6 +33,7 @@
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
#LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_JAVA_LIBRARIES += android.test.runner.stubs
LOCAL_STATIC_JAVA_LIBRARIES := \
diff --git a/tests/tests/provider/Android.mk b/tests/tests/provider/Android.mk
index 648c9852..df178c7 100644
--- a/tests/tests/provider/Android.mk
+++ b/tests/tests/provider/Android.mk
@@ -42,5 +42,6 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsProviderTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index f9763e1..3368526 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -52,6 +52,7 @@
LOCAL_PACKAGE_NAME := CtsSecurityTestCases
#LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index 4fefdab..cddcd76 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -40,7 +40,15 @@
libc++ \
libpcre2 \
libpackagelistparser \
-
+ libpowermanager \
+ libbase \
+ libunwind \
+ libhardware \
+ libsync \
+ libcamera_metadata \
+ libspeexresampler \
+ liblzma \
+ libstagefright_foundation
LOCAL_C_INCLUDES += ndk/sources/cpufeatures
LOCAL_STATIC_LIBRARIES := cpufeatures
diff --git a/tests/tests/security/res/raw/bug_36592202.ogg b/tests/tests/security/res/raw/bug_36592202.ogg
new file mode 100755
index 0000000..868e630
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_36592202.ogg
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_38448381.mp4 b/tests/tests/security/res/raw/bug_38448381.mp4
new file mode 100755
index 0000000..831cc74
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_38448381.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_38487564.mp4 b/tests/tests/security/res/raw/bug_38487564.mp4
new file mode 100755
index 0000000..01984447
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_38487564.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_63121644.mp4 b/tests/tests/security/res/raw/bug_63121644.mp4
new file mode 100755
index 0000000..bf932ac8
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_63121644.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_65398821.mp4 b/tests/tests/security/res/raw/bug_65398821.mp4
new file mode 100755
index 0000000..bfc700d
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_65398821.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_65735716_avc.mp4 b/tests/tests/security/res/raw/bug_65735716_avc.mp4
new file mode 100755
index 0000000..39e2c2a
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_65735716_avc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2016_6764.mp4 b/tests/tests/security/res/raw/cve_2016_6764.mp4
new file mode 100644
index 0000000..46c1214
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2016_6764.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 9a0ea06..6af1d56 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -51,6 +51,8 @@
import java.io.InputStream;
import java.net.URL;
import java.nio.ByteBuffer;
+import java.io.FileOutputStream;
+import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.locks.Condition;
@@ -281,6 +283,11 @@
***********************************************************/
@SecurityTest
+ public void testStagefright_bug_38448381() throws Exception {
+ doStagefrightTest(R.raw.bug_38448381);
+ }
+
+ @SecurityTest
public void testStagefright_bug_70897454() throws Exception {
doStagefrightTestRawBlob(R.raw.b70897454_avc, "video/avc", 320, 420);
}
@@ -296,6 +303,11 @@
}
@SecurityTest
+ public void testStagefright_bug_65735716() throws Exception {
+ doStagefrightTestRawBlob(R.raw.bug_65735716_avc, "video/avc", 320, 240);
+ }
+
+ @SecurityTest
public void testStagefright_bug_65717533() throws Exception {
doStagefrightTest(R.raw.bug_65717533_header_corrupt);
}
@@ -311,11 +323,21 @@
}
@SecurityTest
+ public void testStagefright_bug_38487564() throws Exception {
+ doStagefrightTest(R.raw.bug_38487564, (4 * 60 * 1000));
+ }
+
+ @SecurityTest
public void testStagefright_cve_2016_0842() throws Exception {
doStagefrightTest(R.raw.cve_2016_0842);
}
@SecurityTest
+ public void testStagefright_bug_63121644() throws Exception {
+ doStagefrightTest(R.raw.bug_63121644);
+ }
+
+ @SecurityTest
public void testStagefright_cve_2016_6712() throws Exception {
doStagefrightTest(R.raw.cve_2016_6712);
}
@@ -346,11 +368,66 @@
}
@SecurityTest
+ public void testStagefright_bug_65398821() throws Exception {
+ doStagefrightTest(R.raw.bug_65398821, ( 4 * 60 * 1000 ) );
+ }
+
+ @SecurityTest
public void testStagefright_cve_2015_3869() throws Exception {
doStagefrightTest(R.raw.cve_2015_3869);
}
@SecurityTest
+ public void testStagefright_bug_36592202() throws Exception {
+ Resources resources = getInstrumentation().getContext().getResources();
+ AssetFileDescriptor fd = resources.openRawResourceFd(R.raw.bug_36592202);
+ int page_size = 25627;
+ byte [] blob = new byte[page_size];
+
+ // 127 bytes read and 25500 zeros constitute one Ogg page
+ FileInputStream fis = fd.createInputStream();
+ int numRead = fis.read(blob);
+ fis.close();
+
+ // Creating temp file
+ final File tempFile = File.createTempFile("poc_tmp", ".ogg", null);
+
+ try {
+ final FileOutputStream tempFos = new FileOutputStream(tempFile.getAbsolutePath());
+ int bytesWritten = 0;
+ // Repeat data till size is ~1 GB
+ for (int i = 0; i < 50000; i++) {
+ tempFos.write(blob);
+ bytesWritten += page_size;
+ }
+ tempFos.close();
+
+ final int fileSize = bytesWritten;
+ int timeout = (10 * 60 * 1000);
+
+ runWithTimeout(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ doStagefrightTestMediaCodec(tempFile.getAbsolutePath());
+ } catch (Exception | AssertionError e) {
+ if (!tempFile.delete()) {
+ Log.e(TAG, "Failed to delete temporary PoC file");
+ }
+ fail("Operation was not successful");
+ }
+ }
+ }, timeout);
+ } catch (Exception e) {
+ fail("Failed to test b/36592202");
+ } finally {
+ if (!tempFile.delete()) {
+ Log.e(TAG, "Failed to delete temporary PoC file");
+ }
+ }
+ }
+
+ @SecurityTest
public void testStagefright_bug_32322258() throws Exception {
doStagefrightTest(R.raw.bug_32322258);
}
@@ -449,6 +526,11 @@
***********************************************************/
@SecurityTest
+ public void testStagefright_cve_2016_6764() throws Exception {
+ doStagefrightTest(R.raw.cve_2016_6764);
+ }
+
+ @SecurityTest
public void testStagefright_cve_2017_13214() throws Exception {
doStagefrightTest(R.raw.cve_2017_13214);
}
diff --git a/tests/tests/selinux/selinuxTargetSdk25/Android.mk b/tests/tests/selinux/selinuxTargetSdk25/Android.mk
index b13e613..15ec6e2 100755
--- a/tests/tests/selinux/selinuxTargetSdk25/Android.mk
+++ b/tests/tests/selinux/selinuxTargetSdk25/Android.mk
@@ -22,9 +22,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
ctstestrunner \
compatibility-device-util \
- legacy-android-test \
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
+LOCAL_JAVA_LIBRARIES := android.test.base.stubs android.test.runner.stubs
LOCAL_JNI_SHARED_LIBRARIES := \
libc++ \
@@ -39,6 +38,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src common)
LOCAL_PACKAGE_NAME := CtsSelinuxTargetSdk25TestCases
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/selinux/selinuxTargetSdk27/Android.mk b/tests/tests/selinux/selinuxTargetSdk27/Android.mk
index 6de5250..e0e493e 100755
--- a/tests/tests/selinux/selinuxTargetSdk27/Android.mk
+++ b/tests/tests/selinux/selinuxTargetSdk27/Android.mk
@@ -22,9 +22,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
ctstestrunner \
compatibility-device-util \
- legacy-android-test \
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
+LOCAL_JAVA_LIBRARIES := android.test.base.stubs android.test.runner.stubs
LOCAL_JNI_SHARED_LIBRARIES := \
libc++ \
@@ -39,6 +38,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src common)
LOCAL_PACKAGE_NAME := CtsSelinuxTargetSdk27TestCases
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/selinux/selinuxTargetSdkCurrent/Android.mk b/tests/tests/selinux/selinuxTargetSdkCurrent/Android.mk
index 6c515f2..698d1ef 100755
--- a/tests/tests/selinux/selinuxTargetSdkCurrent/Android.mk
+++ b/tests/tests/selinux/selinuxTargetSdkCurrent/Android.mk
@@ -22,9 +22,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
ctstestrunner \
compatibility-device-util \
- legacy-android-test \
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
+LOCAL_JAVA_LIBRARIES := android.test.base.stubs android.test.runner.stubs
LOCAL_JNI_SHARED_LIBRARIES := \
libc++ \
@@ -39,6 +38,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src common)
LOCAL_PACKAGE_NAME := CtsSelinuxTargetSdkCurrentTestCases
+LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/slice/Android.mk b/tests/tests/slice/Android.mk
index 4410b74..c56f74c 100644
--- a/tests/tests/slice/Android.mk
+++ b/tests/tests/slice/Android.mk
@@ -38,6 +38,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsSliceTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/speech/Android.mk b/tests/tests/speech/Android.mk
index 147b137..7fb9124 100755
--- a/tests/tests/speech/Android.mk
+++ b/tests/tests/speech/Android.mk
@@ -36,5 +36,6 @@
# Needed for testing O API
#LOCAL_SDK_VERSION := test_current
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/systemui/Android.mk b/tests/tests/systemui/Android.mk
index 4d96171..2c07248 100644
--- a/tests/tests/systemui/Android.mk
+++ b/tests/tests/systemui/Android.mk
@@ -34,5 +34,6 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsSystemUiTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
index d93d431..c9e0c56 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
@@ -211,7 +211,6 @@
}
public static boolean waitForUnBinding() {
- sServiceUnBoundLatch = TestUtils.waitForLock(sServiceUnBoundLatch);
- return sServiceUnBoundLatch != null;
+ return TestUtils.waitForLatchCountDown(sServiceUnBoundLatch);
}
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsSelfManagedConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/CtsSelfManagedConnectionService.java
index b057648..e6070ce 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsSelfManagedConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsSelfManagedConnectionService.java
@@ -198,7 +198,7 @@
* timeout expired without the lock being released.
*/
public boolean waitForUpdate(int lock) {
- mLocks[lock] = waitForLock(mLocks[lock]);
+ mLocks[lock] = TestUtils.waitForLock(mLocks[lock]);
return mLocks[lock] != null;
}
@@ -207,31 +207,7 @@
* @return {@code true} if binding happened within the time limit, or {@code false} otherwise.
*/
public static boolean waitForBinding() {
- sBindingLock = waitForLock(sBindingLock);
- return sBindingLock != null;
- }
-
- /**
- * Given a {@link CountDownLatch}, wait for the latch to reach zero for 5 seconds. If the lock
- * was released, return a new instance. Otherwise, return null to indicate that the timeout
- * expired without the lock being released.
- *
- * @param lock The lock to wait on.
- * @return {@code true} if the lock was released, and {@code false} if it failed to be released.
- */
- private static CountDownLatch waitForLock(CountDownLatch lock) {
- boolean success;
- try {
- success = lock.await(5000, TimeUnit.MILLISECONDS);
- } catch (InterruptedException ie) {
- return null;
- }
-
- if (success) {
- return new CountDownLatch(1);
- } else {
- return null;
- }
+ return TestUtils.waitForLatchCountDown(sBindingLock);
}
public TestUtils.InvokeCounter getOnCreateIncomingHandoverConnectionCounter() {
diff --git a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
index 3980f7f..31000de 100644
--- a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
+++ b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
@@ -255,17 +255,36 @@
}
}
- public static CountDownLatch waitForLock(CountDownLatch lock) {
- boolean success;
- try {
- if (lock == null) {
- return null;
- }
- success = lock.await(5000, TimeUnit.MILLISECONDS);
- } catch (InterruptedException ie) {
- return null;
+ /**
+ * Waits for the {@link CountDownLatch} to count down to 0 and then returns without reseting
+ * the latch.
+ * @param lock the latch that the system will wait on.
+ * @return true if the latch was released successfully, false if the latch timed out before
+ * resetting.
+ */
+ public static boolean waitForLatchCountDown(CountDownLatch lock) {
+ if (lock == null) {
+ return false;
}
+ boolean success;
+ try {
+ success = lock.await(5000, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException ie) {
+ return false;
+ }
+
+ return success;
+ }
+
+ /**
+ * Waits for the {@link CountDownLatch} to count down to 0 and then returns a new reset latch.
+ * @param lock The lock that will await a countDown to 0.
+ * @return a new reset {@link CountDownLatch} if the lock successfully counted down to 0 or
+ * null if the operation timed out.
+ */
+ public static CountDownLatch waitForLock(CountDownLatch lock) {
+ boolean success = waitForLatchCountDown(lock);
if (success) {
return new CountDownLatch(1);
} else {
diff --git a/tests/tests/telephony/Android.mk b/tests/tests/telephony/Android.mk
index 4d6922b..f19dbb5 100644
--- a/tests/tests/telephony/Android.mk
+++ b/tests/tests/telephony/Android.mk
@@ -43,6 +43,7 @@
# uncomment when b/13250611 is fixed
#LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_JAVA_LIBRARIES += android.test.runner.stubs
LOCAL_JAVA_LIBRARIES += android.test.base.stubs
diff --git a/tests/tests/telephony/src/android/telephony/cts/ServiceStateTest.java b/tests/tests/telephony/src/android/telephony/cts/ServiceStateTest.java
index 59a44ed..8b92826 100644
--- a/tests/tests/telephony/src/android/telephony/cts/ServiceStateTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/ServiceStateTest.java
@@ -23,6 +23,8 @@
private static final String OPERATOR_ALPHA_LONG = "CtsOperatorLong";
private static final String OPERATOR_ALPHA_SHORT = "CtsOp";
private static final String OPERATOR_NUMERIC = "02871";
+ private static final int SYSTEM_ID = 123;
+ private static final int NETWORK_ID = 456;
public void testServiceState() {
ServiceState serviceState = new ServiceState();
@@ -53,6 +55,10 @@
assertEquals(OPERATOR_ALPHA_SHORT, serviceState.getOperatorAlphaShort());
assertEquals(OPERATOR_NUMERIC, serviceState.getOperatorNumeric());
+ serviceState.setSystemAndNetworkId(SYSTEM_ID, NETWORK_ID);
+ assertEquals(SYSTEM_ID, serviceState.getSystemId());
+ assertEquals(NETWORK_ID, serviceState.getNetworkId());
+
assertTrue(serviceState.hashCode() > 0);
assertNotNull(serviceState.toString());
diff --git a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadFlowTest.java b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadFlowTest.java
index 5089381..e6a97ed 100644
--- a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadFlowTest.java
+++ b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadFlowTest.java
@@ -21,6 +21,7 @@
import android.os.Bundle;
import android.telephony.MbmsDownloadSession;
import android.telephony.cts.embmstestapp.CtsDownloadService;
+import android.telephony.mbms.DownloadRequest;
import android.telephony.mbms.MbmsDownloadReceiver;
import java.io.File;
@@ -29,14 +30,16 @@
public class MbmsDownloadFlowTest extends MbmsDownloadTestBase {
private File tempFileRootDir;
- private String tempFileRootDirPath;
+ private DownloadRequest testDownloadRequest;
@Override
public void setUp() throws Exception {
super.setUp();
+ testDownloadRequest = downloadRequestTemplate
+ .setAppIntent(new Intent(MbmsDownloadReceiverTest.APP_INTENT_ACTION))
+ .build();
tempFileRootDir = new File(mContext.getFilesDir(), "CtsTestDir");
tempFileRootDir.mkdir();
- tempFileRootDirPath = tempFileRootDir.getCanonicalPath();
mDownloadSession.setTempFileRootDirectory(tempFileRootDir);
}
@@ -49,15 +52,15 @@
public void testFileDownloadFlow() throws Exception {
MbmsDownloadReceiverTest.AppIntentCapture captor =
- new MbmsDownloadReceiverTest.AppIntentCapture(mContext, mCallbackHandler);
- mDownloadSession.download(MbmsDownloadReceiverTest.TEST_DOWNLOAD_REQUEST);
+ new MbmsDownloadReceiverTest.AppIntentCapture(mContext, mHandler);
+ mDownloadSession.download(testDownloadRequest);
mMiddlewareControl.actuallyStartDownloadFlow();
Intent downloadDoneIntent = captor.getIntent();
assertEquals(MbmsDownloadReceiverTest.APP_INTENT_ACTION, downloadDoneIntent.getAction());
assertEquals(MbmsDownloadSession.RESULT_SUCCESSFUL,
downloadDoneIntent.getIntExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT, -1));
- assertEquals(MbmsDownloadReceiverTest.TEST_DOWNLOAD_REQUEST,
+ assertEquals(testDownloadRequest,
downloadDoneIntent.getParcelableExtra(
MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST));
assertEquals(CtsDownloadService.FILE_INFO,
diff --git a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadReceiverTest.java b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadReceiverTest.java
index 0d88f13..8232271 100644
--- a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadReceiverTest.java
+++ b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadReceiverTest.java
@@ -47,9 +47,6 @@
public static final String APP_INTENT_ACTION =
"android.telephony.embms.cts.ACTION_TEST_DOWNLOAD_COMPLETE";
- public static final DownloadRequest TEST_DOWNLOAD_REQUEST = DOWNLOAD_REQUEST_TEMPLATE
- .setAppIntent(new Intent(APP_INTENT_ACTION))
- .build();
public static class AppIntentCapture {
private final BlockingQueue<Intent> mReceivedIntent = new LinkedBlockingQueue<>();
@@ -82,10 +79,14 @@
private MbmsDownloadReceiver mReceiver;
private File tempFileRootDir;
private String tempFileRootDirPath;
+ private DownloadRequest testDownloadRequest;
@Override
public void setUp() throws Exception {
super.setUp();
+ testDownloadRequest = downloadRequestTemplate
+ .setAppIntent(new Intent(APP_INTENT_ACTION))
+ .build();
mReceiver = new MbmsDownloadReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(VendorUtils.ACTION_DOWNLOAD_RESULT_INTERNAL);
@@ -140,9 +141,9 @@
intentForReceiverTest.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT,
MbmsDownloadSession.RESULT_CANCELLED);
intentForReceiverTest.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST,
- TEST_DOWNLOAD_REQUEST);
+ testDownloadRequest);
- AppIntentCapture intentCaptor = new AppIntentCapture(mContext, mCallbackHandler);
+ AppIntentCapture intentCaptor = new AppIntentCapture(mContext, mHandler);
sendBroadcastAndValidate(intentForReceiverTest, MbmsDownloadReceiver.RESULT_OK);
Intent receivedIntent = intentCaptor.getIntent();
@@ -150,7 +151,7 @@
assertEquals(MbmsDownloadSession.RESULT_CANCELLED,
receivedIntent.getIntExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT, -1));
- assertEquals(TEST_DOWNLOAD_REQUEST,
+ assertEquals(testDownloadRequest,
receivedIntent.getParcelableExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST));
}
@@ -162,7 +163,7 @@
intentForReceiverTest.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT,
MbmsDownloadSession.RESULT_SUCCESSFUL);
intentForReceiverTest.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST,
- TEST_DOWNLOAD_REQUEST);
+ testDownloadRequest);
intentForReceiverTest.putExtra(MbmsDownloadSession.EXTRA_MBMS_FILE_INFO,
CtsDownloadService.FILE_INFO);
intentForReceiverTest.putExtra(VendorUtils.EXTRA_FINAL_URI,
@@ -230,7 +231,7 @@
receivedExtras.add(getResultExtras(true));
receivedCode.add(getResultCode());
}
- }, mCallbackHandler, -1, null, null);
+ }, mHandler, -1, null, null);
try {
assertEquals(expectedCode,
diff --git a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadSessionTest.java b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadSessionTest.java
index 29e70bb..5e70828 100644
--- a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadSessionTest.java
+++ b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadSessionTest.java
@@ -33,7 +33,7 @@
public void testDuplicateSession() throws Exception {
try {
MbmsDownloadSession failure = MbmsDownloadSession.create(
- mContext, mCallback, mCallbackHandler);
+ mContext, mCallbackExecutor, mCallback);
fail("Duplicate create should've thrown an exception");
} catch (IllegalStateException e) {
// Succeed
@@ -139,7 +139,7 @@
}
public void testResetDownloadKnowledge() throws Exception {
- DownloadRequest request = DOWNLOAD_REQUEST_TEMPLATE.build();
+ DownloadRequest request = downloadRequestTemplate.build();
mDownloadSession.resetDownloadKnowledge(request);
List<Bundle> resetDownloadKnowledgeCalls =
@@ -150,7 +150,7 @@
}
public void testGetDownloadStatus() throws Exception {
- DownloadRequest request = DOWNLOAD_REQUEST_TEMPLATE.build();
+ DownloadRequest request = downloadRequestTemplate.build();
mDownloadSession.requestDownloadState(request, CtsDownloadService.FILE_INFO);
List<Bundle> getDownloadStatusCalls =
@@ -163,7 +163,7 @@
}
public void testCancelDownload() throws Exception {
- DownloadRequest request = DOWNLOAD_REQUEST_TEMPLATE.build();
+ DownloadRequest request = downloadRequestTemplate.build();
mDownloadSession.cancelDownload(request);
List<Bundle> cancelDownloadCalls =
@@ -174,7 +174,11 @@
}
public void testListPendingDownloads() throws Exception {
- DownloadRequest request = DOWNLOAD_REQUEST_TEMPLATE.setAppIntent(new Intent()).build();
+ File tempFileRootDir = new File(mContext.getFilesDir(), "CtsTestDir");
+ tempFileRootDir.mkdir();
+ mDownloadSession.setTempFileRootDirectory(tempFileRootDir);
+
+ DownloadRequest request = downloadRequestTemplate.setAppIntent(new Intent()).build();
mDownloadSession.download(request);
List<DownloadRequest> downloads = mDownloadSession.listPendingDownloads();
@@ -194,14 +198,12 @@
assertNotSame(mDownloadSession.getTempFileRootDirectory(), tempFileDirName);
}
- public void testDownloadRequestOpacity() throws Exception {
+ public void testDownloadRequestSerialization() throws Exception {
Intent intent = new Intent("sample_intent_action");
- DownloadRequest request = DOWNLOAD_REQUEST_TEMPLATE.setAppIntent(intent).build();
- DownloadRequest newRequest = new DownloadRequest.Builder(request.getSourceUri())
- .setServiceId(request.getFileServiceId())
- .setSubscriptionId(request.getSubscriptionId())
- .setOpaqueData(request.getOpaqueData())
- .build();
+ DownloadRequest request = downloadRequestTemplate.setAppIntent(intent).build();
+ DownloadRequest newRequest =
+ DownloadRequest.Builder.fromSerializedRequest(request.toByteArray())
+ .build();
assertEquals(request, newRequest);
}
diff --git a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadStateCallbackTest.java b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadStateCallbackTest.java
index a5cc2d0..c01de7c 100644
--- a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadStateCallbackTest.java
+++ b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadStateCallbackTest.java
@@ -83,8 +83,8 @@
public void testFullCallback() throws Exception {
int sampleInt = 10;
TestDSCallback callback = new TestDSCallback(DownloadStateCallback.ALL_UPDATES);
- DownloadRequest request = DOWNLOAD_REQUEST_TEMPLATE.build();
- mDownloadSession.registerStateCallback(request, callback, mCallbackHandler);
+ DownloadRequest request = downloadRequestTemplate.build();
+ mDownloadSession.registerStateCallback(request, mCallbackExecutor, callback);
mMiddlewareControl.fireOnProgressUpdated(request, CtsDownloadService.FILE_INFO,
sampleInt, sampleInt, sampleInt, sampleInt);
SomeArgs progressArgs = callback.waitOnProgressUpdated(ASYNC_TIMEOUT);
@@ -104,8 +104,8 @@
public void testDeregistration() throws Exception {
TestDSCallback callback = new TestDSCallback(DownloadStateCallback.ALL_UPDATES);
- DownloadRequest request = DOWNLOAD_REQUEST_TEMPLATE.build();
- mDownloadSession.registerStateCallback(request, callback, mCallbackHandler);
+ DownloadRequest request = downloadRequestTemplate.build();
+ mDownloadSession.registerStateCallback(request, mCallbackExecutor, callback);
mDownloadSession.unregisterStateCallback(request, callback);
mMiddlewareControl.fireOnStateUpdated(null, null, 0);
@@ -116,8 +116,8 @@
public void testCallbackFiltering1() throws Exception {
TestDSCallback callback = new TestDSCallback(DownloadStateCallback.PROGRESS_UPDATES);
- DownloadRequest request = DOWNLOAD_REQUEST_TEMPLATE.build();
- mDownloadSession.registerStateCallback(request, callback, mCallbackHandler);
+ DownloadRequest request = downloadRequestTemplate.build();
+ mDownloadSession.registerStateCallback(request, mCallbackExecutor, callback);
mMiddlewareControl.fireOnStateUpdated(null, null, 0);
assertNull(callback.waitOnStateUpdated(SHORT_TIMEOUT));
@@ -127,8 +127,8 @@
public void testCallbackFiltering2() throws Exception {
TestDSCallback callback = new TestDSCallback(DownloadStateCallback.STATE_UPDATES);
- DownloadRequest request = DOWNLOAD_REQUEST_TEMPLATE.build();
- mDownloadSession.registerStateCallback(request, callback, mCallbackHandler);
+ DownloadRequest request = downloadRequestTemplate.build();
+ mDownloadSession.registerStateCallback(request, mCallbackExecutor, callback);
mMiddlewareControl.fireOnStateUpdated(null, null, 0);
assertNotNull(callback.waitOnStateUpdated(SHORT_TIMEOUT));
diff --git a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadTestBase.java b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadTestBase.java
index 9da5f04..bde9de6 100644
--- a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadTestBase.java
+++ b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsDownloadTestBase.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
@@ -41,6 +42,7 @@
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -107,13 +109,12 @@
}
}
- static final DownloadRequest.Builder DOWNLOAD_REQUEST_TEMPLATE =
- new DownloadRequest.Builder(CtsDownloadService.DOWNLOAD_SOURCE_URI)
- .setServiceInfo(CtsDownloadService.FILE_SERVICE_INFO);
+ DownloadRequest.Builder downloadRequestTemplate;
Context mContext;
HandlerThread mHandlerThread;
- Handler mCallbackHandler;
+ Handler mHandler;
+ Executor mCallbackExecutor;
ICtsDownloadMiddlewareControl mMiddlewareControl;
MbmsDownloadSession mDownloadSession;
TestCallback mCallback = new TestCallback();
@@ -123,8 +124,16 @@
mContext = getInstrumentation().getContext();
mHandlerThread = new HandlerThread("EmbmsCtsTestWorker");
mHandlerThread.start();
- mCallbackHandler = new Handler(mHandlerThread.getLooper());
+ mHandler = new Handler(mHandlerThread.getLooper());
+ mCallbackExecutor = mHandler::post;
mCallback = new TestCallback();
+
+ File destinationDirectory = new File(mContext.getFilesDir(), "downloads");
+ destinationDirectory.mkdirs();
+ Uri destinationDirectoryUri = Uri.fromFile(destinationDirectory);
+ downloadRequestTemplate = new DownloadRequest.Builder(
+ CtsDownloadService.DOWNLOAD_SOURCE_URI, destinationDirectoryUri)
+ .setServiceInfo(CtsDownloadService.FILE_SERVICE_INFO);
getControlBinder();
setupDownloadSession();
}
@@ -138,7 +147,7 @@
private void setupDownloadSession() throws Exception {
mDownloadSession = MbmsDownloadSession.create(
- mContext, mCallback, mCallbackHandler);
+ mContext, mCallbackExecutor, mCallback);
assertNotNull(mDownloadSession);
assertTrue(mCallback.waitOnMiddlewareReady());
assertEquals(0, mCallback.getNumErrorCalls());
diff --git a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsStreamingServiceTest.java b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsStreamingServiceTest.java
index 42e5618..835a6e4 100644
--- a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsStreamingServiceTest.java
+++ b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsStreamingServiceTest.java
@@ -127,7 +127,7 @@
public void testStartStreaming() throws Exception {
StreamingService streamingService = mStreamingSession.startStreaming(
CtsStreamingService .STREAMING_SERVICE_INFO,
- mStreamingServiceCallback, mCallbackHandler);
+ mCallbackExecutor, mStreamingServiceCallback);
assertNotNull(streamingService);
assertEquals(CtsStreamingService.STREAMING_SERVICE_INFO, streamingService.getInfo());
@@ -145,7 +145,7 @@
public void testGetPlaybackUri() throws Exception {
StreamingService streamingService = mStreamingSession.startStreaming(
CtsStreamingService .STREAMING_SERVICE_INFO,
- mStreamingServiceCallback, mCallbackHandler);
+ mCallbackExecutor, mStreamingServiceCallback);
assertEquals(CtsStreamingService.STREAMING_URI, streamingService.getPlaybackUri());
List<List<Object>> getPlaybackUriCalls =
@@ -158,8 +158,8 @@
public void testStopStreaming() throws Exception {
StreamingService streamingService = mStreamingSession.startStreaming(
CtsStreamingService .STREAMING_SERVICE_INFO,
- mStreamingServiceCallback, mCallbackHandler);
- streamingService.stopStreaming();
+ mCallbackExecutor, mStreamingServiceCallback);
+ streamingService.close();
List<List<Object>> stopStreamingCalls =
getMiddlewareCalls(CtsStreamingService.METHOD_STOP_STREAMING);
assertEquals(1, stopStreamingCalls.size());
@@ -170,7 +170,7 @@
public void testStreamingCallbacks() throws Exception {
mStreamingSession.startStreaming(
CtsStreamingService .STREAMING_SERVICE_INFO,
- mStreamingServiceCallback, mCallbackHandler);
+ mCallbackExecutor, mStreamingServiceCallback);
mMiddlewareControl.fireErrorOnStream(
MbmsErrors.StreamingErrors.ERROR_UNABLE_TO_START_SERVICE, "");
@@ -194,7 +194,7 @@
mMiddlewareControl.forceErrorCode(
MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE);
mStreamingSession.startStreaming(CtsStreamingService.STREAMING_SERVICE_INFO,
- mStreamingServiceCallback, mCallbackHandler);
+ mCallbackExecutor, mStreamingServiceCallback);
assertEquals(MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE,
mCallback.waitOnError().arg1);
}
diff --git a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsStreamingSessionTest.java b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsStreamingSessionTest.java
index 92b3fc9..0aeb734 100644
--- a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsStreamingSessionTest.java
+++ b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsStreamingSessionTest.java
@@ -29,7 +29,7 @@
public void testDuplicateSession() throws Exception {
try {
MbmsStreamingSession failure = MbmsStreamingSession.create(
- mContext, mCallback, mCallbackHandler);
+ mContext, mCallbackExecutor, mCallback);
fail("Duplicate create should've thrown an exception");
} catch (IllegalStateException e) {
// Succeed
diff --git a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsStreamingTestBase.java b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsStreamingTestBase.java
index e170998..e4bb27b 100644
--- a/tests/tests/telephony/src/android/telephony/embms/cts/MbmsStreamingTestBase.java
+++ b/tests/tests/telephony/src/android/telephony/embms/cts/MbmsStreamingTestBase.java
@@ -21,6 +21,7 @@
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -87,7 +88,7 @@
Context mContext;
HandlerThread mHandlerThread;
- Handler mCallbackHandler;
+ Executor mCallbackExecutor;
ICtsStreamingMiddlewareControl mMiddlewareControl;
MbmsStreamingSession mStreamingSession;
TestCallback mCallback = new TestCallback();
@@ -97,7 +98,7 @@
mContext = getInstrumentation().getContext();
mHandlerThread = new HandlerThread("EmbmsCtsTestWorker");
mHandlerThread.start();
- mCallbackHandler = new Handler(mHandlerThread.getLooper());
+ mCallbackExecutor = (new Handler(mHandlerThread.getLooper()))::post;
mCallback = new TestCallback();
getControlBinder();
setupStreamingSession();
@@ -112,7 +113,7 @@
private void setupStreamingSession() throws Exception {
mStreamingSession = MbmsStreamingSession.create(
- mContext, mCallback, mCallbackHandler);
+ mContext, mCallbackExecutor, mCallback);
assertNotNull(mStreamingSession);
assertTrue(mCallback.waitOnMiddlewareReady());
assertEquals(0, mCallback.getNumErrorCalls());
diff --git a/tests/tests/telephony2/Android.mk b/tests/tests/telephony2/Android.mk
index c755c2a..b86cae1 100644
--- a/tests/tests/telephony2/Android.mk
+++ b/tests/tests/telephony2/Android.mk
@@ -29,6 +29,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsTelephony2TestCases
+LOCAL_SDK_VERSION := current
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/tests/tests/text/src/android/text/cts/MeasuredTextTest.java b/tests/tests/text/src/android/text/cts/MeasuredTextTest.java
deleted file mode 100644
index 0ecd284..0000000
--- a/tests/tests/text/src/android/text/cts/MeasuredTextTest.java
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.text.cts;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.text.Layout;
-import android.text.MeasuredText;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.TextDirectionHeuristic;
-import android.text.TextDirectionHeuristics;
-import android.text.TextPaint;
-import android.text.style.LocaleSpan;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Locale;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class MeasuredTextTest {
-
- private static final CharSequence NULL_CHAR_SEQUENCE = null;
- private static final String STRING = "Hello, World!";
- private static final String MULTIPARA_STRING = "Hello,\nWorld!";
-
- private static final int SPAN_START = 3;
- private static final int SPAN_END = 7;
- private static final LocaleSpan SPAN = new LocaleSpan(Locale.US);
- private static final Spanned SPANNED;
- static {
- final SpannableStringBuilder ssb = new SpannableStringBuilder(STRING);
- ssb.setSpan(SPAN, SPAN_START, SPAN_END, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
- SPANNED = ssb;
- }
-
- private static final TextPaint PAINT = new TextPaint();
-
- private static final TextDirectionHeuristic LTR = TextDirectionHeuristics.LTR;
-
- @Test
- public void testBuilder() {
- assertNotNull(new MeasuredText.Builder(STRING, PAINT)
- .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
- .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE).build());
- assertNotNull(new MeasuredText.Builder(SPANNED, PAINT)
- .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
- .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE).build());
- }
-
- @Test
- public void testBuilder_withNull() {
- try {
- new MeasuredText.Builder(NULL_CHAR_SEQUENCE, PAINT);
- fail();
- } catch (NullPointerException e) {
- // pass
- }
- try {
- new MeasuredText.Builder(STRING, null);
- fail();
- } catch (NullPointerException e) {
- // pass
- }
- try {
- new MeasuredText.Builder(STRING, PAINT).setTextDirection(null);
- fail();
- } catch (NullPointerException e) {
- // pass
- }
- }
-
- @Test
- public void testBuilder_setRange() {
- assertNotNull(new MeasuredText.Builder(STRING, PAINT).setRange(0, STRING.length()).build());
- assertNotNull(new MeasuredText.Builder(STRING, PAINT)
- .setRange(1, STRING.length() - 1).build());
- assertNotNull(new MeasuredText.Builder(SPANNED, PAINT)
- .setRange(0, SPANNED.length()).build());
- assertNotNull(new MeasuredText.Builder(SPANNED, PAINT)
- .setRange(1, SPANNED.length() - 1).build());
- try {
- new MeasuredText.Builder(STRING, PAINT).setRange(-1, -1);
- fail();
- } catch (IllegalArgumentException e) {
- // pass
- }
- try {
- new MeasuredText.Builder(STRING, PAINT).setRange(100000, 100000);
- fail();
- } catch (IllegalArgumentException e) {
- // pass
- }
- try {
- new MeasuredText.Builder(STRING, PAINT).setRange(STRING.length() - 1, 0);
- fail();
- } catch (IllegalArgumentException e) {
- // pass
- }
- }
-
- @Test
- public void testCharSequenceInteferface() {
- final CharSequence s = new MeasuredText.Builder(STRING, PAINT).build();
- assertEquals(STRING.length(), s.length());
- assertEquals('H', s.charAt(0));
- assertEquals('e', s.charAt(1));
- assertEquals('l', s.charAt(2));
- assertEquals('l', s.charAt(3));
- assertEquals('o', s.charAt(4));
- assertEquals(',', s.charAt(5));
- assertEquals("Hello, World!", s.toString());
-
- // Even measure the part of the text, the CharSequence interface still works for original
- // text.
- // TODO: Should this work like substring?
- final CharSequence s2 = new MeasuredText.Builder(STRING, PAINT)
- .setRange(7, STRING.length()).build();
- assertEquals(STRING.length(), s2.length());
- assertEquals('H', s2.charAt(0));
- assertEquals('e', s2.charAt(1));
- assertEquals('l', s2.charAt(2));
- assertEquals('l', s2.charAt(3));
- assertEquals('o', s2.charAt(4));
- assertEquals(',', s2.charAt(5));
- assertEquals("Hello, World!", s2.toString());
-
- final CharSequence s3 = s.subSequence(0, 3);
- assertEquals(3, s3.length());
- assertEquals('H', s3.charAt(0));
- assertEquals('e', s3.charAt(1));
- assertEquals('l', s3.charAt(2));
-
- }
-
- @Test
- public void testSpannedInterface_Spanned() {
- final Spanned s = new MeasuredText.Builder(SPANNED, PAINT).build();
- final LocaleSpan[] spans = s.getSpans(0, s.length(), LocaleSpan.class);
- assertNotNull(spans);
- assertEquals(1, spans.length);
- assertEquals(SPAN, spans[0]);
-
- assertEquals(SPAN_START, s.getSpanStart(SPAN));
- assertEquals(SPAN_END, s.getSpanEnd(SPAN));
- assertTrue((s.getSpanFlags(SPAN) & Spanned.SPAN_INCLUSIVE_EXCLUSIVE) != 0);
-
- assertEquals(SPAN_START, s.nextSpanTransition(0, s.length(), LocaleSpan.class));
- assertEquals(SPAN_END, s.nextSpanTransition(SPAN_START, s.length(), LocaleSpan.class));
-
- final Spanned s2 = new MeasuredText.Builder(SPANNED, PAINT)
- .setRange(7, SPANNED.length()).build();
- final LocaleSpan[] spans2 = s2.getSpans(0, s2.length(), LocaleSpan.class);
- assertNotNull(spans2);
- assertEquals(1, spans2.length);
- assertEquals(SPAN, spans2[0]);
-
- assertEquals(SPAN_START, s2.getSpanStart(SPAN));
- assertEquals(SPAN_END, s2.getSpanEnd(SPAN));
- assertTrue((s2.getSpanFlags(SPAN) & Spanned.SPAN_INCLUSIVE_EXCLUSIVE) != 0);
-
- assertEquals(SPAN_START, s2.nextSpanTransition(0, s2.length(), LocaleSpan.class));
- assertEquals(SPAN_END, s2.nextSpanTransition(SPAN_START, s2.length(), LocaleSpan.class));
- }
-
- @Test
- public void testSpannedInterface_String() {
- final Spanned s = new MeasuredText.Builder(STRING, PAINT).build();
- LocaleSpan[] spans = s.getSpans(0, s.length(), LocaleSpan.class);
- assertNotNull(spans);
- assertEquals(0, spans.length);
-
- assertEquals(-1, s.getSpanStart(SPAN));
- assertEquals(-1, s.getSpanEnd(SPAN));
- assertEquals(0, s.getSpanFlags(SPAN));
-
- assertEquals(s.length(), s.nextSpanTransition(0, s.length(), LocaleSpan.class));
- }
-
- @Test
- public void testGetText() {
- assertSame(STRING, new MeasuredText.Builder(STRING, PAINT).build().getText());
- assertSame(SPANNED, new MeasuredText.Builder(SPANNED, PAINT).build().getText());
-
- assertSame(STRING, new MeasuredText.Builder(STRING, PAINT)
- .setRange(1, 5).build().getText());
- assertSame(SPANNED, new MeasuredText.Builder(SPANNED, PAINT)
- .setRange(1, 5).build().getText());
- }
-
- @Test
- public void testGetStartEnd() {
- assertEquals(0, new MeasuredText.Builder(STRING, PAINT).build().getStart());
- assertEquals(STRING.length(), new MeasuredText.Builder(STRING, PAINT).build().getEnd());
-
- assertEquals(1, new MeasuredText.Builder(STRING, PAINT).setRange(1, 5).build().getStart());
- assertEquals(5, new MeasuredText.Builder(STRING, PAINT).setRange(1, 5).build().getEnd());
-
- assertEquals(0, new MeasuredText.Builder(SPANNED, PAINT).build().getStart());
- assertEquals(SPANNED.length(), new MeasuredText.Builder(SPANNED, PAINT).build().getEnd());
-
- assertEquals(1, new MeasuredText.Builder(SPANNED, PAINT).setRange(1, 5).build().getStart());
- assertEquals(5, new MeasuredText.Builder(SPANNED, PAINT).setRange(1, 5).build().getEnd());
- }
-
- @Test
- public void testGetTextDir() {
- assertSame(TextDirectionHeuristics.FIRSTSTRONG_LTR,
- new MeasuredText.Builder(STRING, PAINT).build().getTextDir());
- assertSame(TextDirectionHeuristics.LTR,
- new MeasuredText.Builder(SPANNED, PAINT)
- .setTextDirection(TextDirectionHeuristics.LTR).build().getTextDir());
- }
-
- @Test
- public void testGetPaint() {
- // No Paint equality functions. Check only not null.
- assertNotNull(new MeasuredText.Builder(STRING, PAINT).build().getPaint());
- assertNotNull(new MeasuredText.Builder(SPANNED, PAINT).build().getPaint());
- }
-
- @Test
- public void testGetBreakStrategy() {
- assertEquals(Layout.BREAK_STRATEGY_HIGH_QUALITY,
- new MeasuredText.Builder(STRING, PAINT).build().getBreakStrategy());
- assertEquals(Layout.BREAK_STRATEGY_SIMPLE,
- new MeasuredText.Builder(STRING, PAINT)
- .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE).build().getBreakStrategy());
- }
-
- @Test
- public void testGetHyphenationFrequency() {
- assertEquals(Layout.HYPHENATION_FREQUENCY_NORMAL,
- new MeasuredText.Builder(STRING, PAINT).build().getHyphenationFrequency());
- assertEquals(Layout.HYPHENATION_FREQUENCY_NONE,
- new MeasuredText.Builder(STRING, PAINT)
- .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE).build()
- .getHyphenationFrequency());
- }
-
- @Test
- public void testGetParagraphCount() {
- final MeasuredText pm = new MeasuredText.Builder(STRING, PAINT).build();
- assertEquals(1, pm.getParagraphCount());
- assertEquals(0, pm.getParagraphStart(0));
- assertEquals(STRING.length(), pm.getParagraphEnd(0));
-
- final MeasuredText pm2 = new MeasuredText.Builder(STRING, PAINT).setRange(1, 9).build();
- assertEquals(1, pm2.getParagraphCount());
- assertEquals(1, pm2.getParagraphStart(0));
- assertEquals(9, pm2.getParagraphEnd(0));
-
- final MeasuredText pm3 = new MeasuredText.Builder(MULTIPARA_STRING, PAINT).build();
- assertEquals(2, pm3.getParagraphCount());
- assertEquals(0, pm3.getParagraphStart(0));
- assertEquals(7, pm3.getParagraphEnd(0));
- assertEquals(7, pm3.getParagraphStart(1));
- assertEquals(pm3.length(), pm3.getParagraphEnd(1));
-
- final MeasuredText pm4 = new MeasuredText.Builder(MULTIPARA_STRING, PAINT)
- .setRange(1, 5).build();
- assertEquals(1, pm4.getParagraphCount());
- assertEquals(1, pm4.getParagraphStart(0));
- assertEquals(5, pm4.getParagraphEnd(0));
-
- final MeasuredText pm5 = new MeasuredText.Builder(MULTIPARA_STRING, PAINT)
- .setRange(1, 9).build();
- assertEquals(2, pm5.getParagraphCount());
- assertEquals(1, pm5.getParagraphStart(0));
- assertEquals(7, pm5.getParagraphEnd(0));
- assertEquals(7, pm5.getParagraphStart(1));
- assertEquals(9, pm5.getParagraphEnd(1));
- }
-
-}
diff --git a/tests/tests/text/src/android/text/cts/PrecomputedTextTest.java b/tests/tests/text/src/android/text/cts/PrecomputedTextTest.java
new file mode 100644
index 0000000..8967d3a
--- /dev/null
+++ b/tests/tests/text/src/android/text/cts/PrecomputedTextTest.java
@@ -0,0 +1,246 @@
+/*
+ * 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.text.cts;
+
+import static android.text.TextDirectionHeuristics.LTR;
+import static android.text.TextDirectionHeuristics.RTL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.Layout;
+import android.text.PrecomputedText;
+import android.text.PrecomputedText.Params;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.TextDirectionHeuristics;
+import android.text.TextPaint;
+import android.text.style.LocaleSpan;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PrecomputedTextTest {
+
+ private static final CharSequence NULL_CHAR_SEQUENCE = null;
+ private static final String STRING = "Hello, World!";
+ private static final String MULTIPARA_STRING = "Hello,\nWorld!";
+
+ private static final int SPAN_START = 3;
+ private static final int SPAN_END = 7;
+ private static final LocaleSpan SPAN = new LocaleSpan(Locale.US);
+ private static final Spanned SPANNED;
+ static {
+ final SpannableStringBuilder ssb = new SpannableStringBuilder(STRING);
+ ssb.setSpan(SPAN, SPAN_START, SPAN_END, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+ SPANNED = ssb;
+ }
+
+ private static final TextPaint PAINT = new TextPaint();
+
+ @Test
+ public void testParams_create() {
+ assertNotNull(new Params.Builder(PAINT).build());
+ assertNotNull(new Params.Builder(PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE).build());
+ assertNotNull(new Params.Builder(PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL).build());
+ assertNotNull(new Params.Builder(PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setTextDirection(LTR).build());
+ }
+
+ @Test
+ public void testParams_SetGet() {
+ assertEquals(Layout.BREAK_STRATEGY_SIMPLE, new Params.Builder(PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE).build().getBreakStrategy());
+ assertEquals(Layout.HYPHENATION_FREQUENCY_NONE, new Params.Builder(PAINT)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE).build()
+ .getHyphenationFrequency());
+ assertEquals(RTL, new Params.Builder(PAINT).setTextDirection(RTL).build()
+ .getTextDirection());
+ }
+
+ @Test
+ public void testParams_GetDefaultValues() {
+ assertEquals(Layout.BREAK_STRATEGY_HIGH_QUALITY,
+ new Params.Builder(PAINT).build().getBreakStrategy());
+ assertEquals(Layout.HYPHENATION_FREQUENCY_NORMAL,
+ new Params.Builder(PAINT).build().getHyphenationFrequency());
+ assertEquals(TextDirectionHeuristics.FIRSTSTRONG_LTR,
+ new Params.Builder(PAINT).build().getTextDirection());
+ }
+
+ @Test
+ public void testParams_equals() {
+ final Params base = new Params.Builder(PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setTextDirection(LTR).build();
+
+ assertFalse(base.equals(null));
+ assertTrue(base.equals(base));
+ assertFalse(base.equals(new Object()));
+
+ Params other = new Params.Builder(PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setTextDirection(LTR).build();
+ assertTrue(base.equals(other));
+ assertTrue(other.equals(base));
+ assertEquals(base.hashCode(), other.hashCode());
+
+ other = new Params.Builder(PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setTextDirection(LTR).build();
+ assertFalse(base.equals(other));
+ assertFalse(other.equals(base));
+
+ other = new Params.Builder(PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+ .setTextDirection(LTR).build();
+ assertFalse(base.equals(other));
+ assertFalse(other.equals(base));
+
+
+ other = new Params.Builder(PAINT)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setTextDirection(RTL).build();
+ assertFalse(base.equals(other));
+ assertFalse(other.equals(base));
+
+
+ TextPaint anotherPaint = new TextPaint(PAINT);
+ anotherPaint.setTextSize(PAINT.getTextSize() * 2.0f);
+ other = new Params.Builder(anotherPaint)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setTextDirection(LTR).build();
+ assertFalse(base.equals(other));
+ assertFalse(other.equals(base));
+
+ }
+
+ @Test
+ public void testCreate_withNull() {
+ final Params param = new Params.Builder(PAINT).build();
+ try {
+ PrecomputedText.create(NULL_CHAR_SEQUENCE, param);
+ fail();
+ } catch (NullPointerException e) {
+ // pass
+ }
+ try {
+ PrecomputedText.create(STRING, null);
+ fail();
+ } catch (NullPointerException e) {
+ // pass
+ }
+ }
+
+ @Test
+ public void testCharSequenceInteface() {
+ final Params param = new Params.Builder(PAINT).build();
+ final CharSequence s = PrecomputedText.create(STRING, param);
+ assertEquals(STRING.length(), s.length());
+ assertEquals('H', s.charAt(0));
+ assertEquals('e', s.charAt(1));
+ assertEquals('l', s.charAt(2));
+ assertEquals('l', s.charAt(3));
+ assertEquals('o', s.charAt(4));
+ assertEquals(',', s.charAt(5));
+ assertEquals("Hello, World!", s.toString());
+
+ final CharSequence s3 = s.subSequence(0, 3);
+ assertEquals(3, s3.length());
+ assertEquals('H', s3.charAt(0));
+ assertEquals('e', s3.charAt(1));
+ assertEquals('l', s3.charAt(2));
+
+ }
+
+ @Test
+ public void testSpannedInterface_Spanned() {
+ final Params param = new Params.Builder(PAINT).build();
+ final Spanned s = PrecomputedText.create(SPANNED, param);
+ final LocaleSpan[] spans = s.getSpans(0, s.length(), LocaleSpan.class);
+ assertNotNull(spans);
+ assertEquals(1, spans.length);
+ assertEquals(SPAN, spans[0]);
+
+ assertEquals(SPAN_START, s.getSpanStart(SPAN));
+ assertEquals(SPAN_END, s.getSpanEnd(SPAN));
+ assertTrue((s.getSpanFlags(SPAN) & Spanned.SPAN_INCLUSIVE_EXCLUSIVE) != 0);
+
+ assertEquals(SPAN_START, s.nextSpanTransition(0, s.length(), LocaleSpan.class));
+ assertEquals(SPAN_END, s.nextSpanTransition(SPAN_START, s.length(), LocaleSpan.class));
+ }
+
+ @Test
+ public void testSpannedInterface_String() {
+ final Params param = new Params.Builder(PAINT).build();
+ final Spanned s = PrecomputedText.create(STRING, param);
+ LocaleSpan[] spans = s.getSpans(0, s.length(), LocaleSpan.class);
+ assertNotNull(spans);
+ assertEquals(0, spans.length);
+
+ assertEquals(-1, s.getSpanStart(SPAN));
+ assertEquals(-1, s.getSpanEnd(SPAN));
+ assertEquals(0, s.getSpanFlags(SPAN));
+
+ assertEquals(s.length(), s.nextSpanTransition(0, s.length(), LocaleSpan.class));
+ }
+
+ @Test
+ public void testGetText() {
+ final Params param = new Params.Builder(PAINT).build();
+ assertEquals(STRING.toString(), PrecomputedText.create(STRING, param).getText().toString());
+ assertEquals(SPANNED.toString(),
+ PrecomputedText.create(SPANNED, param).getText().toString());
+ }
+
+ @Test
+ public void testGetParagraphCount() {
+ final Params param = new Params.Builder(PAINT).build();
+ final PrecomputedText pm = PrecomputedText.create(STRING, param);
+ assertEquals(1, pm.getParagraphCount());
+ assertEquals(0, pm.getParagraphStart(0));
+ assertEquals(STRING.length(), pm.getParagraphEnd(0));
+
+ final PrecomputedText pm1 = PrecomputedText.create(MULTIPARA_STRING, param);
+ assertEquals(2, pm1.getParagraphCount());
+ assertEquals(0, pm1.getParagraphStart(0));
+ assertEquals(7, pm1.getParagraphEnd(0));
+ assertEquals(7, pm1.getParagraphStart(1));
+ assertEquals(pm1.length(), pm1.getParagraphEnd(1));
+ }
+
+}
diff --git a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
index fe05167..8113615 100644
--- a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
@@ -22,29 +22,29 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Typeface;
+import android.os.LocaleList;
import android.support.test.filters.SmallTest;
import android.support.test.filters.Suppress;
import android.support.test.runner.AndroidJUnit4;
import android.text.Editable;
import android.text.Layout;
import android.text.Layout.Alignment;
-import android.text.MeasuredText;
+import android.text.PrecomputedText;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.SpannedString;
import android.text.StaticLayout;
+import android.text.TextDirectionHeuristic;
import android.text.TextDirectionHeuristics;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.text.method.cts.EditorState;
import android.text.style.StyleSpan;
-import android.text.style.TextAppearanceSpan;
import org.junit.Before;
import org.junit.Test;
@@ -1283,31 +1283,186 @@
return bmp;
}
- @Test
- public void testPremeasured() {
- final float wholeWidth = mDefaultPaint.measureText(LOREM_IPSUM);
+ private static String textPaintToString(TextPaint p) {
+ return "{"
+ + "mTextSize=" + p.getTextSize() + ", "
+ + "mTextSkewX=" + p.getTextSkewX() + ", "
+ + "mTextScaleX=" + p.getTextScaleX() + ", "
+ + "mLetterSpacing=" + p.getLetterSpacing() + ", "
+ + "mFlags=" + p.getFlags() + ", "
+ + "mTextLocales=" + p.getTextLocales() + ", "
+ + "mFontVariationSettings=" + p.getFontVariationSettings() + ", "
+ + "mTypeface=" + p.getTypeface() + ", "
+ + "mFontFeatureSettings=" + p.getFontFeatureSettings()
+ + "}";
+ }
+
+ private static String directionToString(TextDirectionHeuristic dir) {
+ if (dir == TextDirectionHeuristics.LTR) {
+ return "LTR";
+ } else if (dir == TextDirectionHeuristics.RTL) {
+ return "RTL";
+ } else if (dir == TextDirectionHeuristics.FIRSTSTRONG_LTR) {
+ return "FIRSTSTRONG_LTR";
+ } else if (dir == TextDirectionHeuristics.FIRSTSTRONG_RTL) {
+ return "FIRSTSTRONG_RTL";
+ } else if (dir == TextDirectionHeuristics.ANYRTL_LTR) {
+ return "ANYRTL_LTR";
+ } else {
+ throw new RuntimeException("Unknown Direction");
+ }
+ }
+
+ static class LayoutParam {
+ final int mStrategy;
+ final int mFrequency;
+ final TextPaint mPaint;
+ final TextDirectionHeuristic mDir;
+
+ LayoutParam(int strategy, int frequency, TextPaint paint, TextDirectionHeuristic dir) {
+ mStrategy = strategy;
+ mFrequency = frequency;
+ mPaint = new TextPaint(paint);
+ mDir = dir;
+ }
+
+ @Override
+ public String toString() {
+ return "{"
+ + "mStrategy=" + mStrategy + ", "
+ + "mFrequency=" + mFrequency + ", "
+ + "mPaint=" + textPaintToString(mPaint) + ", "
+ + "mDir=" + directionToString(mDir)
+ + "}";
+
+ }
+
+ Layout getLayout(CharSequence text, int width) {
+ return StaticLayout.Builder.obtain(text, 0, text.length(), mPaint, width)
+ .setBreakStrategy(mStrategy).setHyphenationFrequency(mFrequency)
+ .setTextDirection(mDir).build();
+ }
+
+ PrecomputedText getPrecomputedText(CharSequence text) {
+ PrecomputedText.Params param = new PrecomputedText.Params.Builder(mPaint)
+ .setBreakStrategy(mStrategy)
+ .setHyphenationFrequency(mFrequency)
+ .setTextDirection(mDir).build();
+ return PrecomputedText.create(text, param);
+ }
+ };
+
+ void assertSameStaticLayout(CharSequence text, LayoutParam measuredTextParam,
+ LayoutParam staticLayoutParam) {
+ String msg = "StaticLayout for " + staticLayoutParam + " with PrecomputedText"
+ + " created with " + measuredTextParam + " must output the same BMP.";
+
+ final float wholeWidth = mDefaultPaint.measureText(text.toString());
final int lineWidth = (int) (wholeWidth / 10.0f); // Make 10 lines per paragraph.
- final ColorStateList textColor = ColorStateList.valueOf(0x88FF0000);
- final TextAppearanceSpan span = new TextAppearanceSpan(
- "serif", Typeface.BOLD, 64 /* text size */, textColor, textColor);
- final SpannableStringBuilder ssb = new SpannableStringBuilder(
- LOREM_IPSUM + "\n" + LOREM_IPSUM);
- ssb.setSpan(span, 0, LOREM_IPSUM.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+ // Static layout parameter should be used for the final output.
+ final Layout expectedLayout = staticLayoutParam.getLayout(text, lineWidth);
- final Layout layout = StaticLayout.Builder.obtain(ssb, 0, ssb.length(), mDefaultPaint,
- lineWidth).build();
+ final PrecomputedText mt = measuredTextParam.getPrecomputedText(text);
+ final Layout resultLayout = StaticLayout.Builder.obtain(mt, 0, mt.length(),
+ staticLayoutParam.mPaint, lineWidth)
+ .setBreakStrategy(staticLayoutParam.mStrategy)
+ .setHyphenationFrequency(staticLayoutParam.mFrequency)
+ .setTextDirection(staticLayoutParam.mDir).build();
- final MeasuredText premeasuredText = new MeasuredText.Builder(ssb, mDefaultPaint).build();
- final Layout premLayout = StaticLayout.Builder.obtain(premeasuredText, 0,
- premeasuredText.length(), mDefaultPaint, lineWidth)
- .setTextDirection(TextDirectionHeuristics.FIRSTSTRONG_LTR).build();
+ assertEquals(msg, expectedLayout.getHeight(), resultLayout.getHeight(), 0.0f);
- assertEquals(layout.getHeight(), premLayout.getHeight(), 0.0f);
+ final Bitmap expectedBMP = drawToBitmap(expectedLayout);
+ final Bitmap resultBMP = drawToBitmap(resultLayout);
- final Bitmap bmp = drawToBitmap(layout);
- final Bitmap premBmp = drawToBitmap(premLayout);
+ assertTrue(msg, resultBMP.sameAs(expectedBMP));
+ }
- assertTrue(bmp.sameAs(premBmp)); // Need to be pixel perfect.
+ @Test
+ public void testPrecomputedText() {
+ int[] breaks = {
+ Layout.BREAK_STRATEGY_SIMPLE,
+ Layout.BREAK_STRATEGY_HIGH_QUALITY,
+ Layout.BREAK_STRATEGY_BALANCED,
+ };
+
+ int[] frequencies = {
+ Layout.HYPHENATION_FREQUENCY_NORMAL,
+ Layout.HYPHENATION_FREQUENCY_FULL,
+ Layout.HYPHENATION_FREQUENCY_NONE,
+ };
+
+ TextDirectionHeuristic[] dirs = {
+ TextDirectionHeuristics.LTR,
+ TextDirectionHeuristics.RTL,
+ TextDirectionHeuristics.FIRSTSTRONG_LTR,
+ TextDirectionHeuristics.FIRSTSTRONG_RTL,
+ TextDirectionHeuristics.ANYRTL_LTR,
+ };
+
+ float[] textSizes = {
+ 8.0f, 16.0f, 32.0f
+ };
+
+ LocaleList[] locales = {
+ LocaleList.forLanguageTags("en-US"),
+ LocaleList.forLanguageTags("ja-JP"),
+ LocaleList.forLanguageTags("en-US,ja-JP"),
+ };
+
+ TextPaint paint = new TextPaint();
+
+ // If the PrecomputedText is created with the same argument of the StaticLayout, generate
+ // the same bitmap.
+ for (int b : breaks) {
+ for (int f : frequencies) {
+ for (TextDirectionHeuristic dir : dirs) {
+ for (float textSize : textSizes) {
+ for (LocaleList locale : locales) {
+ paint.setTextSize(textSize);
+ paint.setTextLocales(locale);
+
+ assertSameStaticLayout(LOREM_IPSUM,
+ new LayoutParam(b, f, paint, dir),
+ new LayoutParam(b, f, paint, dir));
+ }
+ }
+ }
+ }
+ }
+
+ // If the parameters are different, the output of the static layout must be
+ // same bitmap.
+ for (int bi = 0; bi < breaks.length; bi++) {
+ for (int fi = 0; fi < frequencies.length; fi++) {
+ for (int diri = 0; diri < dirs.length; diri++) {
+ for (int sizei = 0; sizei < textSizes.length; sizei++) {
+ for (int localei = 0; localei < locales.length; localei++) {
+ TextPaint p1 = new TextPaint();
+ TextPaint p2 = new TextPaint();
+
+ p1.setTextSize(textSizes[sizei]);
+ p2.setTextSize(textSizes[(sizei + 1) % textSizes.length]);
+
+ p1.setTextLocales(locales[localei]);
+ p2.setTextLocales(locales[(localei + 1) % locales.length]);
+
+ int b1 = breaks[bi];
+ int b2 = breaks[(bi + 1) % breaks.length];
+
+ int f1 = frequencies[fi];
+ int f2 = frequencies[(fi + 1) % frequencies.length];
+
+ TextDirectionHeuristic dir1 = dirs[diri];
+ TextDirectionHeuristic dir2 = dirs[(diri + 1) % dirs.length];
+
+ assertSameStaticLayout(LOREM_IPSUM,
+ new LayoutParam(b1, f1, p1, dir1),
+ new LayoutParam(b2, f2, p2, dir2));
+ }
+ }
+ }
+ }
+ }
}
}
diff --git a/tests/tests/toast/Android.mk b/tests/tests/toast/Android.mk
index 1ba7d79..99af898 100644
--- a/tests/tests/toast/Android.mk
+++ b/tests/tests/toast/Android.mk
@@ -28,6 +28,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsToastTestCases
+LOCAL_SDK_VERSION := current
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/toastlegacy/Android.mk b/tests/tests/toastlegacy/Android.mk
index 335c539..217fe55 100644
--- a/tests/tests/toastlegacy/Android.mk
+++ b/tests/tests/toastlegacy/Android.mk
@@ -29,6 +29,7 @@
../toast/src/android/widget/toast/cts/BaseToastTest.java
LOCAL_PACKAGE_NAME := CtsToastLegacyTestCases
+LOCAL_SDK_VERSION := current
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
index 9d33a0a..a1ba898 100755
--- a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
+++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
@@ -25,6 +25,7 @@
import android.content.Intent;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
import android.test.InstrumentationTestCase;
import android.view.FrameStats;
@@ -61,6 +62,7 @@
grantWriteSecureSettingsPermission(uiAutomation);
}
+ @Presubmit
public void testWindowContentFrameStats() throws Exception {
Activity activity = null;
try {
@@ -119,6 +121,7 @@
}
}
+ @Presubmit
public void testWindowContentFrameStatsNoAnimation() throws Exception {
Activity activity = null;
try {
@@ -169,6 +172,7 @@
}
}
+ @Presubmit
public void testWindowAnimationFrameStats() throws Exception {
Activity firstActivity = null;
Activity secondActivity = null;
@@ -265,6 +269,7 @@
assertEquals(stats.getEndTimeNano(), FrameStats.UNDEFINED_TIME_NANO);
}
+ @Presubmit
public void testUsingUiAutomationAfterDestroy_shouldThrowException() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
uiAutomation.destroy();
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
index ee46601..abaf96e 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
@@ -39,7 +39,7 @@
@Test
public void testScreenshot() {
for (int i = 0 ; i < 500 ; i ++) {
- takeScreenshot(new Point());
+ takeScreenshot(new TestPositionInfo(new Point(), new Point()));
System.gc();
}
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
index ae8f57e..7f588bd 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
@@ -104,6 +104,17 @@
}
@Test
+ public void testLayerPaintXfermodeWithSoftware() {
+ createTest()
+ .addLayout(R.layout.simple_red_layout, (ViewInitializer) view -> {
+ Paint paint = new Paint();
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+ view.setLayerType(View.LAYER_TYPE_SOFTWARE, paint);
+ }, true)
+ .runWithVerifier(new ColorVerifier(Color.TRANSPARENT));
+ }
+
+ @Test
public void testLayerPaintColorFilter() {
// Red, fully desaturated. Note that it's not 255/3 in each channel.
// See ColorMatrix#setSaturation()
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
index 741c35c..2e1ce85 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
@@ -15,17 +15,13 @@
*/
package android.uirendering.cts.testclasses;
-import com.android.compatibility.common.util.SynchronousPixelCopy;
-
import android.animation.ObjectAnimator;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.Point;
import android.graphics.Rect;
import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapverifiers.ColorVerifier;
@@ -40,6 +36,8 @@
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
+import com.android.compatibility.common.util.SynchronousPixelCopy;
+
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -111,9 +109,11 @@
mAnimator.cancel();
}
};
- Screenshotter screenshotter = testOffset -> {
+ Screenshotter screenshotter = testPositionInfo -> {
Bitmap source = getInstrumentation().getUiAutomation().takeScreenshot();
- return Bitmap.createBitmap(source, testOffset.x, testOffset.y, TEST_WIDTH, TEST_HEIGHT);
+ return Bitmap.createBitmap(source,
+ testPositionInfo.screenOffset.x, testPositionInfo.screenOffset.y,
+ TEST_WIDTH, TEST_HEIGHT);
};
createTest()
.addLayout(R.layout.frame_layout, initializer, true)
@@ -131,7 +131,7 @@
}
@Override
- public Bitmap takeScreenshot(Point point /* ignored */) {
+ public Bitmap takeScreenshot(TestPositionInfo testPositionInfo) {
SynchronousPixelCopy copy = new SynchronousPixelCopy();
Bitmap dest = Bitmap.createBitmap(
TEST_WIDTH, TEST_HEIGHT, Config.ARGB_8888);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
index 99f2780..f94047d 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -118,26 +118,25 @@
}
}
- public Bitmap takeScreenshot(Point testOffset) {
+ public Bitmap takeScreenshot(TestPositionInfo testPositionInfo) {
if (mScreenshotter == null) {
SynchronousPixelCopy copy = new SynchronousPixelCopy();
Bitmap dest = Bitmap.createBitmap(
TEST_WIDTH, TEST_HEIGHT,
getActivity().getWindow().isWideColorGamut()
? Config.RGBA_F16 : Config.ARGB_8888);
- Rect srcRect = new Rect(testOffset.x, testOffset.y,
- testOffset.x + TEST_WIDTH, testOffset.y + TEST_HEIGHT);
- Log.d("UiRendering", "capturing screenshot of " + srcRect.toShortString());
+ Rect srcRect = new Rect(0, 0, TEST_WIDTH, TEST_HEIGHT);
+ srcRect.offset(testPositionInfo.surfaceOffset.x, testPositionInfo.surfaceOffset.y);
+ Log.d(TAG, "capturing screenshot of " + srcRect.toShortString());
int copyResult = copy.request(getActivity().getWindow(), srcRect, dest);
Assert.assertEquals(PixelCopy.SUCCESS, copyResult);
return dest;
} else {
- return mScreenshotter.takeScreenshot(testOffset);
+ return mScreenshotter.takeScreenshot(testPositionInfo);
}
}
-
- protected Point runRenderSpec(TestCase testCase) {
- Point testOffset = getActivity().enqueueRenderSpecAndWait(
+ protected TestPositionInfo runRenderSpec(TestCase testCase) {
+ TestPositionInfo testPositionInfo = getActivity().enqueueRenderSpecAndWait(
testCase.layoutID, testCase.canvasClient,
testCase.viewInitializer, testCase.useHardware, testCase.usePicture);
testCase.wasTestRan = true;
@@ -148,15 +147,14 @@
throw new RuntimeException("readyFence didn't signal within 5 seconds");
}
}
- return testOffset;
+ return testPositionInfo;
}
/**
* Used to execute a specific part of a test and get the resultant bitmap
*/
protected Bitmap captureRenderSpec(TestCase testCase) {
- Point testOffset = runRenderSpec(testCase);
- return takeScreenshot(testOffset);
+ return takeScreenshot(runRenderSpec(testCase));
}
protected TestCaseBuilder createTest() {
@@ -165,8 +163,28 @@
return mTestCaseBuilder;
}
+ public static class TestPositionInfo {
+ /**
+ * Position of capture area in surface space - use this offset for e.g.
+ * PixelCopy from a window's surface.
+ */
+ public final Point surfaceOffset;
+
+ /**
+ * Position of capture area in screen space - use this offset for e.g.
+ * {@code getInstrumentation().getUiAutomation().takeScreenshot()},
+ * since those screenshots are captured in screen space.
+ */
+ public final Point screenOffset;
+
+ public TestPositionInfo(Point surfaceOffset, Point screenOffset) {
+ this.surfaceOffset = surfaceOffset;
+ this.screenOffset = screenOffset;
+ }
+ }
+
public interface Screenshotter {
- Bitmap takeScreenshot(Point point);
+ Bitmap takeScreenshot(TestPositionInfo params);
}
/**
@@ -230,7 +248,7 @@
}
for (TestCase testCase : mTestCases) {
- Point testOffset = runRenderSpec(testCase);
+ TestPositionInfo testPositionInfo = runRenderSpec(testCase);
for (int i = 0; i < VERIFY_ANIMATION_LOOP_COUNT; i++) {
try {
@@ -238,7 +256,7 @@
} catch (InterruptedException e) {
e.printStackTrace();
}
- Bitmap testCaseBitmap = takeScreenshot(testOffset);
+ Bitmap testCaseBitmap = takeScreenshot(testPositionInfo);
mBitmapAsserter.assertBitmapIsVerified(testCaseBitmap, bitmapVerifier,
getName(), testCase.getDebugString());
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
index 48c4a95..b12390e 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
@@ -47,7 +47,8 @@
static final String EXTRA_WIDE_COLOR_GAMUT = "DrawActivity.WIDE_COLOR_GAMUT";
private final static long TIME_OUT_MS = 10000;
- private final Point mLock = new Point();
+ private final Object mLock = new Object();
+ private ActivityTestBase.TestPositionInfo mPositionInfo;
private Handler mHandler;
private View mView;
@@ -72,11 +73,11 @@
return mOnTv;
}
- public Point enqueueRenderSpecAndWait(int layoutId, CanvasClient canvasClient,
- @Nullable ViewInitializer viewInitializer, boolean useHardware, boolean usePicture) {
+ public ActivityTestBase.TestPositionInfo enqueueRenderSpecAndWait(int layoutId,
+ CanvasClient canvasClient, @Nullable ViewInitializer viewInitializer,
+ boolean useHardware, boolean usePicture) {
((RenderSpecHandler) mHandler).setViewInitializer(viewInitializer);
int arg2 = (useHardware ? View.LAYER_TYPE_NONE : View.LAYER_TYPE_SOFTWARE);
- Point point = new Point();
synchronized (mLock) {
if (canvasClient != null) {
mHandler.obtainMessage(RenderSpecHandler.CANVAS_MSG, usePicture ? 1 : 0,
@@ -87,12 +88,11 @@
try {
mLock.wait(TIME_OUT_MS);
- point.set(mLock.x, mLock.y);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
- return point;
+ return mPositionInfo;
}
public void reset() {
@@ -187,8 +187,6 @@
}
private class DrawCounterListener implements ViewTreeObserver.OnDrawListener {
- private final int[] mLocationInWindow = new int[2];
-
@Override
public void onDraw() {
long vsyncMillis = mView.getDrawingTime();
@@ -196,9 +194,14 @@
mView.post(() -> mView.getViewTreeObserver().removeOnDrawListener(this));
mDrawMonitor.notifyWhenDrawn(vsyncMillis, () -> {
+ final int[] location = new int[2];
+ mViewWrapper.getLocationInWindow(location);
+ Point surfaceOffset = new Point(location[0], location[1]);
+ mViewWrapper.getLocationOnScreen(location);
+ Point screenOffset = new Point(location[0], location[1]);
synchronized (mLock) {
- mViewWrapper.getLocationInWindow(mLocationInWindow);
- mLock.set(mLocationInWindow[0], mLocationInWindow[1]);
+ mPositionInfo = new ActivityTestBase.TestPositionInfo(
+ surfaceOffset, screenOffset);
mLock.notify();
}
});
diff --git a/tests/tests/util/Android.mk b/tests/tests/util/Android.mk
index 4fa2a39..4dffce7 100644
--- a/tests/tests/util/Android.mk
+++ b/tests/tests/util/Android.mk
@@ -34,5 +34,6 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsUtilTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/view/Android.mk b/tests/tests/view/Android.mk
index 4538de3..e639b5c 100644
--- a/tests/tests/view/Android.mk
+++ b/tests/tests/view/Android.mk
@@ -42,6 +42,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
LOCAL_PACKAGE_NAME := CtsViewTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/view/AndroidManifest.xml b/tests/tests/view/AndroidManifest.xml
index 3b23811..e79a2e3 100644
--- a/tests/tests/view/AndroidManifest.xml
+++ b/tests/tests/view/AndroidManifest.xml
@@ -191,6 +191,13 @@
android:configChanges="orientation|screenSize"
android:colorMode="wideColorGamut" />
+ <activity android:name="android.view.cts.PixelCopyViewProducerDialogActivity"
+ android:label="PixelCopyViewProducerDialogActivity"
+ android:screenOrientation="portrait"
+ android:rotationAnimation="jumpcut"
+ android:theme="@android:style/Theme.Material.Dialog.NoActionBar"
+ android:configChanges="orientation|screenSize" />
+
<activity android:name="android.view.cts.FocusFinderCtsActivity"
android:screenOrientation="locked"
android:label="FocusFinderCtsActivity">
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyTest.java b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
index 0cbd0ca..2088b7c 100644
--- a/tests/tests/view/src/android/view/cts/PixelCopyTest.java
+++ b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
@@ -83,6 +83,10 @@
PixelCopyWideGamutViewProducerActivity.class, false, false);
@Rule
+ public ActivityTestRule<PixelCopyViewProducerDialogActivity> mDialogSourceActivityRule =
+ new ActivityTestRule<>(PixelCopyViewProducerDialogActivity.class, false, false);
+
+ @Rule
public SurfaceTextureRule mSurfaceRule = new SurfaceTextureRule();
private Instrumentation mInstrumentation;
@@ -458,6 +462,116 @@
} while (activity.rotate());
}
+ private Window waitForDialogProducerActivity() {
+ PixelCopyViewProducerActivity activity =
+ mDialogSourceActivityRule.launchActivity(null);
+ activity.waitForFirstDrawCompleted(3, TimeUnit.SECONDS);
+ return activity.getWindow();
+ }
+
+ private Rect makeDialogRect(int left, int top, int right, int bottom) {
+ Rect r = new Rect(left, top, right, bottom);
+ mDialogSourceActivityRule.getActivity().normalizedToSurface(r);
+ return r;
+ }
+
+ @Test
+ public void testDialogProducer() {
+ Bitmap bitmap;
+ Window window = waitForDialogProducerActivity();
+ PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity();
+ do {
+ Rect src = makeDialogRect(0, 0, 100, 100);
+ bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.ARGB_8888);
+ int result = mCopyHelper.request(window, src, bitmap);
+ assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result);
+ assertEquals(Config.ARGB_8888, bitmap.getConfig());
+ assertBitmapQuadColor(bitmap,
+ Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+ assertBitmapEdgeColor(bitmap, Color.YELLOW);
+ } while (activity.rotate());
+ }
+
+ @Test
+ public void testDialogProducerCropTopLeft() {
+ Window window = waitForDialogProducerActivity();
+ Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+ PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity();
+ do {
+ int result = mCopyHelper.request(window, makeDialogRect(0, 0, 50, 50), bitmap);
+ assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+ assertBitmapQuadColor(bitmap,
+ Color.RED, Color.RED, Color.RED, Color.RED);
+ } while (activity.rotate());
+ }
+
+ @Test
+ public void testDialogProducerCropCenter() {
+ Window window = waitForDialogProducerActivity();
+ Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+ PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity();
+ do {
+ int result = mCopyHelper.request(window, makeDialogRect(25, 25, 75, 75), bitmap);
+ assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+ assertBitmapQuadColor(bitmap,
+ Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+ } while (activity.rotate());
+ }
+
+ @Test
+ public void testDialogProducerCropBottomHalf() {
+ Window window = waitForDialogProducerActivity();
+ Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+ PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity();
+ do {
+ int result = mCopyHelper.request(window, makeDialogRect(0, 50, 100, 100), bitmap);
+ assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+ assertBitmapQuadColor(bitmap,
+ Color.BLUE, Color.BLACK, Color.BLUE, Color.BLACK);
+ } while (activity.rotate());
+ }
+
+ @Test
+ public void testDialogProducerScaling() {
+ // Since we only sample mid-pixel of each qudrant, filtering
+ // quality isn't tested
+ Window window = waitForDialogProducerActivity();
+ Bitmap bitmap = Bitmap.createBitmap(20, 20, Config.ARGB_8888);
+ PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity();
+ do {
+ int result = mCopyHelper.request(window, bitmap);
+ assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+ // Make sure nothing messed with the bitmap
+ assertEquals(20, bitmap.getWidth());
+ assertEquals(20, bitmap.getHeight());
+ assertEquals(Config.ARGB_8888, bitmap.getConfig());
+ assertBitmapQuadColor(bitmap,
+ Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+ } while (activity.rotate());
+ }
+
+ @Test
+ public void testDialogProducerCopyToRGBA16F() {
+ Window window = waitForDialogProducerActivity();
+ PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity();
+
+ Bitmap bitmap;
+ do {
+ Rect src = makeDialogRect(0, 0, 100, 100);
+ bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.RGBA_F16);
+ int result = mCopyHelper.request(window, src, bitmap);
+ // On OpenGL ES 2.0 devices a copy to RGBA_F16 can fail because there's
+ // not support for float textures
+ if (result != PixelCopy.ERROR_DESTINATION_INVALID) {
+ assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result);
+ assertEquals(Config.RGBA_F16, bitmap.getConfig());
+ assertBitmapQuadColor(bitmap,
+ Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+ assertBitmapEdgeColor(bitmap, Color.YELLOW);
+ }
+ } while (activity.rotate());
+ }
+
private static void assertEqualsRgba16f(String message, Bitmap bitmap, int x, int y,
ByteBuffer dst, float r, float g, float b, float a) {
int index = y * bitmap.getRowBytes() + (x << 3);
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyViewProducerDialogActivity.java b/tests/tests/view/src/android/view/cts/PixelCopyViewProducerDialogActivity.java
new file mode 100644
index 0000000..a213758
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/PixelCopyViewProducerDialogActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.cts;
+
+import android.os.Bundle;
+
+public class PixelCopyViewProducerDialogActivity extends PixelCopyViewProducerActivity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public boolean rotate() {
+ return false;
+ }
+}
diff --git a/tests/tests/view/src/android/view/cts/surfacevalidator/CapturedActivity.java b/tests/tests/view/src/android/view/cts/surfacevalidator/CapturedActivity.java
index 1ff6dc5..4adc056 100644
--- a/tests/tests/view/src/android/view/cts/surfacevalidator/CapturedActivity.java
+++ b/tests/tests/view/src/android/view/cts/surfacevalidator/CapturedActivity.java
@@ -16,6 +16,7 @@
package android.view.cts.surfacevalidator;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.app.Activity;
import android.content.Context;
@@ -23,6 +24,7 @@
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Point;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.MediaPlayer;
@@ -103,6 +105,7 @@
mMediaPlayer = MediaPlayer.create(this, R.raw.colors_video);
mMediaPlayer.setLooping(true);
+
}
public void dismissPermissionDialog() throws UiObjectNotFoundException {
@@ -207,11 +210,20 @@
display.getRealSize(size);
display.getMetrics(metrics);
+ View decorView = getWindow().getDecorView();
+ Rect boundsToCheck = new Rect(0, 0, decorView.getWidth(), decorView.getHeight());
+ int[] topLeft = decorView.getLocationOnScreen();
+ boundsToCheck.offset(topLeft[0], topLeft[1]);
+
+ if (boundsToCheck.width() < 90 || boundsToCheck.height() < 90) {
+ fail("capture bounds too small to be a fullscreen activity: " + boundsToCheck);
+ }
mSurfacePixelValidator = new SurfacePixelValidator(CapturedActivity.this,
- size, animationTestCase.getChecker());
- Log.d("MediaProjection", "Size is " + size.toString());
- mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenSharingDemo",
+ size, boundsToCheck, animationTestCase.getChecker());
+ Log.d("MediaProjection", "Size is " + size.toString()
+ + ", bounds are " + boundsToCheck.toShortString());
+ mVirtualDisplay = mMediaProjection.createVirtualDisplay("CtsCapturedActivity",
size.x, size.y,
metrics.densityDpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
diff --git a/tests/tests/view/src/android/view/cts/surfacevalidator/PixelCounter.rs b/tests/tests/view/src/android/view/cts/surfacevalidator/PixelCounter.rs
index f58b9cb..12e024c 100644
--- a/tests/tests/view/src/android/view/cts/surfacevalidator/PixelCounter.rs
+++ b/tests/tests/view/src/android/view/cts/surfacevalidator/PixelCounter.rs
@@ -18,11 +18,17 @@
#pragma rs reduce(countBlackishPixels) accumulator(countBlackishPixelsAccum) combiner(countBlackishPixelsCombiner)
uchar THRESHOLD;
+int BOUNDS[4];
-static void countBlackishPixelsAccum(int *accum, uchar4 pixel){
+static void countBlackishPixelsAccum(int *accum, uchar4 pixel, uint32_t x, uint32_t y) {
+
if (pixel.r < THRESHOLD
&& pixel.g < THRESHOLD
- && pixel.b < THRESHOLD) {
+ && pixel.b < THRESHOLD
+ && x >= BOUNDS[0]
+ && x < BOUNDS[2]
+ && y >= BOUNDS[1]
+ && y < BOUNDS[3]) {
*accum += 1;
}
}
diff --git a/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java b/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java
index 9523b32..1a8bc0db 100644
--- a/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java
+++ b/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Point;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Trace;
@@ -102,7 +103,8 @@
}
};
- public SurfacePixelValidator(Context context, Point size, PixelChecker pixelChecker) {
+ public SurfacePixelValidator(Context context, Point size, Rect boundsToCheck,
+ PixelChecker pixelChecker) {
mWidth = size.x;
mHeight = size.y;
@@ -116,6 +118,8 @@
mScript = new ScriptC_PixelCounter(mRS);
mInPixelsAllocation = createBufferQueueAllocation();
+ mScript.set_BOUNDS(new int[] {boundsToCheck.left, boundsToCheck.top,
+ boundsToCheck.right, boundsToCheck.bottom});
mScript.set_THRESHOLD(PIXEL_CHANNEL_THRESHOLD);
mInPixelsAllocation.setOnBufferAvailableListener(
diff --git a/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java b/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
index b1d93ab..880cc0d 100644
--- a/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
+++ b/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
@@ -39,6 +39,10 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TextClassificationManagerTest {
@@ -123,6 +127,38 @@
assertFalse(Logger.DISABLED.isSmartSelection("sig.na.ture"));
}
+ @Test
+ public void testResolveEntityListModifications_only_hints() {
+ TextClassifier.EntityConfig entityConfig = TextClassifier.EntityConfig.create(
+ Arrays.asList("some_hint"));
+ assertEquals(1, entityConfig.getHints().size());
+ assertTrue(entityConfig.getHints().contains("some_hint"));
+ assertEquals(Arrays.asList("foo", "bar"),
+ entityConfig.resolveEntityListModifications(Arrays.asList("foo", "bar")));
+ }
+
+ @Test
+ public void testResolveEntityListModifications_include_exclude() {
+ TextClassifier.EntityConfig entityConfig = TextClassifier.EntityConfig.create(
+ Arrays.asList("some_hint"),
+ Arrays.asList("a", "b", "c"),
+ Arrays.asList("b", "d", "x"));
+ assertEquals(1, entityConfig.getHints().size());
+ assertTrue(entityConfig.getHints().contains("some_hint"));
+ assertEquals(new HashSet(Arrays.asList("a", "c", "w")),
+ new HashSet(entityConfig.resolveEntityListModifications(
+ Arrays.asList("c", "w", "x"))));
+ }
+
+ @Test
+ public void testResolveEntityListModifications_explicit() {
+ TextClassifier.EntityConfig entityConfig =
+ TextClassifier.EntityConfig.createWithEntityList(Arrays.asList("a", "b"));
+ assertEquals(Collections.EMPTY_LIST, entityConfig.getHints());
+ assertEquals(Arrays.asList("a", "b"),
+ entityConfig.resolveEntityListModifications(Arrays.asList("w", "x")));
+ }
+
private static void assertValidResult(TextSelection selection) {
assertNotNull(selection);
assertTrue(selection.getSelectionStartIndex() >= 0);
diff --git a/tests/tests/webkit/Android.mk b/tests/tests/webkit/Android.mk
index a5f01b2..bb70293 100644
--- a/tests/tests/webkit/Android.mk
+++ b/tests/tests/webkit/Android.mk
@@ -42,5 +42,6 @@
# uncomment when dalvik.annotation.Test* are removed or part of SDK
#LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index f10e7fd..6d61e1c 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -1030,7 +1030,6 @@
if (!NullWebViewUtils.isWebViewAvailable()) {
return;
}
- assertFalse(mSettings.getSafeBrowsingEnabled());
mSettings.setSafeBrowsingEnabled(false);
assertFalse(mSettings.getSafeBrowsingEnabled());
}
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 7d2d84f..4bedbb1 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -3072,4 +3072,12 @@
Assert.fail("The privacy policy URL should be a well-formed URL");
}
}
+
+ public void testWebViewClassLoaderReturnsNonNull() {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+
+ assertNotNull(WebView.getWebViewClassLoader());
+ }
}
diff --git a/tests/tests/widget/Android.mk b/tests/tests/widget/Android.mk
index f939c43..209f6cb 100644
--- a/tests/tests/widget/Android.mk
+++ b/tests/tests/widget/Android.mk
@@ -35,6 +35,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsWidgetTestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/tests/tests/widget/src/android/widget/cts/MagnifierTest.java b/tests/tests/widget/src/android/widget/cts/MagnifierTest.java
index fc54362..5c7c47e 100644
--- a/tests/tests/widget/src/android/widget/cts/MagnifierTest.java
+++ b/tests/tests/widget/src/android/widget/cts/MagnifierTest.java
@@ -22,11 +22,9 @@
import static org.junit.Assume.assumeTrue;
import android.app.Activity;
-import android.app.Instrumentation;
import android.graphics.Bitmap;
import android.graphics.PointF;
import android.graphics.Rect;
-import android.support.test.InstrumentationRegistry;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.rule.ActivityTestRule;
@@ -38,6 +36,7 @@
import android.widget.Magnifier;
import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.WidgetTestUtils;
import org.junit.Before;
import org.junit.Rule;
@@ -46,6 +45,8 @@
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Tests for {@link Magnifier}.
@@ -53,7 +54,9 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
public class MagnifierTest {
- private Instrumentation mInstrumentation;
+ private static final String TIME_LIMIT_EXCEEDED =
+ "Completing the magnifier operation took too long";
+
private Activity mActivity;
private LinearLayout mLayout;
private Magnifier mMagnifier;
@@ -64,7 +67,6 @@
@Before
public void setup() {
- mInstrumentation = InstrumentationRegistry.getInstrumentation();
mActivity = mActivityRule.getActivity();
PollingCheck.waitFor(mActivity::hasWindowFocus);
mLayout = mActivity.findViewById(R.id.magnifier_activity_basic_layout);
@@ -141,25 +143,31 @@
}
@Test
- public void testWindowContent() {
+ public void testWindowContent() throws Throwable {
prepareFourQuadrantsScenario();
+ final CountDownLatch latch = new CountDownLatch(1);
+ mMagnifier.setOnOperationCompleteCallback(latch::countDown);
+
// Show the magnifier at the center of the activity.
- mInstrumentation.runOnMainSync(() -> {
+ mActivityRule.runOnUiThread(() -> {
mMagnifier.show(mLayout.getWidth() / 2, mLayout.getHeight() / 2);
});
- mInstrumentation.waitForIdleSync();
+ assertTrue(TIME_LIMIT_EXCEEDED, latch.await(1, TimeUnit.SECONDS));
assertFourQuadrants(mMagnifier.getContent());
}
@Test
- public void testWindowPosition() {
+ public void testWindowPosition() throws Throwable {
prepareFourQuadrantsScenario();
+ final CountDownLatch latch = new CountDownLatch(1);
+ mMagnifier.setOnOperationCompleteCallback(latch::countDown);
+
// Show the magnifier at the center of the activity.
- mInstrumentation.runOnMainSync(() -> {
+ mActivityRule.runOnUiThread(() -> {
mMagnifier.show(mLayout.getWidth() / 2, mLayout.getHeight() / 2);
});
- mInstrumentation.waitForIdleSync();
+ assertTrue(TIME_LIMIT_EXCEEDED, latch.await(1, TimeUnit.SECONDS));
// Assert that the magnifier position represents a valid rectangle on screen.
final Rect position = mMagnifier.getWindowPositionOnScreen();
@@ -169,27 +177,33 @@
}
@Test
- public void testWindowContent_modifiesAfterUpdate() {
+ public void testWindowContent_modifiesAfterUpdate() throws Throwable {
prepareFourQuadrantsScenario();
+
// Show the magnifier at the center of the activity.
- mInstrumentation.runOnMainSync(() -> {
+ final CountDownLatch latchForShow = new CountDownLatch(1);
+ mMagnifier.setOnOperationCompleteCallback(latchForShow::countDown);
+ mActivityRule.runOnUiThread(() -> {
mMagnifier.show(mLayout.getWidth() / 2, mLayout.getHeight() / 2);
});
- mInstrumentation.waitForIdleSync();
+ assertTrue(TIME_LIMIT_EXCEEDED, latchForShow.await(1, TimeUnit.SECONDS));
final Bitmap initialBitmap = mMagnifier.getContent()
.copy(mMagnifier.getContent().getConfig(), true);
assertFourQuadrants(initialBitmap);
// Make the one quadrant white.
- mInstrumentation.runOnMainSync(() -> {
- mActivity.findViewById(R.id.magnifier_activity_four_quadrants_layout_quadrant_1)
- .setBackground(null);
+ final View quadrant1 =
+ mActivity.findViewById(R.id.magnifier_activity_four_quadrants_layout_quadrant_1);
+ WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, quadrant1, () -> {
+ quadrant1.setBackground(null);
});
- mInstrumentation.waitForIdleSync();
+
// Update the magnifier.
- mInstrumentation.runOnMainSync(mMagnifier::update);
- mInstrumentation.waitForIdleSync();
+ final CountDownLatch latchForUpdate = new CountDownLatch(1);
+ mMagnifier.setOnOperationCompleteCallback(latchForUpdate::countDown);
+ mActivityRule.runOnUiThread(mMagnifier::update);
+ assertTrue(TIME_LIMIT_EXCEEDED, latchForUpdate.await(1, TimeUnit.SECONDS));
final Bitmap newBitmap = mMagnifier.getContent();
assertFourQuadrants(newBitmap);
@@ -200,13 +214,13 @@
* Sets the activity to contain four equal quadrants coloured differently and
* instantiates a magnifier. This method should not be called on the UI thread.
*/
- private void prepareFourQuadrantsScenario() {
- mInstrumentation.runOnMainSync(() -> {
+ private void prepareFourQuadrantsScenario() throws Throwable {
+ WidgetTestUtils.runOnMainAndLayoutSync(mActivityRule, () -> {
mActivity.setContentView(R.layout.magnifier_activity_four_quadrants_layout);
mLayout = mActivity.findViewById(R.id.magnifier_activity_four_quadrants_layout);
mMagnifier = new Magnifier(mLayout);
- });
- mInstrumentation.waitForIdleSync();
+ }, false);
+ WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mLayout, null);
}
/**
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 992f05e..3843780 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -86,7 +86,7 @@
import android.text.InputFilter;
import android.text.InputType;
import android.text.Layout;
-import android.text.MeasuredText;
+import android.text.PrecomputedText;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableString;
@@ -1637,12 +1637,10 @@
@UiThreadTest
@Test
- public void testSetText_MeasuredText() {
+ public void testSetText_PrecomputedText() {
final TextView tv = findTextView(R.id.textview_text);
- final MeasuredText measured = new MeasuredText.Builder(
- "This is an example text.", new TextPaint())
- .setBreakStrategy(tv.getBreakStrategy())
- .setHyphenationFrequency(tv.getHyphenationFrequency()).build();
+ final PrecomputedText measured = PrecomputedText.create(
+ "This is an example text.", tv.getTextMetricsParams());
tv.setText(measured);
assertEquals(measured.toString(), tv.getText().toString());
}
@@ -8026,6 +8024,28 @@
assertTrue(mTextView.isFallbackLineSpacing());
}
+ @UiThreadTest
+ @Test
+ public void testTextLayoutParam() {
+ mActivity.setContentView(R.layout.textview_fallbacklinespacing_layout);
+ mTextView = findTextView(R.id.textview_default);
+ PrecomputedText.Params param = mTextView.getTextMetricsParams();
+
+ assertEquals(mTextView.getBreakStrategy(), param.getBreakStrategy());
+ assertEquals(mTextView.getHyphenationFrequency(), param.getHyphenationFrequency());
+
+ assertTrue(param.equals(mTextView.getTextMetricsParams()));
+
+ mTextView.setBreakStrategy(
+ mTextView.getBreakStrategy() == Layout.BREAK_STRATEGY_SIMPLE
+ ? Layout.BREAK_STRATEGY_BALANCED : Layout.BREAK_STRATEGY_SIMPLE);
+
+ assertFalse(param.equals(mTextView.getTextMetricsParams()));
+
+ mTextView.setTextMetricsParams(param);
+ assertTrue(param.equals(mTextView.getTextMetricsParams()));
+ }
+
private void initializeTextForSmartSelection(CharSequence text) throws Throwable {
assertTrue(text.length() >= SMARTSELECT_END);
mActivityRule.runOnUiThread(() -> {
diff --git a/tests/tests/widget/src/android/widget/cts/TimePickerTest.java b/tests/tests/widget/src/android/widget/cts/TimePickerTest.java
index ce093e7..0886aa3 100644
--- a/tests/tests/widget/src/android/widget/cts/TimePickerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TimePickerTest.java
@@ -553,6 +553,12 @@
prepareForKeyboardInput(initialHour, initialMinute, false /* is24hFormat */,
false /* isClockMode */);
+ // when testing on device with lower resolution, the Spinner mode time picker may not show
+ // completely, which will cause case fail, so in this case remove the clock time picker to
+ // focus on the test of Spinner mode
+ final TimePicker clock = mActivity.findViewById(R.id.timepicker_clock);
+ mActivityRule.runOnUiThread(() -> clock.setVisibility(View.GONE));
+
assertEquals(initialHour, mTimePicker.getHour());
mActivityRule.runOnUiThread(() -> mTimePicker.getHourView().requestFocus());
mInstrumentation.waitForIdleSync();
@@ -665,6 +671,12 @@
prepareForKeyboardInput(initialHour, initialMinute, true /* is24hFormat */,
false /* isClockMode */);
+ // when testing on device with lower resolution, the Spinner mode time picker may not show
+ // completely, which will cause case fail, so in this case remove the clock time picker to
+ // focus on the test of Spinner mode
+ final TimePicker clock = mActivity.findViewById(R.id.timepicker_clock);
+ mActivityRule.runOnUiThread(() -> clock.setVisibility(View.GONE));
+
assertEquals(initialHour, mTimePicker.getHour());
mActivityRule.runOnUiThread(() -> mTimePicker.getHourView().requestFocus());
mInstrumentation.waitForIdleSync();
diff --git a/tools/cts-tradefed/res/config/retry.xml b/tools/cts-tradefed/res/config/retry.xml
index e488410..d425d8e 100644
--- a/tools/cts-tradefed/res/config/retry.xml
+++ b/tools/cts-tradefed/res/config/retry.xml
@@ -14,6 +14,8 @@
limitations under the License.
-->
<configuration description="Runs a retry of a previous CTS session.">
+ <option name="dynamic-sharding" value="true" />
+ <option name="disable-strict-sharding" value="true" />
<device_recovery class="com.android.tradefed.device.WaitDeviceRecovery" />
<build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider" />
@@ -21,6 +23,8 @@
<option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:rerun-from-file:true" />
<option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:fallback-to-serial-rerun:false" />
+ <option name="compatibility:test-arg" value="com.android.compatibility.testtype.LibcoreTest:rerun-from-file:true" />
+ <option name="compatibility:test-arg" value="com.android.compatibility.testtype.LibcoreTest:fallback-to-serial-rerun:false" />
<logger class="com.android.tradefed.log.FileLogger">
<option name="log-level-display" value="WARN" />
@@ -36,6 +40,16 @@
<option name="skip-device-info" value="true" />
<option name="enable-root" value="false" />
+ <!-- retain 200MB of host log -->
+ <option name="max-log-size" value="200" />
+ <!-- retain 200MB of logcat -->
+ <option name="max-tmp-logcat-file" value="209715200" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="settings put global package_verifier_enable 0" />
+ <option name="teardown-command" value="settings put global package_verifier_enable 1"/>
+ </target_preparer>
+
<result_reporter class="com.android.compatibility.common.tradefed.result.ConsoleReporter" />
<result_reporter class="com.android.compatibility.common.tradefed.result.ResultReporter" />
diff --git a/tools/device-setup/TestDeviceSetup/Android.mk b/tools/device-setup/TestDeviceSetup/Android.mk
index edb85d2..1820347 100644
--- a/tools/device-setup/TestDeviceSetup/Android.mk
+++ b/tools/device-setup/TestDeviceSetup/Android.mk
@@ -27,6 +27,7 @@
# uncomment when b/13282254 is fixed
#LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := system_current
LOCAL_PACKAGE_NAME := TestDeviceSetup