Merge changes from topic "b149346795" into rvc-dev
* changes:
Camera: Verify offline image timestamps
Camera: Test offline processing along with regular session
Camera: Extend offline processing testing
diff --git a/apps/CameraITS/pymodules/its/device.py b/apps/CameraITS/pymodules/its/device.py
index bc1d3a6..3d9a42e 100644
--- a/apps/CameraITS/pymodules/its/device.py
+++ b/apps/CameraITS/pymodules/its/device.py
@@ -249,7 +249,7 @@
ch = self.sock.recv(1)
if len(ch) == 0:
# Socket was probably closed; otherwise don't get empty strings
- raise its.error.Error('Problem with socket on device side')
+ raise its.error.SocketError(self.device_id, 'Problem with socket on device side')
chars.append(ch)
line = ''.join(chars)
jobj = json.loads(line)
diff --git a/apps/CameraITS/pymodules/its/error.py b/apps/CameraITS/pymodules/its/error.py
index 884389b..5b0c467 100644
--- a/apps/CameraITS/pymodules/its/error.py
+++ b/apps/CameraITS/pymodules/its/error.py
@@ -12,15 +12,54 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import subprocess
import unittest
+
class Error(Exception):
pass
+
+class SocketError(Error):
+
+ def __init__(self, device_id, message):
+ """Exception raised for socket errors.
+
+ Args:
+ device_id (str): device id
+ message (str): explanation of the error
+ """
+ Error.__init__(self)
+ self.message = message
+ locale = self.get_device_locale(device_id)
+ if locale != "en-US":
+ print "Unsupported default language %s" % locale
+ print "Please set the default language to English (United States)"
+ print "in Settings > Language & input > Languages\n"
+
+ def get_device_locale(self, device_id):
+ """Return the default locale of a given device.
+
+ Args:
+ device_id (str): device id
+
+ Returns:
+ str: Device locale.
+ """
+ locale_property = "persist.sys.locale"
+
+ com = ("adb -s %s shell getprop %s" % (device_id, locale_property))
+ proc = subprocess.Popen(com.split(), stdout=subprocess.PIPE)
+ output, error = proc.communicate()
+ assert error is None
+
+ return output
+
+
class __UnitTest(unittest.TestCase):
"""Run a suite of unit tests on this module.
"""
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/apps/CameraITS/tests/scene2_a/SampleTarget.jpg b/apps/CameraITS/tests/scene2_a/SampleTarget.jpg
deleted file mode 100644
index c054f7e..0000000
--- a/apps/CameraITS/tests/scene2_a/SampleTarget.jpg
+++ /dev/null
Binary files differ
diff --git a/apps/CameraITS/tests/scene2_a/test_jpeg_quality.py b/apps/CameraITS/tests/scene2_a/test_jpeg_quality.py
new file mode 100644
index 0000000..b52fb1e
--- /dev/null
+++ b/apps/CameraITS/tests/scene2_a/test_jpeg_quality.py
@@ -0,0 +1,256 @@
+# Copyright 2020 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 math
+import os.path
+
+import its.caps
+import its.device
+import its.image
+import its.objects
+
+from matplotlib import pylab
+import matplotlib.pyplot
+import numpy as np
+
+JPEG_APPN_MARKERS = [[255, 224], [255, 225], [255, 226], [255, 227], [255, 228],
+ [255, 235]]
+JPEG_DHT_MARKER = [255, 196] # JPEG Define Huffman Table
+JPEG_DQT_MARKER = [255, 219] # JPEG Define Quantization Table
+JPEG_DQT_TOL = 0.8 # -20% for each +20 in jpeg.quality (empirical number)
+JPEG_EOI_MARKER = [255, 217] # JPEG End of Image
+JPEG_SOI_MARKER = [255, 216] # JPEG Start of Image
+JPEG_SOS_MARKER = [255, 218] # JPEG Start of Scan
+NAME = os.path.basename(__file__).split('.')[0]
+QUALITIES = [25, 45, 65, 85]
+SYMBOLS = ['o', 's', 'v', '^', '<', '>']
+
+
+def is_square(integer):
+ root = math.sqrt(integer)
+ return integer == int(root + 0.5) ** 2
+
+
+def strip_soi_marker(jpeg):
+ """strip off start of image marker.
+
+ SOI is of form [xFF xD8] and JPEG needs to start with marker.
+
+ Args:
+ jpeg: 1-D numpy int [0:255] array; values from JPEG capture
+
+ Returns:
+ jpeg with SOI marker stripped off.
+ """
+
+ soi = jpeg[0:2]
+ assert list(soi) == JPEG_SOI_MARKER, 'JPEG has no Start Of Image marker'
+ return jpeg[2:]
+
+
+def strip_appn_data(jpeg):
+ """strip off application specific data at beginning of JPEG.
+
+ APPN markers are of form [xFF, xE*, size_msb, size_lsb] and should follow
+ SOI marker.
+
+ Args:
+ jpeg: 1-D numpy int [0:255] array; values from JPEG capture
+
+ Returns:
+ jpeg with APPN marker(s) and data stripped off.
+ """
+
+ length = 0
+ i = 0
+ # find APPN markers and strip off payloads at beginning of jpeg
+ while i < len(jpeg)-1:
+ if [jpeg[i], jpeg[i+1]] in JPEG_APPN_MARKERS:
+ length = jpeg[i+2] * 256 + jpeg[i+3] + 2
+ print ' stripped APPN length:', length
+ jpeg = np.concatenate((jpeg[0:i], jpeg[length:]), axis=None)
+ elif ([jpeg[i], jpeg[i+1]] == JPEG_DQT_MARKER or
+ [jpeg[i], jpeg[i+1]] == JPEG_DHT_MARKER):
+ break
+ else:
+ i += 1
+
+ return jpeg
+
+
+def find_dqt_markers(marker, jpeg):
+ """Find location(s) of marker list in jpeg.
+
+ DQT marker is of form [xFF, xDB].
+
+ Args:
+ marker: list; marker values
+ jpeg: 1-D numpy int [0:255] array; JPEG capture w/ SOI & APPN stripped
+
+ Returns:
+ locs: list; marker locations in jpeg
+ """
+ locs = []
+ marker_len = len(marker)
+ for i in xrange(len(jpeg)-marker_len+1):
+ if list(jpeg[i:i+marker_len]) == marker:
+ locs.append(i)
+ return locs
+
+
+def extract_dqts(jpeg, debug=False):
+ """Find and extract the DQT info in the JPEG.
+
+ SOI marker and APPN markers plus data are stripped off front of JPEG.
+ DQT marker is of form [xFF, xDB] followed by [size_msb, size_lsb].
+ Size includes the size values, but not the marker values.
+ Luma DQT is prefixed by 0, Chroma DQT by 1.
+ DQTs can have both luma & chroma or each individually.
+ There can be more than one DQT table for luma and chroma.
+
+ Args:
+ jpeg: 1-D numpy int [0:255] array; values from JPEG capture
+ debug: bool; command line flag to print debug data
+
+ Returns:
+ lumas, chromas: lists of numpy means of luma & chroma DQT matrices.
+ Higher values represent higher compression.
+ """
+
+ dqt_markers = find_dqt_markers(JPEG_DQT_MARKER, jpeg)
+ print 'DQT header loc(s):', dqt_markers
+ lumas = []
+ chromas = []
+ for i, dqt in enumerate(dqt_markers):
+ if debug:
+ print '\n DQT %d start: %d, marker: %s, length: %s' % (
+ i, dqt, jpeg[dqt:dqt+2], jpeg[dqt+2:dqt+4])
+ dqt_size = jpeg[dqt+2]*256 + jpeg[dqt+3] - 2 # strip off size marker
+ if dqt_size % 2 == 0: # even payload means luma & chroma
+ print ' both luma & chroma DQT matrices in marker'
+ dqt_size = (dqt_size - 2) / 2 # subtact off luma/chroma markers
+ assert is_square(dqt_size), 'DQT size: %d' % dqt_size
+ luma_start = dqt + 5 # skip header, length, & matrix id
+ chroma_start = luma_start + dqt_size + 1 # skip lumen & matrix_id
+ luma = np.array(jpeg[luma_start:luma_start+dqt_size])
+ chroma = np.array(jpeg[chroma_start:chroma_start+dqt_size])
+ lumas.append(np.mean(luma))
+ chromas.append(np.mean(chroma))
+ if debug:
+ h = int(math.sqrt(dqt_size))
+ print ' luma:', luma.reshape(h, h)
+ print ' chroma:', chroma.reshape(h, h)
+ else: # odd payload means only 1 matrix
+ print ' single DQT matrix in marker'
+ dqt_size = dqt_size - 1 # subtract off luma/chroma marker
+ assert is_square(dqt_size), 'DQT size: %d' % dqt_size
+ start = dqt + 5
+ matrix = np.array(jpeg[start:start+dqt_size])
+ if jpeg[dqt+4]: # chroma == 1
+ chromas.append(np.mean(matrix))
+ if debug:
+ h = int(math.sqrt(dqt_size))
+ print ' chroma:', matrix.reshape(h, h)
+ else: # luma == 0
+ lumas.append(np.mean(matrix))
+ if debug:
+ h = int(math.sqrt(dqt_size))
+ print ' luma:', matrix.reshape(h, h)
+
+ return lumas, chromas
+
+
+def plot_data(qualities, lumas, chromas):
+ """Create plot of data."""
+ print 'qualities: %s' % str(qualities)
+ print 'luma DQT avgs: %s' % str(lumas)
+ print 'chroma DQT avgs: %s' % str(chromas)
+ pylab.title(NAME)
+ for i in range(lumas.shape[1]):
+ pylab.plot(qualities, lumas[:, i], '-g'+SYMBOLS[i],
+ label='luma_dqt'+str(i))
+ pylab.plot(qualities, chromas[:, i], '-r'+SYMBOLS[i],
+ label='chroma_dqt'+str(i))
+ pylab.xlim([0, 100])
+ pylab.ylim([0, None])
+ pylab.xlabel('jpeg.quality')
+ pylab.ylabel('DQT luma/chroma matrix averages')
+ pylab.legend(loc='upper right', numpoints=1, fancybox=True)
+ matplotlib.pyplot.savefig('%s_plot.png' % NAME)
+
+
+def main():
+ """Test the camera JPEG compression quality.
+
+ Step JPEG qualities through android.jpeg.quality. Ensure quanitization
+ matrix decreases with quality increase. Matrix should decrease as the
+ matrix represents the division factor. Higher numbers --> fewer quantization
+ levels.
+ """
+
+ # determine debug
+ debug = its.caps.debug_mode()
+
+ # init variables
+ lumas = []
+ chromas = []
+
+ with its.device.ItsSession() as cam:
+ props = cam.get_camera_properties()
+ cam.do_3a()
+
+ # do captures over jpeg quality range
+ req = its.objects.auto_capture_request()
+ for q in QUALITIES:
+ print '\njpeg.quality: %.d' % q
+ req['android.jpeg.quality'] = q
+ cap = cam.do_capture(req, cam.CAP_JPEG)
+ jpeg = cap['data']
+
+ # strip off start of image
+ jpeg = strip_soi_marker(jpeg)
+
+ # strip off application specific data
+ jpeg = strip_appn_data(jpeg)
+ print 'remaining JPEG header:', jpeg[0:4]
+
+ # find and extract DQTs
+ lumas_i, chromas_i = extract_dqts(jpeg, debug)
+ lumas.append(lumas_i)
+ chromas.append(chromas_i)
+
+ # save JPEG image
+ img = its.image.convert_capture_to_rgb_image(cap, props=props)
+ its.image.write_image(img, '%s_%d.jpg' % (NAME, q))
+
+ # turn lumas/chromas into np array to ease multi-dimensional plots/asserts
+ lumas = np.array(lumas)
+ chromas = np.array(chromas)
+
+ # create plot of luma & chroma averages vs quality
+ plot_data(QUALITIES, lumas, chromas)
+
+ # assert decreasing luma/chroma with improved jpeg quality
+ for i in range(lumas.shape[1]):
+ l = lumas[:, i]
+ c = chromas[:, i]
+ emsg = 'luma DQT avgs: %s, TOL: %.1f' % (str(l), JPEG_DQT_TOL)
+ assert all(y < x * JPEG_DQT_TOL for x, y in zip(l, l[1:])), emsg
+ emsg = 'chroma DQT avgs: %s, TOL: %.1f' % (str(c), JPEG_DQT_TOL)
+ assert all(y < x * JPEG_DQT_TOL for x, y in zip(c, c[1:])), emsg
+
+
+if __name__ == '__main__':
+ main()
diff --git a/apps/CameraITS/tests/scene4/SampleTarget.pdf b/apps/CameraITS/tests/scene4/SampleTarget.pdf
deleted file mode 100644
index e693b34..0000000
--- a/apps/CameraITS/tests/scene4/SampleTarget.pdf
+++ /dev/null
Binary files differ
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index 021a324..e47795e 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -104,7 +104,9 @@
['test_channel_saturation', 29]
],
'scene1_2': [],
- 'scene2_a': [],
+ 'scene2_a': [
+ ['test_jpeg_quality', 30]
+ ],
'scene2_b': [
['test_auto_per_frame_control', NOT_YET_MANDATED_ALL]
],
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 36c2284..92b881b 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1381,6 +1381,168 @@
android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
</activity>
+ <activity
+ android:name=".biometrics.UserAuthenticationCredentialCipherTest"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:label="@string/biometric_test_set_user_authentication_credential_cipher_label" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+
+ <meta-data android:name="test_category" android:value="@string/biometric_test_category_combination" />
+ <meta-data android:name="test_parent"
+ android:value="com.android.cts.verifier.biometrics.BiometricTestList" />
+ <meta-data android:name="test_required_features" android:value="android.software.secure_lock_screen" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+ </activity>
+
+ <activity
+ android:name=".biometrics.UserAuthenticationBiometricCipherTest"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:label="@string/biometric_test_set_user_authentication_biometric_cipher_label" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+
+ <meta-data android:name="test_category" android:value="@string/biometric_test_category_combination" />
+ <meta-data android:name="test_parent"
+ android:value="com.android.cts.verifier.biometrics.BiometricTestList" />
+ <meta-data android:name="test_required_features" android:value="android.software.secure_lock_screen" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+ </activity>
+
+ <activity
+ android:name=".biometrics.UserAuthenticationBiometricOrCredentialCipherTest"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:label="@string/biometric_test_set_user_authentication_biometric_credential_cipher_label" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+
+ <meta-data android:name="test_category" android:value="@string/biometric_test_category_combination" />
+ <meta-data android:name="test_parent"
+ android:value="com.android.cts.verifier.biometrics.BiometricTestList" />
+ <meta-data android:name="test_required_features" android:value="android.software.secure_lock_screen" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+ </activity>
+
+ <activity
+ android:name=".biometrics.UserAuthenticationCredentialSignatureTest"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:label="@string/biometric_test_set_user_authentication_credential_signature_label" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+
+ <meta-data android:name="test_category" android:value="@string/biometric_test_category_combination" />
+ <meta-data android:name="test_parent"
+ android:value="com.android.cts.verifier.biometrics.BiometricTestList" />
+ <meta-data android:name="test_required_features" android:value="android.software.secure_lock_screen" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+ </activity>
+
+ <activity
+ android:name=".biometrics.UserAuthenticationBiometricSignatureTest"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:label="@string/biometric_test_set_user_authentication_biometric_signature_label" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+
+ <meta-data android:name="test_category" android:value="@string/biometric_test_category_combination" />
+ <meta-data android:name="test_parent"
+ android:value="com.android.cts.verifier.biometrics.BiometricTestList" />
+ <meta-data android:name="test_required_features" android:value="android.software.secure_lock_screen" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+ </activity>
+
+ <activity
+ android:name=".biometrics.UserAuthenticationBiometricOrCredentialSignatureTest"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:label="@string/biometric_test_set_user_authentication_biometric_or_credential_signature_label" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+
+ <meta-data android:name="test_category" android:value="@string/biometric_test_category_combination" />
+ <meta-data android:name="test_parent"
+ android:value="com.android.cts.verifier.biometrics.BiometricTestList" />
+ <meta-data android:name="test_required_features" android:value="android.software.secure_lock_screen" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+ </activity>
+
+ <activity
+ android:name=".biometrics.UserAuthenticationCredentialMacTest"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:label="@string/biometric_test_set_user_authentication_credential_mac_label" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+
+ <meta-data android:name="test_category" android:value="@string/biometric_test_category_combination" />
+ <meta-data android:name="test_parent"
+ android:value="com.android.cts.verifier.biometrics.BiometricTestList" />
+ <meta-data android:name="test_required_features" android:value="android.software.secure_lock_screen" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+ </activity>
+
+ <activity
+ android:name=".biometrics.UserAuthenticationBiometricMacTest"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:label="@string/biometric_test_set_user_authentication_biometric_mac_label" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+
+ <meta-data android:name="test_category" android:value="@string/biometric_test_category_combination" />
+ <meta-data android:name="test_parent"
+ android:value="com.android.cts.verifier.biometrics.BiometricTestList" />
+ <meta-data android:name="test_required_features" android:value="android.software.secure_lock_screen" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+ </activity>
+
+ <activity
+ android:name=".biometrics.UserAuthenticationBiometricOrCredentialMacTest"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:label="@string/biometric_test_set_user_authentication_biometric_or_credential_mac_label" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+
+ <meta-data android:name="test_category" android:value="@string/biometric_test_category_combination" />
+ <meta-data android:name="test_parent"
+ android:value="com.android.cts.verifier.biometrics.BiometricTestList" />
+ <meta-data android:name="test_required_features" android:value="android.software.secure_lock_screen" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+ </activity>
+
<activity android:name=".security.IdentityCredentialAuthentication"
android:label="@string/sec_identity_credential_authentication_test"
android:configChanges="keyboardHidden|orientation|screenSize" >
diff --git a/apps/CtsVerifier/jni/audio_loopback/Android.bp b/apps/CtsVerifier/jni/audio_loopback/Android.bp
index 9227c75..29b7e13 100644
--- a/apps/CtsVerifier/jni/audio_loopback/Android.bp
+++ b/apps/CtsVerifier/jni/audio_loopback/Android.bp
@@ -1,21 +1,22 @@
cc_test_library {
name: "libaudioloopback_jni",
srcs: [
- "sles.cpp",
- "jni_sles.c",
- "audio_utils/atomic.c",
- "audio_utils/fifo.c",
- "audio_utils/roundup.c",
+ "jni-bridge.cpp",
+ "NativeAudioAnalyzer.cpp",
+ ],
+ include_dirs: [
+ "frameworks/av/media/ndk/include",
+ "system/core/include/cutils",
],
shared_libs: [
- "libOpenSLES",
+ "libaaudio",
"liblog",
],
+ stl: "libc++_static",
ldflags: ["-Wl,--hash-style=sysv"],
cflags: [
- "-DSTDC_HEADERS",
"-Werror",
"-Wall",
],
- sdk_version: "23",
+ sdk_version: "current",
}
diff --git a/apps/CtsVerifier/jni/audio_loopback/NativeAudioAnalyzer.cpp b/apps/CtsVerifier/jni/audio_loopback/NativeAudioAnalyzer.cpp
new file mode 100644
index 0000000..d8d6946
--- /dev/null
+++ b/apps/CtsVerifier/jni/audio_loopback/NativeAudioAnalyzer.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2020 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 "NativeAudioAnalyzer.h"
+
+static void convertPcm16ToFloat(const int16_t *source,
+ float *destination,
+ int32_t numSamples) {
+ constexpr float scaler = 1.0f / 32768.0f;
+ for (int i = 0; i < numSamples; i++) {
+ destination[i] = source[i] * scaler;
+ }
+}
+
+// Fill the audio output buffer.
+int32_t NativeAudioAnalyzer::readFormattedData(int32_t numFrames) {
+ int32_t framesRead = AAUDIO_ERROR_INVALID_FORMAT;
+ if (mActualInputFormat == AAUDIO_FORMAT_PCM_I16) {
+ framesRead = AAudioStream_read(mInputStream, mInputShortData,
+ numFrames,
+ 0 /* timeoutNanoseconds */);
+ } else if (mActualInputFormat == AAUDIO_FORMAT_PCM_FLOAT) {
+ framesRead = AAudioStream_read(mInputStream, mInputFloatData,
+ numFrames,
+ 0 /* timeoutNanoseconds */);
+ } else {
+ ALOGE("ERROR actualInputFormat = %d\n", mActualInputFormat);
+ assert(false);
+ }
+ if (framesRead < 0) {
+ // Expect INVALID_STATE if STATE_STARTING
+ if (mFramesReadTotal > 0) {
+ mInputError = framesRead;
+ ALOGE("ERROR in read = %d = %s\n", framesRead,
+ AAudio_convertResultToText(framesRead));
+ } else {
+ framesRead = 0;
+ }
+ } else {
+ mFramesReadTotal += framesRead;
+ }
+ return framesRead;
+}
+
+aaudio_data_callback_result_t NativeAudioAnalyzer::dataCallbackProc(
+ void *audioData,
+ int32_t numFrames
+) {
+ aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE;
+ float *outputData = (float *) audioData;
+
+ // Read audio data from the input stream.
+ int32_t actualFramesRead;
+
+ if (numFrames > mInputFramesMaximum) {
+ ALOGE("%s() numFrames:%d > mInputFramesMaximum:%d", __func__, numFrames, mInputFramesMaximum);
+ mInputError = AAUDIO_ERROR_OUT_OF_RANGE;
+ return AAUDIO_CALLBACK_RESULT_STOP;
+ }
+
+ if (numFrames > mMaxNumFrames) {
+ mMaxNumFrames = numFrames;
+ }
+ if (numFrames < mMinNumFrames) {
+ mMinNumFrames = numFrames;
+ }
+
+ // Silence the output.
+ int32_t numBytes = numFrames * mActualOutputChannelCount * sizeof(float);
+ memset(audioData, 0 /* value */, numBytes);
+
+ if (mNumCallbacksToDrain > 0) {
+ // Drain the input FIFOs.
+ int32_t totalFramesRead = 0;
+ do {
+ actualFramesRead = readFormattedData(numFrames);
+ if (actualFramesRead > 0) {
+ totalFramesRead += actualFramesRead;
+ } else if (actualFramesRead < 0) {
+ callbackResult = AAUDIO_CALLBACK_RESULT_STOP;
+ }
+ // Ignore errors because input stream may not be started yet.
+ } while (actualFramesRead > 0);
+ // Only counts if we actually got some data.
+ if (totalFramesRead > 0) {
+ mNumCallbacksToDrain--;
+ }
+
+ } else if (mNumCallbacksToNotRead > 0) {
+ // Let the input fill up a bit so we are not so close to the write pointer.
+ mNumCallbacksToNotRead--;
+ } else if (mNumCallbacksToDiscard > 0) {
+ // Ignore. Allow the input to fill back up to equilibrium with the output.
+ actualFramesRead = readFormattedData(numFrames);
+ if (actualFramesRead < 0) {
+ callbackResult = AAUDIO_CALLBACK_RESULT_STOP;
+ }
+ mNumCallbacksToDiscard--;
+
+ } else {
+ // The full duplex stream is now stable so process the audio.
+ int32_t numInputBytes = numFrames * mActualInputChannelCount * sizeof(float);
+ memset(mInputFloatData, 0 /* value */, numInputBytes);
+
+ int64_t inputFramesWritten = AAudioStream_getFramesWritten(mInputStream);
+ int64_t inputFramesRead = AAudioStream_getFramesRead(mInputStream);
+ int64_t framesAvailable = inputFramesWritten - inputFramesRead;
+
+ // Read the INPUT data.
+ actualFramesRead = readFormattedData(numFrames); // READ
+ if (actualFramesRead < 0) {
+ callbackResult = AAUDIO_CALLBACK_RESULT_STOP;
+ } else {
+ if (actualFramesRead < numFrames) {
+ if(actualFramesRead < (int32_t) framesAvailable) {
+ ALOGE("insufficient for no reason, numFrames = %d"
+ ", actualFramesRead = %d"
+ ", inputFramesWritten = %d"
+ ", inputFramesRead = %d"
+ ", available = %d\n",
+ numFrames,
+ actualFramesRead,
+ (int) inputFramesWritten,
+ (int) inputFramesRead,
+ (int) framesAvailable);
+ }
+ mInsufficientReadCount++;
+ mInsufficientReadFrames += numFrames - actualFramesRead; // deficit
+ // ALOGE("Error insufficientReadCount = %d\n",(int)mInsufficientReadCount);
+ }
+
+ int32_t numSamples = actualFramesRead * mActualInputChannelCount;
+
+ if (mActualInputFormat == AAUDIO_FORMAT_PCM_I16) {
+ convertPcm16ToFloat(mInputShortData, mInputFloatData, numSamples);
+ }
+
+ // Process the INPUT and generate the OUTPUT.
+ mLoopbackProcessor->process(mInputFloatData,
+ mActualInputChannelCount,
+ numFrames,
+ outputData,
+ mActualOutputChannelCount,
+ numFrames);
+
+ mIsDone = mLoopbackProcessor->isDone();
+ if (mIsDone) {
+ callbackResult = AAUDIO_CALLBACK_RESULT_STOP;
+ }
+ }
+ }
+ mFramesWrittenTotal += numFrames;
+
+ return callbackResult;
+}
+
+static aaudio_data_callback_result_t s_MyDataCallbackProc(
+ AAudioStream * /* outputStream */,
+ void *userData,
+ void *audioData,
+ int32_t numFrames) {
+ NativeAudioAnalyzer *myData = (NativeAudioAnalyzer *) userData;
+ return myData->dataCallbackProc(audioData, numFrames);
+}
+
+static void s_MyErrorCallbackProc(
+ AAudioStream * /* stream */,
+ void * userData,
+ aaudio_result_t error) {
+ ALOGE("Error Callback, error: %d\n",(int)error);
+ NativeAudioAnalyzer *myData = (NativeAudioAnalyzer *) userData;
+ myData->mOutputError = error;
+}
+
+bool NativeAudioAnalyzer::isRecordingComplete() {
+ return mPulseLatencyAnalyzer.isRecordingComplete();
+}
+
+int NativeAudioAnalyzer::analyze() {
+ mPulseLatencyAnalyzer.analyze();
+ return getError(); // TODO review
+}
+
+double NativeAudioAnalyzer::getLatencyMillis() {
+ return mPulseLatencyAnalyzer.getMeasuredLatency() * 1000.0 / 48000;
+}
+
+double NativeAudioAnalyzer::getConfidence() {
+ return mPulseLatencyAnalyzer.getMeasuredConfidence();
+}
+
+aaudio_result_t NativeAudioAnalyzer::openAudio() {
+ AAudioStreamBuilder *builder = nullptr;
+
+ mLoopbackProcessor = &mPulseLatencyAnalyzer; // for latency test
+
+ // Use an AAudioStreamBuilder to contain requested parameters.
+ aaudio_result_t result = AAudio_createStreamBuilder(&builder);
+ if (result != AAUDIO_OK) {
+ ALOGE("AAudio_createStreamBuilder() returned %s",
+ AAudio_convertResultToText(result));
+ return result;
+ }
+
+ // Create the OUTPUT stream -----------------------
+ AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);
+ AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+ AAudioStreamBuilder_setSharingMode(builder, AAUDIO_SHARING_MODE_EXCLUSIVE);
+ AAudioStreamBuilder_setFormat(builder, AAUDIO_FORMAT_PCM_FLOAT);
+ AAudioStreamBuilder_setChannelCount(builder, 2); // stereo
+ AAudioStreamBuilder_setDataCallback(builder, s_MyDataCallbackProc, this);
+ AAudioStreamBuilder_setErrorCallback(builder, s_MyErrorCallbackProc, this);
+
+ result = AAudioStreamBuilder_openStream(builder, &mOutputStream);
+ if (result != AAUDIO_OK) {
+ ALOGE("NativeAudioAnalyzer::openAudio() OUTPUT error %s",
+ AAudio_convertResultToText(result));
+ return result;
+ }
+
+ int32_t outputFramesPerBurst = AAudioStream_getFramesPerBurst(mOutputStream);
+ (void) AAudioStream_setBufferSizeInFrames(mOutputStream, outputFramesPerBurst * kDefaultOutputSizeBursts);
+
+ int32_t outputSampleRate = AAudioStream_getSampleRate(mOutputStream);
+ mActualOutputChannelCount = AAudioStream_getChannelCount(mOutputStream);
+
+ // Create the INPUT stream -----------------------
+ AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_INPUT);
+ AAudioStreamBuilder_setFormat(builder, AAUDIO_FORMAT_UNSPECIFIED);
+ AAudioStreamBuilder_setSampleRate(builder, outputSampleRate); // must match
+ AAudioStreamBuilder_setChannelCount(builder, 1); // mono
+ AAudioStreamBuilder_setDataCallback(builder, nullptr, nullptr);
+ AAudioStreamBuilder_setErrorCallback(builder, nullptr, nullptr);
+ result = AAudioStreamBuilder_openStream(builder, &mInputStream);
+ if (result != AAUDIO_OK) {
+ ALOGE("NativeAudioAnalyzer::openAudio() INPUT error %s",
+ AAudio_convertResultToText(result));
+ return result;
+ }
+
+ int32_t actualCapacity = AAudioStream_getBufferCapacityInFrames(mInputStream);
+ (void) AAudioStream_setBufferSizeInFrames(mInputStream, actualCapacity);
+
+ // ------- Setup loopbackData -----------------------------
+ mActualInputFormat = AAudioStream_getFormat(mInputStream);
+ mActualInputChannelCount = AAudioStream_getChannelCount(mInputStream);
+
+ // Allocate a buffer for the audio data.
+ mInputFramesMaximum = 32 * AAudioStream_getFramesPerBurst(mInputStream);
+
+ if (mActualInputFormat == AAUDIO_FORMAT_PCM_I16) {
+ mInputShortData = new int16_t[mInputFramesMaximum * mActualInputChannelCount]{};
+ }
+ mInputFloatData = new float[mInputFramesMaximum * mActualInputChannelCount]{};
+
+ return result;
+}
+
+aaudio_result_t NativeAudioAnalyzer::startAudio() {
+ mLoopbackProcessor->prepareToTest();
+
+ // Start OUTPUT first so INPUT does not overflow.
+ aaudio_result_t result = AAudioStream_requestStart(mOutputStream);
+ if (result != AAUDIO_OK) {
+ stopAudio();
+ return result;
+ }
+
+ result = AAudioStream_requestStart(mInputStream);
+ if (result != AAUDIO_OK) {
+ stopAudio();
+ return result;
+ }
+
+ return result;
+}
+
+aaudio_result_t NativeAudioAnalyzer::stopAudio() {
+ aaudio_result_t result1 = AAUDIO_OK;
+ aaudio_result_t result2 = AAUDIO_OK;
+ ALOGD("stopAudio() , minNumFrames = %d, maxNumFrames = %d\n", mMinNumFrames, mMaxNumFrames);
+ // Stop OUTPUT first because it uses INPUT.
+ if (mOutputStream != nullptr) {
+ result1 = AAudioStream_requestStop(mOutputStream);
+ }
+
+ // Stop INPUT.
+ if (mInputStream != nullptr) {
+ result2 = AAudioStream_requestStop(mInputStream);
+ }
+ return result1 != AAUDIO_OK ? result1 : result2;
+}
+
+aaudio_result_t NativeAudioAnalyzer::closeAudio() {
+ aaudio_result_t result1 = AAUDIO_OK;
+ aaudio_result_t result2 = AAUDIO_OK;
+ // Stop and close OUTPUT first because it uses INPUT.
+ if (mOutputStream != nullptr) {
+ result1 = AAudioStream_close(mOutputStream);
+ mOutputStream = nullptr;
+ }
+
+ // Stop and close INPUT.
+ if (mInputStream != nullptr) {
+ result2 = AAudioStream_close(mInputStream);
+ mInputStream = nullptr;
+ }
+ return result1 != AAUDIO_OK ? result1 : result2;
+}
diff --git a/apps/CtsVerifier/jni/audio_loopback/NativeAudioAnalyzer.h b/apps/CtsVerifier/jni/audio_loopback/NativeAudioAnalyzer.h
new file mode 100644
index 0000000..0d9c64b
--- /dev/null
+++ b/apps/CtsVerifier/jni/audio_loopback/NativeAudioAnalyzer.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#ifndef CTS_NATIVE_AUDIO_ANALYZER_H
+#define CTS_NATIVE_AUDIO_ANALYZER_H
+
+#define LOG_TAG "NativeAudioAnalyzer"
+#include <android/log.h>
+
+#ifndef MODULE_NAME
+#define MODULE_NAME "NativeAudioAnalyzer"
+#endif
+
+#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, MODULE_NAME, __VA_ARGS__)
+#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, MODULE_NAME, __VA_ARGS__)
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, MODULE_NAME, __VA_ARGS__)
+#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, MODULE_NAME, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, MODULE_NAME, __VA_ARGS__)
+#define ALOGF(...) __android_log_print(ANDROID_LOG_FATAL, MODULE_NAME, __VA_ARGS__)
+
+#include <aaudio/AAudio.h>
+
+#include "analyzer/GlitchAnalyzer.h"
+#include "analyzer/LatencyAnalyzer.h"
+
+class NativeAudioAnalyzer {
+public:
+
+ /**
+ * Open the audio input and output streams.
+ * @return AAUDIO_OK or negative error
+ */
+ aaudio_result_t openAudio();
+
+ /**
+ * Start the audio input and output streams.
+ * @return AAUDIO_OK or negative error
+ */
+ aaudio_result_t startAudio();
+
+ /**
+ * Stop the audio input and output streams.
+ * @return AAUDIO_OK or negative error
+ */
+ aaudio_result_t stopAudio();
+
+ /**
+ * Close the audio input and output streams.
+ * @return AAUDIO_OK or negative error
+ */
+ aaudio_result_t closeAudio();
+
+ /**
+ * @return true if enough audio input has been recorded
+ */
+ bool isRecordingComplete();
+
+ /**
+ * Analyze the input and measure the latency between output and input.
+ * @return AAUDIO_OK or negative error
+ */
+ int analyze();
+
+ /**
+ * @return the measured latency in milliseconds
+ */
+ double getLatencyMillis();
+
+ /**
+ * The confidence is based on a normalized correlation.
+ * It ranges from 0.0 to 1.0. Higher is better.
+ *
+ * @return the confidence in the latency result
+ */
+ double getConfidence();
+
+ aaudio_result_t getError() {
+ return mInputError ? mInputError : mOutputError;
+ }
+
+ AAudioStream *mInputStream = nullptr;
+ AAudioStream *mOutputStream = nullptr;
+ aaudio_format_t mActualInputFormat = AAUDIO_FORMAT_INVALID;
+ int16_t *mInputShortData = nullptr;
+ float *mInputFloatData = nullptr;
+
+ aaudio_result_t mInputError = AAUDIO_OK;
+ aaudio_result_t mOutputError = AAUDIO_OK;
+
+aaudio_data_callback_result_t dataCallbackProc(
+ void *audioData,
+ int32_t numFrames);
+
+private:
+
+ int32_t readFormattedData(int32_t numFrames);
+
+ GlitchAnalyzer mSineAnalyzer;
+ PulseLatencyAnalyzer mPulseLatencyAnalyzer;
+ LoopbackProcessor *mLoopbackProcessor;
+
+ int32_t mInputFramesMaximum = 0;
+ int32_t mActualInputChannelCount = 0;
+ int32_t mActualOutputChannelCount = 0;
+ int32_t mNumCallbacksToDrain = kNumCallbacksToDrain;
+ int32_t mNumCallbacksToNotRead = kNumCallbacksToNotRead;
+ int32_t mNumCallbacksToDiscard = kNumCallbacksToDiscard;
+ int32_t mMinNumFrames = INT32_MAX;
+ int32_t mMaxNumFrames = 0;
+ int32_t mInsufficientReadCount = 0;
+ int32_t mInsufficientReadFrames = 0;
+ int32_t mFramesReadTotal = 0;
+ int32_t mFramesWrittenTotal = 0;
+ bool mIsDone = false;
+
+ static constexpr int kLogPeriodMillis = 1000;
+ static constexpr int kNumInputChannels = 1;
+ static constexpr int kNumCallbacksToDrain = 20;
+ static constexpr int kNumCallbacksToNotRead = 0; // let input fill back up
+ static constexpr int kNumCallbacksToDiscard = 20;
+ static constexpr int kDefaultHangTimeMillis = 50;
+ static constexpr int kMaxGlitchEventsToSave = 32;
+ static constexpr int kDefaultOutputSizeBursts = 2;
+};
+
+#endif // CTS_NATIVE_AUDIO_ANALYZER_H
diff --git a/apps/CtsVerifier/jni/audio_loopback/analyzer/GlitchAnalyzer.h b/apps/CtsVerifier/jni/audio_loopback/analyzer/GlitchAnalyzer.h
new file mode 100644
index 0000000..0adcd6e
--- /dev/null
+++ b/apps/CtsVerifier/jni/audio_loopback/analyzer/GlitchAnalyzer.h
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANALYZER_GLITCH_ANALYZER_H
+#define ANALYZER_GLITCH_ANALYZER_H
+
+#include <algorithm>
+#include <cctype>
+#include <iomanip>
+#include <iostream>
+
+#include "LatencyAnalyzer.h"
+#include "PseudoRandom.h"
+
+/**
+ * Output a steady sine wave and analyze the return signal.
+ *
+ * Use a cosine transform to measure the predicted magnitude and relative phase of the
+ * looped back sine wave. Then generate a predicted signal and compare with the actual signal.
+ */
+class GlitchAnalyzer : public LoopbackProcessor {
+public:
+
+ int32_t getState() const {
+ return mState;
+ }
+
+ double getPeakAmplitude() const {
+ return mPeakFollower.getLevel();
+ }
+
+ double getTolerance() {
+ return mTolerance;
+ }
+
+ void setTolerance(double tolerance) {
+ mTolerance = tolerance;
+ mScaledTolerance = mMagnitude * mTolerance;
+ }
+
+ void setMagnitude(double magnitude) {
+ mMagnitude = magnitude;
+ mScaledTolerance = mMagnitude * mTolerance;
+ }
+
+ int32_t getGlitchCount() const {
+ return mGlitchCount;
+ }
+
+ int32_t getStateFrameCount(int state) const {
+ return mStateFrameCounters[state];
+ }
+
+ double getSignalToNoiseDB() {
+ static const double threshold = 1.0e-14;
+ if (mMeanSquareSignal < threshold || mMeanSquareNoise < threshold) {
+ return 0.0;
+ } else {
+ double signalToNoise = mMeanSquareSignal / mMeanSquareNoise; // power ratio
+ double signalToNoiseDB = 10.0 * log(signalToNoise);
+ if (signalToNoiseDB < MIN_SNR_DB) {
+ ALOGD("ERROR - signal to noise ratio is too low! < %d dB. Adjust volume.",
+ MIN_SNR_DB);
+ setResult(ERROR_VOLUME_TOO_LOW);
+ }
+ return signalToNoiseDB;
+ }
+ }
+
+ std::string analyze() override {
+ std::stringstream report;
+ report << "GlitchAnalyzer ------------------\n";
+ report << LOOPBACK_RESULT_TAG "peak.amplitude = " << std::setw(8)
+ << getPeakAmplitude() << "\n";
+ report << LOOPBACK_RESULT_TAG "sine.magnitude = " << std::setw(8)
+ << mMagnitude << "\n";
+ report << LOOPBACK_RESULT_TAG "rms.noise = " << std::setw(8)
+ << mMeanSquareNoise << "\n";
+ report << LOOPBACK_RESULT_TAG "signal.to.noise.db = " << std::setw(8)
+ << getSignalToNoiseDB() << "\n";
+ report << LOOPBACK_RESULT_TAG "frames.accumulated = " << std::setw(8)
+ << mFramesAccumulated << "\n";
+ report << LOOPBACK_RESULT_TAG "sine.period = " << std::setw(8)
+ << mSinePeriod << "\n";
+ report << LOOPBACK_RESULT_TAG "test.state = " << std::setw(8)
+ << mState << "\n";
+ report << LOOPBACK_RESULT_TAG "frame.count = " << std::setw(8)
+ << mFrameCounter << "\n";
+ // Did we ever get a lock?
+ bool gotLock = (mState == STATE_LOCKED) || (mGlitchCount > 0);
+ if (!gotLock) {
+ report << "ERROR - failed to lock on reference sine tone.\n";
+ setResult(ERROR_NO_LOCK);
+ } else {
+ // Only print if meaningful.
+ report << LOOPBACK_RESULT_TAG "glitch.count = " << std::setw(8)
+ << mGlitchCount << "\n";
+ report << LOOPBACK_RESULT_TAG "max.glitch = " << std::setw(8)
+ << mMaxGlitchDelta << "\n";
+ if (mGlitchCount > 0) {
+ report << "ERROR - number of glitches > 0\n";
+ setResult(ERROR_GLITCHES);
+ }
+ }
+ return report.str();
+ }
+
+ void printStatus() override {
+ ALOGD("st = %d, #gl = %3d,", mState, mGlitchCount);
+ }
+ /**
+ * Calculate the magnitude of the component of the input signal
+ * that matches the analysis frequency.
+ * Also calculate the phase that we can use to create a
+ * signal that matches that component.
+ * The phase will be between -PI and +PI.
+ */
+ double calculateMagnitude(double *phasePtr = nullptr) {
+ if (mFramesAccumulated == 0) {
+ return 0.0;
+ }
+ double sinMean = mSinAccumulator / mFramesAccumulated;
+ double cosMean = mCosAccumulator / mFramesAccumulated;
+ double magnitude = 2.0 * sqrt((sinMean * sinMean) + (cosMean * cosMean));
+ if (phasePtr != nullptr) {
+ double phase = M_PI_2 - atan2(sinMean, cosMean);
+ *phasePtr = phase;
+ }
+ return magnitude;
+ }
+
+ /**
+ * @param frameData contains microphone data with sine signal feedback
+ * @param channelCount
+ */
+ result_code processInputFrame(float *frameData, int /* channelCount */) override {
+ result_code result = RESULT_OK;
+
+ float sample = frameData[0];
+ float peak = mPeakFollower.process(sample);
+
+ // Force a periodic glitch to test the detector!
+ if (mForceGlitchDuration > 0) {
+ if (mForceGlitchCounter == 0) {
+ ALOGE("%s: force a glitch!!", __func__);
+ mForceGlitchCounter = getSampleRate();
+ } else if (mForceGlitchCounter <= mForceGlitchDuration) {
+ // Force an abrupt offset.
+ sample += (sample > 0.0) ? -0.5f : 0.5f;
+ }
+ --mForceGlitchCounter;
+ }
+
+ mStateFrameCounters[mState]++; // count how many frames we are in each state
+
+ switch (mState) {
+ case STATE_IDLE:
+ mDownCounter--;
+ if (mDownCounter <= 0) {
+ mState = STATE_IMMUNE;
+ mDownCounter = IMMUNE_FRAME_COUNT;
+ mInputPhase = 0.0; // prevent spike at start
+ mOutputPhase = 0.0;
+ }
+ break;
+
+ case STATE_IMMUNE:
+ mDownCounter--;
+ if (mDownCounter <= 0) {
+ mState = STATE_WAITING_FOR_SIGNAL;
+ }
+ break;
+
+ case STATE_WAITING_FOR_SIGNAL:
+ if (peak > mThreshold) {
+ mState = STATE_WAITING_FOR_LOCK;
+ //ALOGD("%5d: switch to STATE_WAITING_FOR_LOCK", mFrameCounter);
+ resetAccumulator();
+ }
+ break;
+
+ case STATE_WAITING_FOR_LOCK:
+ mSinAccumulator += sample * sinf(mInputPhase);
+ mCosAccumulator += sample * cosf(mInputPhase);
+ mFramesAccumulated++;
+ // Must be a multiple of the period or the calculation will not be accurate.
+ if (mFramesAccumulated == mSinePeriod * PERIODS_NEEDED_FOR_LOCK) {
+ double phaseOffset = 0.0;
+ setMagnitude(calculateMagnitude(&phaseOffset));
+// ALOGD("%s() mag = %f, offset = %f, prev = %f",
+// __func__, mMagnitude, mPhaseOffset, mPreviousPhaseOffset);
+ if (mMagnitude > mThreshold) {
+ if (abs(phaseOffset) < kMaxPhaseError) {
+ mState = STATE_LOCKED;
+// ALOGD("%5d: switch to STATE_LOCKED", mFrameCounter);
+ }
+ // Adjust mInputPhase to match measured phase
+ mInputPhase += phaseOffset;
+ }
+ resetAccumulator();
+ }
+ incrementInputPhase();
+ break;
+
+ case STATE_LOCKED: {
+ // Predict next sine value
+ double predicted = sinf(mInputPhase) * mMagnitude;
+ double diff = predicted - sample;
+ double absDiff = fabs(diff);
+ mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff);
+ if (absDiff > mScaledTolerance) {
+ result = ERROR_GLITCHES;
+ onGlitchStart();
+// LOGI("diff glitch detected, absDiff = %g", absDiff);
+ } else {
+ mSumSquareSignal += predicted * predicted;
+ mSumSquareNoise += diff * diff;
+ // Track incoming signal and slowly adjust magnitude to account
+ // for drift in the DRC or AGC.
+ mSinAccumulator += sample * sinf(mInputPhase);
+ mCosAccumulator += sample * cosf(mInputPhase);
+ mFramesAccumulated++;
+ // Must be a multiple of the period or the calculation will not be accurate.
+ if (mFramesAccumulated == mSinePeriod) {
+ const double coefficient = 0.1;
+ double phaseOffset = 0.0;
+ double magnitude = calculateMagnitude(&phaseOffset);
+ // One pole averaging filter.
+ setMagnitude((mMagnitude * (1.0 - coefficient)) + (magnitude * coefficient));
+
+ mMeanSquareNoise = mSumSquareNoise * mInverseSinePeriod;
+ mMeanSquareSignal = mSumSquareSignal * mInverseSinePeriod;
+ resetAccumulator();
+
+ if (abs(phaseOffset) > kMaxPhaseError) {
+ result = ERROR_GLITCHES;
+ onGlitchStart();
+ ALOGD("phase glitch detected, phaseOffset = %g", phaseOffset);
+ } else if (mMagnitude < mThreshold) {
+ result = ERROR_GLITCHES;
+ onGlitchStart();
+ ALOGD("magnitude glitch detected, mMagnitude = %g", mMagnitude);
+ }
+ }
+ }
+ incrementInputPhase();
+ } break;
+
+ case STATE_GLITCHING: {
+ // Predict next sine value
+ mGlitchLength++;
+ double predicted = sinf(mInputPhase) * mMagnitude;
+ double diff = predicted - sample;
+ double absDiff = fabs(diff);
+ mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff);
+ if (absDiff < mScaledTolerance) { // close enough?
+ // If we get a full sine period of non-glitch samples in a row then consider the glitch over.
+ // We don't want to just consider a zero crossing the end of a glitch.
+ if (mNonGlitchCount++ > mSinePeriod) {
+ onGlitchEnd();
+ }
+ } else {
+ mNonGlitchCount = 0;
+ if (mGlitchLength > (4 * mSinePeriod)) {
+ relock();
+ }
+ }
+ incrementInputPhase();
+ } break;
+
+ case NUM_STATES: // not a real state
+ break;
+ }
+
+ mFrameCounter++;
+
+ return result;
+ }
+
+ // advance and wrap phase
+ void incrementInputPhase() {
+ mInputPhase += mPhaseIncrement;
+ if (mInputPhase > M_PI) {
+ mInputPhase -= (2.0 * M_PI);
+ }
+ }
+
+ // advance and wrap phase
+ void incrementOutputPhase() {
+ mOutputPhase += mPhaseIncrement;
+ if (mOutputPhase > M_PI) {
+ mOutputPhase -= (2.0 * M_PI);
+ }
+ }
+
+ /**
+ * @param frameData upon return, contains the reference sine wave
+ * @param channelCount
+ */
+ result_code processOutputFrame(float *frameData, int channelCount) override {
+ float output = 0.0f;
+ // Output sine wave so we can measure it.
+ if (mState != STATE_IDLE) {
+ float sinOut = sinf(mOutputPhase);
+ incrementOutputPhase();
+ output = (sinOut * mOutputAmplitude)
+ + (mWhiteNoise.nextRandomDouble() * kNoiseAmplitude);
+ // ALOGD("sin(%f) = %f, %f\n", mOutputPhase, sinOut, mPhaseIncrement);
+ }
+ frameData[0] = output;
+ for (int i = 1; i < channelCount; i++) {
+ frameData[i] = 0.0f;
+ }
+ return RESULT_OK;
+ }
+
+ void onGlitchStart() {
+ mGlitchCount++;
+// ALOGD("%5d: STARTED a glitch # %d", mFrameCounter, mGlitchCount);
+ mState = STATE_GLITCHING;
+ mGlitchLength = 1;
+ mNonGlitchCount = 0;
+ }
+
+ void onGlitchEnd() {
+// ALOGD("%5d: ENDED a glitch # %d, length = %d", mFrameCounter, mGlitchCount, mGlitchLength);
+ mState = STATE_LOCKED;
+ resetAccumulator();
+ }
+
+ // reset the sine wave detector
+ void resetAccumulator() {
+ mFramesAccumulated = 0;
+ mSinAccumulator = 0.0;
+ mCosAccumulator = 0.0;
+ mSumSquareSignal = 0.0;
+ mSumSquareNoise = 0.0;
+ }
+
+ void relock() {
+// ALOGD("relock: %d because of a very long %d glitch", mFrameCounter, mGlitchLength);
+ mState = STATE_WAITING_FOR_LOCK;
+ resetAccumulator();
+ }
+
+ void reset() override {
+ LoopbackProcessor::reset();
+ mState = STATE_IDLE;
+ mDownCounter = IDLE_FRAME_COUNT;
+ resetAccumulator();
+ }
+
+ void prepareToTest() override {
+ LoopbackProcessor::prepareToTest();
+ mSinePeriod = getSampleRate() / kTargetGlitchFrequency;
+ mOutputPhase = 0.0f;
+ mInverseSinePeriod = 1.0 / mSinePeriod;
+ mPhaseIncrement = 2.0 * M_PI * mInverseSinePeriod;
+ mGlitchCount = 0;
+ mMaxGlitchDelta = 0.0;
+ for (int i = 0; i < NUM_STATES; i++) {
+ mStateFrameCounters[i] = 0;
+ }
+ }
+
+private:
+
+ // These must match the values in GlitchActivity.java
+ enum sine_state_t {
+ STATE_IDLE, // beginning
+ STATE_IMMUNE, // ignoring input, waiting fo HW to settle
+ STATE_WAITING_FOR_SIGNAL, // looking for a loud signal
+ STATE_WAITING_FOR_LOCK, // trying to lock onto the phase of the sine
+ STATE_LOCKED, // locked on the sine wave, looking for glitches
+ STATE_GLITCHING, // locked on the sine wave but glitching
+ NUM_STATES
+ };
+
+ enum constants {
+ // Arbitrary durations, assuming 48000 Hz
+ IDLE_FRAME_COUNT = 48 * 100,
+ IMMUNE_FRAME_COUNT = 48 * 100,
+ PERIODS_NEEDED_FOR_LOCK = 8,
+ MIN_SNR_DB = 65
+ };
+
+ static constexpr float kNoiseAmplitude = 0.00; // Used to experiment with warbling caused by DRC.
+ static constexpr int kTargetGlitchFrequency = 607;
+ static constexpr double kMaxPhaseError = M_PI * 0.05;
+
+ float mTolerance = 0.10; // scaled from 0.0 to 1.0
+ double mThreshold = 0.005;
+ int mSinePeriod = 1; // this will be set before use
+ double mInverseSinePeriod = 1.0;
+
+ int32_t mStateFrameCounters[NUM_STATES];
+
+ double mPhaseIncrement = 0.0;
+ double mInputPhase = 0.0;
+ double mOutputPhase = 0.0;
+ double mMagnitude = 0.0;
+ int32_t mFramesAccumulated = 0;
+ double mSinAccumulator = 0.0;
+ double mCosAccumulator = 0.0;
+ double mMaxGlitchDelta = 0.0;
+ int32_t mGlitchCount = 0;
+ int32_t mNonGlitchCount = 0;
+ int32_t mGlitchLength = 0;
+ // This is used for processing every frame so we cache it here.
+ double mScaledTolerance = 0.0;
+ int mDownCounter = IDLE_FRAME_COUNT;
+ int32_t mFrameCounter = 0;
+ double mOutputAmplitude = 0.75;
+
+ int32_t mForceGlitchDuration = 0; // if > 0 then force a glitch for debugging
+ int32_t mForceGlitchCounter = 4 * 48000; // count down and trigger at zero
+
+ // measure background noise continuously as a deviation from the expected signal
+ double mSumSquareSignal = 0.0;
+ double mSumSquareNoise = 0.0;
+ double mMeanSquareSignal = 0.0;
+ double mMeanSquareNoise = 0.0;
+
+ PeakDetector mPeakFollower;
+
+ PseudoRandom mWhiteNoise;
+
+ sine_state_t mState = STATE_IDLE;
+};
+
+
+#endif //ANALYZER_GLITCH_ANALYZER_H
diff --git a/apps/CtsVerifier/jni/audio_loopback/analyzer/LatencyAnalyzer.h b/apps/CtsVerifier/jni/audio_loopback/analyzer/LatencyAnalyzer.h
new file mode 100644
index 0000000..59106cb
--- /dev/null
+++ b/apps/CtsVerifier/jni/audio_loopback/analyzer/LatencyAnalyzer.h
@@ -0,0 +1,604 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+/**
+ * Tools for measuring latency and for detecting glitches.
+ * These classes are pure math and can be used with any audio system.
+ */
+
+#ifndef ANALYZER_LATENCY_ANALYZER_H
+#define ANALYZER_LATENCY_ANALYZER_H
+
+#include <algorithm>
+#include <assert.h>
+#include <cctype>
+#include <iomanip>
+#include <iostream>
+#include <math.h>
+#include <memory>
+#include <sstream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <vector>
+
+#include "PeakDetector.h"
+#include "PseudoRandom.h"
+#include "RandomPulseGenerator.h"
+
+
+#define LOOPBACK_RESULT_TAG "RESULT: "
+
+static constexpr int32_t kDefaultSampleRate = 48000;
+static constexpr int32_t kMillisPerSecond = 1000;
+static constexpr int32_t kMaxLatencyMillis = 700; // arbitrary and generous
+static constexpr double kMinimumConfidence = 0.2;
+
+struct LatencyReport {
+ int32_t latencyInFrames = 0.0;
+ double confidence = 0.0;
+
+ void reset() {
+ latencyInFrames = 0;
+ confidence = 0.0;
+ }
+};
+
+// Calculate a normalized cross correlation.
+static double calculateNormalizedCorrelation(const float *a,
+ const float *b,
+ int windowSize) {
+ double correlation = 0.0;
+ double sumProducts = 0.0;
+ double sumSquares = 0.0;
+
+ // Correlate a against b.
+ for (int i = 0; i < windowSize; i++) {
+ float s1 = a[i];
+ float s2 = b[i];
+ // Use a normalized cross-correlation.
+ sumProducts += s1 * s2;
+ sumSquares += ((s1 * s1) + (s2 * s2));
+ }
+
+ if (sumSquares >= 1.0e-9) {
+ correlation = 2.0 * sumProducts / sumSquares;
+ }
+ return correlation;
+}
+
+static double calculateRootMeanSquare(float *data, int32_t numSamples) {
+ double sum = 0.0;
+ for (int32_t i = 0; i < numSamples; i++) {
+ float sample = data[i];
+ sum += sample * sample;
+ }
+ return sqrt(sum / numSamples);
+}
+
+/**
+ * Monophonic recording with processing.
+ */
+class AudioRecording
+{
+public:
+
+ void allocate(int maxFrames) {
+ mData = std::make_unique<float[]>(maxFrames);
+ mMaxFrames = maxFrames;
+ }
+
+ // Write SHORT data from the first channel.
+ int32_t write(int16_t *inputData, int32_t inputChannelCount, int32_t numFrames) {
+ // stop at end of buffer
+ if ((mFrameCounter + numFrames) > mMaxFrames) {
+ numFrames = mMaxFrames - mFrameCounter;
+ }
+ for (int i = 0; i < numFrames; i++) {
+ mData[mFrameCounter++] = inputData[i * inputChannelCount] * (1.0f / 32768);
+ }
+ return numFrames;
+ }
+
+ // Write FLOAT data from the first channel.
+ int32_t write(float *inputData, int32_t inputChannelCount, int32_t numFrames) {
+ // stop at end of buffer
+ if ((mFrameCounter + numFrames) > mMaxFrames) {
+ numFrames = mMaxFrames - mFrameCounter;
+ }
+ for (int i = 0; i < numFrames; i++) {
+ mData[mFrameCounter++] = inputData[i * inputChannelCount];
+ }
+ return numFrames;
+ }
+
+ // Write FLOAT data from the first channel.
+ int32_t write(float sample) {
+ // stop at end of buffer
+ if (mFrameCounter < mMaxFrames) {
+ mData[mFrameCounter++] = sample;
+ return 1;
+ }
+ return 0;
+ }
+
+ void clear() {
+ mFrameCounter = 0;
+ }
+ int32_t size() const {
+ return mFrameCounter;
+ }
+
+ bool isFull() const {
+ return mFrameCounter >= mMaxFrames;
+ }
+
+ float *getData() const {
+ return mData.get();
+ }
+
+ void setSampleRate(int32_t sampleRate) {
+ mSampleRate = sampleRate;
+ }
+
+ int32_t getSampleRate() const {
+ return mSampleRate;
+ }
+
+ /**
+ * Square the samples so they are all positive and so the peaks are emphasized.
+ */
+ void square() {
+ float *x = mData.get();
+ for (int i = 0; i < mFrameCounter; i++) {
+ x[i] *= x[i];
+ }
+ }
+
+ /**
+ * Amplify a signal so that the peak matches the specified target.
+ *
+ * @param target final max value
+ * @return gain applied to signal
+ */
+ float normalize(float target) {
+ float maxValue = 1.0e-9f;
+ for (int i = 0; i < mFrameCounter; i++) {
+ maxValue = std::max(maxValue, abs(mData[i]));
+ }
+ float gain = target / maxValue;
+ for (int i = 0; i < mFrameCounter; i++) {
+ mData[i] *= gain;
+ }
+ return gain;
+ }
+
+private:
+ std::unique_ptr<float[]> mData;
+ int32_t mFrameCounter = 0;
+ int32_t mMaxFrames = 0;
+ int32_t mSampleRate = kDefaultSampleRate; // common default
+};
+
+static int measureLatencyFromPulse(AudioRecording &recorded,
+ AudioRecording &pulse,
+ LatencyReport *report) {
+
+ report->latencyInFrames = 0;
+ report->confidence = 0.0;
+
+ int numCorrelations = recorded.size() - pulse.size();
+ if (numCorrelations < 10) {
+ ALOGE("%s() recording too small = %d frames\n", __func__, recorded.size());
+ return -1;
+ }
+ std::unique_ptr<float[]> correlations= std::make_unique<float[]>(numCorrelations);
+
+ // Correlate pulse against the recorded data.
+ for (int i = 0; i < numCorrelations; i++) {
+ float correlation = (float) calculateNormalizedCorrelation(&recorded.getData()[i],
+ &pulse.getData()[0],
+ pulse.size());
+ correlations[i] = correlation;
+ }
+
+ // Find highest peak in correlation array.
+ float peakCorrelation = 0.0;
+ int peakIndex = -1;
+ for (int i = 0; i < numCorrelations; i++) {
+ float value = abs(correlations[i]);
+ if (value > peakCorrelation) {
+ peakCorrelation = value;
+ peakIndex = i;
+ }
+ }
+ if (peakIndex < 0) {
+ ALOGE("%s() no signal for correlation\n", __func__);
+ return -2;
+ }
+
+ report->latencyInFrames = peakIndex;
+ report->confidence = peakCorrelation;
+
+ return 0;
+}
+
+// ====================================================================================
+class LoopbackProcessor {
+public:
+ virtual ~LoopbackProcessor() = default;
+
+ enum result_code {
+ RESULT_OK = 0,
+ ERROR_NOISY = -99,
+ ERROR_VOLUME_TOO_LOW,
+ ERROR_VOLUME_TOO_HIGH,
+ ERROR_CONFIDENCE,
+ ERROR_INVALID_STATE,
+ ERROR_GLITCHES,
+ ERROR_NO_LOCK
+ };
+
+ virtual void prepareToTest() {
+ reset();
+ }
+
+ virtual void reset() {
+ mResult = 0;
+ mResetCount++;
+ }
+
+ virtual result_code processInputFrame(float *frameData, int channelCount) = 0;
+ virtual result_code processOutputFrame(float *frameData, int channelCount) = 0;
+
+ void process(float *inputData, int inputChannelCount, int numInputFrames,
+ float *outputData, int outputChannelCount, int numOutputFrames) {
+ int numBoth = std::min(numInputFrames, numOutputFrames);
+ // Process one frame at a time.
+ for (int i = 0; i < numBoth; i++) {
+ processInputFrame(inputData, inputChannelCount);
+ inputData += inputChannelCount;
+ processOutputFrame(outputData, outputChannelCount);
+ outputData += outputChannelCount;
+ }
+ // If there is more input than output.
+ for (int i = numBoth; i < numInputFrames; i++) {
+ processInputFrame(inputData, inputChannelCount);
+ inputData += inputChannelCount;
+ }
+ // If there is more output than input.
+ for (int i = numBoth; i < numOutputFrames; i++) {
+ processOutputFrame(outputData, outputChannelCount);
+ outputData += outputChannelCount;
+ }
+ }
+
+ virtual std::string analyze() = 0;
+
+ virtual void printStatus() {};
+
+ int32_t getResult() {
+ return mResult;
+ }
+
+ void setResult(int32_t result) {
+ mResult = result;
+ }
+
+ virtual bool isDone() {
+ return false;
+ }
+
+ virtual int save(const char *fileName) {
+ (void) fileName;
+ return -1;
+ }
+
+ virtual int load(const char *fileName) {
+ (void) fileName;
+ return -1;
+ }
+
+ virtual void setSampleRate(int32_t sampleRate) {
+ mSampleRate = sampleRate;
+ }
+
+ int32_t getSampleRate() const {
+ return mSampleRate;
+ }
+
+ int32_t getResetCount() const {
+ return mResetCount;
+ }
+
+ /** Called when not enough input frames could be read after synchronization.
+ */
+ virtual void onInsufficientRead() {
+ reset();
+ }
+
+protected:
+ int32_t mResetCount = 0;
+
+private:
+ int32_t mSampleRate = kDefaultSampleRate;
+ int32_t mResult = 0;
+};
+
+class LatencyAnalyzer : public LoopbackProcessor {
+public:
+
+ LatencyAnalyzer() : LoopbackProcessor() {}
+ virtual ~LatencyAnalyzer() = default;
+
+ virtual int32_t getProgress() const = 0;
+
+ virtual int getState() = 0;
+
+ // @return latency in frames
+ virtual int32_t getMeasuredLatency() = 0;
+
+ virtual double getMeasuredConfidence() = 0;
+
+ virtual double getBackgroundRMS() = 0;
+
+ virtual double getSignalRMS() = 0;
+
+};
+
+// ====================================================================================
+/**
+ * Measure latency given a loopback stream data.
+ * Use an encoded bit train as the sound source because it
+ * has an unambiguous correlation value.
+ * Uses a state machine to cycle through various stages.
+ *
+ */
+class PulseLatencyAnalyzer : public LatencyAnalyzer {
+public:
+
+ PulseLatencyAnalyzer() : LatencyAnalyzer() {
+ int32_t maxLatencyFrames = getSampleRate() * kMaxLatencyMillis / kMillisPerSecond;
+ int32_t numPulseBits = getSampleRate() * kPulseLengthMillis
+ / (kFramesPerEncodedBit * kMillisPerSecond);
+ int32_t pulseLength = numPulseBits * kFramesPerEncodedBit;
+ mFramesToRecord = pulseLength + maxLatencyFrames;
+ mAudioRecording.allocate(mFramesToRecord);
+ mAudioRecording.setSampleRate(getSampleRate());
+ generateRandomPulse(pulseLength);
+ }
+
+ void generateRandomPulse(int32_t pulseLength) {
+ mPulse.allocate(pulseLength);
+ RandomPulseGenerator pulser(kFramesPerEncodedBit);
+ for (int i = 0; i < pulseLength; i++) {
+ mPulse.write(pulser.nextFloat());
+ }
+ }
+
+ int getState() override {
+ return mState;
+ }
+
+ void setSampleRate(int32_t sampleRate) override {
+ LoopbackProcessor::setSampleRate(sampleRate);
+ mAudioRecording.setSampleRate(sampleRate);
+ }
+
+ void reset() override {
+ LoopbackProcessor::reset();
+ mDownCounter = getSampleRate() / 2;
+ mLoopCounter = 0;
+
+ mPulseCursor = 0;
+ mBackgroundSumSquare = 0.0f;
+ mBackgroundSumCount = 0;
+ mBackgroundRMS = 0.0f;
+ mSignalRMS = 0.0f;
+
+ mState = STATE_MEASURE_BACKGROUND;
+ mAudioRecording.clear();
+ mLatencyReport.reset();
+ }
+
+ bool hasEnoughData() {
+ return mAudioRecording.isFull();
+ }
+
+ bool isDone() override {
+ return mState == STATE_DONE;
+ }
+
+ int32_t getProgress() const override {
+ return mAudioRecording.size();
+ }
+
+ std::string analyze() override {
+ std::stringstream report;
+ report << "PulseLatencyAnalyzer ---------------\n";
+ report << LOOPBACK_RESULT_TAG "test.state = "
+ << std::setw(8) << mState << "\n";
+ report << LOOPBACK_RESULT_TAG "test.state.name = "
+ << convertStateToText(mState) << "\n";
+ report << LOOPBACK_RESULT_TAG "background.rms = "
+ << std::setw(8) << mBackgroundRMS << "\n";
+
+ int32_t newResult = RESULT_OK;
+ if (mState != STATE_GOT_DATA) {
+ report << "WARNING - Bad state. Check volume on device.\n";
+ // setResult(ERROR_INVALID_STATE);
+ } else {
+ float gain = mAudioRecording.normalize(1.0f);
+ measureLatencyFromPulse(mAudioRecording,
+ mPulse,
+ &mLatencyReport);
+
+ if (mLatencyReport.confidence < kMinimumConfidence) {
+ report << " ERROR - confidence too low!";
+ newResult = ERROR_CONFIDENCE;
+ } else {
+ mSignalRMS = calculateRootMeanSquare(
+ &mAudioRecording.getData()[mLatencyReport.latencyInFrames], mPulse.size())
+ / gain;
+ }
+ double latencyMillis = kMillisPerSecond * (double) mLatencyReport.latencyInFrames
+ / getSampleRate();
+ report << LOOPBACK_RESULT_TAG "latency.frames = " << std::setw(8)
+ << mLatencyReport.latencyInFrames << "\n";
+ report << LOOPBACK_RESULT_TAG "latency.msec = " << std::setw(8)
+ << latencyMillis << "\n";
+ report << LOOPBACK_RESULT_TAG "latency.confidence = " << std::setw(8)
+ << mLatencyReport.confidence << "\n";
+ }
+ mState = STATE_DONE;
+ if (getResult() == RESULT_OK) {
+ setResult(newResult);
+ }
+
+ return report.str();
+ }
+
+ int32_t getMeasuredLatency() override {
+ return mLatencyReport.latencyInFrames;
+ }
+
+ double getMeasuredConfidence() override {
+ return mLatencyReport.confidence;
+ }
+
+ double getBackgroundRMS() override {
+ return mBackgroundRMS;
+ }
+
+ double getSignalRMS() override {
+ return mSignalRMS;
+ }
+
+ bool isRecordingComplete() {
+ return mState == STATE_GOT_DATA;
+ }
+
+ void printStatus() override {
+ ALOGD("latency: st = %d = %s", mState, convertStateToText(mState));
+ }
+
+ result_code processInputFrame(float *frameData, int channelCount) override {
+ echo_state nextState = mState;
+ mLoopCounter++;
+
+ switch (mState) {
+ case STATE_MEASURE_BACKGROUND:
+ // Measure background RMS on channel 0
+ mBackgroundSumSquare += frameData[0] * frameData[0];
+ mBackgroundSumCount++;
+ mDownCounter--;
+ if (mDownCounter <= 0) {
+ mBackgroundRMS = sqrtf(mBackgroundSumSquare / mBackgroundSumCount);
+ nextState = STATE_IN_PULSE;
+ mPulseCursor = 0;
+ }
+ break;
+
+ case STATE_IN_PULSE:
+ // Record input until the mAudioRecording is full.
+ mAudioRecording.write(frameData, channelCount, 1);
+ if (hasEnoughData()) {
+ nextState = STATE_GOT_DATA;
+ }
+ break;
+
+ case STATE_GOT_DATA:
+ case STATE_DONE:
+ default:
+ break;
+ }
+
+ mState = nextState;
+ return RESULT_OK;
+ }
+
+ result_code processOutputFrame(float *frameData, int channelCount) override {
+ switch (mState) {
+ case STATE_IN_PULSE:
+ if (mPulseCursor < mPulse.size()) {
+ float pulseSample = mPulse.getData()[mPulseCursor++];
+ for (int i = 0; i < channelCount; i++) {
+ frameData[i] = pulseSample;
+ }
+ } else {
+ for (int i = 0; i < channelCount; i++) {
+ frameData[i] = 0;
+ }
+ }
+ break;
+
+ case STATE_MEASURE_BACKGROUND:
+ case STATE_GOT_DATA:
+ case STATE_DONE:
+ default:
+ for (int i = 0; i < channelCount; i++) {
+ frameData[i] = 0.0f; // silence
+ }
+ break;
+ }
+
+ return RESULT_OK;
+ }
+
+private:
+
+ enum echo_state {
+ STATE_MEASURE_BACKGROUND,
+ STATE_IN_PULSE,
+ STATE_GOT_DATA, // must match RoundTripLatencyActivity.java
+ STATE_DONE,
+ };
+
+ const char *convertStateToText(echo_state state) {
+ switch (state) {
+ case STATE_MEASURE_BACKGROUND:
+ return "INIT";
+ case STATE_IN_PULSE:
+ return "PULSE";
+ case STATE_GOT_DATA:
+ return "GOT_DATA";
+ case STATE_DONE:
+ return "DONE";
+ }
+ return "UNKNOWN";
+ }
+
+ int32_t mDownCounter = 500;
+ int32_t mLoopCounter = 0;
+ echo_state mState = STATE_MEASURE_BACKGROUND;
+
+ static constexpr int32_t kFramesPerEncodedBit = 8; // multiple of 2
+ static constexpr int32_t kPulseLengthMillis = 500;
+
+ AudioRecording mPulse;
+ int32_t mPulseCursor = 0;
+
+ double mBackgroundSumSquare = 0.0;
+ int32_t mBackgroundSumCount = 0;
+ double mBackgroundRMS = 0.0;
+ double mSignalRMS = 0.0;
+ int32_t mFramesToRecord = 0;
+
+ AudioRecording mAudioRecording; // contains only the input after starting the pulse
+ LatencyReport mLatencyReport;
+};
+
+#endif // ANALYZER_LATENCY_ANALYZER_H
diff --git a/apps/CtsVerifier/jni/audio_loopback/analyzer/ManchesterEncoder.h b/apps/CtsVerifier/jni/audio_loopback/analyzer/ManchesterEncoder.h
new file mode 100644
index 0000000..3f7eebb
--- /dev/null
+++ b/apps/CtsVerifier/jni/audio_loopback/analyzer/ManchesterEncoder.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#ifndef ANALYZER_MANCHESTER_ENCODER_H
+#define ANALYZER_MANCHESTER_ENCODER_H
+
+#include <cstdint>
+
+/**
+ * Encode bytes using Manchester Coding scheme.
+ *
+ * Manchester Code is self clocking.
+ * There is a transition in the middle of every bit.
+ * Zero is high then low.
+ * One is low then high.
+ *
+ * This avoids having long DC sections that would droop when
+ * passed though analog circuits with AC coupling.
+ *
+ * IEEE 802.3 compatible.
+ */
+
+class ManchesterEncoder {
+public:
+ ManchesterEncoder(int samplesPerPulse)
+ : mSamplesPerPulse(samplesPerPulse)
+ , mSamplesPerPulseHalf(samplesPerPulse / 2)
+ , mCursor(samplesPerPulse) {
+ }
+
+ virtual ~ManchesterEncoder() = default;
+
+ /**
+ * This will be called when the next byte is needed.
+ * @return
+ */
+ virtual uint8_t onNextByte() = 0;
+
+ /**
+ * Generate the next floating point sample.
+ * @return
+ */
+ virtual float nextFloat() {
+ advanceSample();
+ if (mCurrentBit) {
+ return (mCursor < mSamplesPerPulseHalf) ? -1.0f : 1.0f; // one
+ } else {
+ return (mCursor < mSamplesPerPulseHalf) ? 1.0f : -1.0f; // zero
+ }
+ }
+
+protected:
+ /**
+ * This will be called when a new bit is ready to be encoded.
+ * It can be used to prepare the encoded samples.
+ * @param current
+ */
+ virtual void onNextBit(bool /* current */) {};
+
+ void advanceSample() {
+ // Are we ready for a new bit?
+ if (++mCursor >= mSamplesPerPulse) {
+ mCursor = 0;
+ if (mBitsLeft == 0) {
+ mCurrentByte = onNextByte();
+ mBitsLeft = 8;
+ }
+ --mBitsLeft;
+ mCurrentBit = (mCurrentByte >> mBitsLeft) & 1;
+ onNextBit(mCurrentBit);
+ }
+ }
+
+ bool getCurrentBit() {
+ return mCurrentBit;
+ }
+
+ const int mSamplesPerPulse;
+ const int mSamplesPerPulseHalf;
+ int mCursor;
+ int mBitsLeft = 0;
+ uint8_t mCurrentByte = 0;
+ bool mCurrentBit = false;
+};
+#endif //ANALYZER_MANCHESTER_ENCODER_H
diff --git a/apps/CtsVerifier/jni/audio_loopback/analyzer/PeakDetector.h b/apps/CtsVerifier/jni/audio_loopback/analyzer/PeakDetector.h
new file mode 100644
index 0000000..e407eac
--- /dev/null
+++ b/apps/CtsVerifier/jni/audio_loopback/analyzer/PeakDetector.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#ifndef ANALYZER_PEAK_DETECTOR_H
+#define ANALYZER_PEAK_DETECTOR_H
+
+#include <math.h>
+
+/**
+ * Measure a peak envelope by rising with the peaks,
+ * and decaying exponentially after each peak.
+ * The absolute value of the input signal is used.
+ */
+class PeakDetector {
+public:
+
+ void reset() {
+ mLevel = 0.0;
+ }
+
+ double process(double input) {
+ mLevel *= mDecay; // exponential decay
+ input = fabs(input);
+ // never fall below the input signal
+ if (input > mLevel) {
+ mLevel = input;
+ }
+ return mLevel;
+ }
+
+ double getLevel() const {
+ return mLevel;
+ }
+
+ double getDecay() const {
+ return mDecay;
+ }
+
+ /**
+ * Multiply the level by this amount on every iteration.
+ * This provides an exponential decay curve.
+ * A value just under 1.0 is best, for example, 0.99;
+ * @param decay scale level for each input
+ */
+ void setDecay(double decay) {
+ mDecay = decay;
+ }
+
+private:
+ static constexpr double kDefaultDecay = 0.99f;
+
+ double mLevel = 0.0;
+ double mDecay = kDefaultDecay;
+};
+#endif //ANALYZER_PEAK_DETECTOR_H
diff --git a/apps/CtsVerifier/jni/audio_loopback/analyzer/PseudoRandom.h b/apps/CtsVerifier/jni/audio_loopback/analyzer/PseudoRandom.h
new file mode 100644
index 0000000..d8f5894
--- /dev/null
+++ b/apps/CtsVerifier/jni/audio_loopback/analyzer/PseudoRandom.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+
+#ifndef ANALYZER_PSEUDORANDOM_H
+#define ANALYZER_PSEUDORANDOM_H
+
+#include <cctype>
+
+class PseudoRandom {
+public:
+ PseudoRandom(int64_t seed = 99887766)
+ : mSeed(seed)
+ {}
+
+ /**
+ * Returns the next random double from -1.0 to 1.0
+ *
+ * @return value from -1.0 to 1.0
+ */
+ double nextRandomDouble() {
+ return nextRandomInteger() * (0.5 / (((int32_t)1) << 30));
+ }
+
+ /** Calculate random 32 bit number using linear-congruential method
+ * with known real-time performance.
+ */
+ int32_t nextRandomInteger() {
+#if __has_builtin(__builtin_mul_overflow) && __has_builtin(__builtin_add_overflow)
+ int64_t prod;
+ // Use values for 64-bit sequence from MMIX by Donald Knuth.
+ __builtin_mul_overflow(mSeed, (int64_t)6364136223846793005, &prod);
+ __builtin_add_overflow(prod, (int64_t)1442695040888963407, &mSeed);
+#else
+ mSeed = (mSeed * (int64_t)6364136223846793005) + (int64_t)1442695040888963407;
+#endif
+ return (int32_t) (mSeed >> 32); // The higher bits have a longer sequence.
+ }
+
+private:
+ int64_t mSeed;
+};
+
+#endif //ANALYZER_PSEUDORANDOM_H
diff --git a/apps/CtsVerifier/jni/audio_loopback/analyzer/RandomPulseGenerator.h b/apps/CtsVerifier/jni/audio_loopback/analyzer/RandomPulseGenerator.h
new file mode 100644
index 0000000..b057d09
--- /dev/null
+++ b/apps/CtsVerifier/jni/audio_loopback/analyzer/RandomPulseGenerator.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#ifndef ANALYZER_RANDOM_PULSE_GENERATOR_H
+#define ANALYZER_RANDOM_PULSE_GENERATOR_H
+
+#include <stdlib.h>
+#include "RoundedManchesterEncoder.h"
+
+/**
+ * Encode random ones and zeros using Manchester Code per IEEE 802.3.
+ */
+class RandomPulseGenerator : public RoundedManchesterEncoder {
+public:
+ RandomPulseGenerator(int samplesPerPulse)
+ : RoundedManchesterEncoder(samplesPerPulse) {
+ }
+
+ virtual ~RandomPulseGenerator() = default;
+
+ /**
+ * This will be called when the next byte is needed.
+ * @return random byte
+ */
+ uint8_t onNextByte() override {
+ return static_cast<uint8_t>(rand());
+ }
+};
+
+#endif //ANALYZER_RANDOM_PULSE_GENERATOR_H
diff --git a/apps/CtsVerifier/jni/audio_loopback/analyzer/RoundedManchesterEncoder.h b/apps/CtsVerifier/jni/audio_loopback/analyzer/RoundedManchesterEncoder.h
new file mode 100644
index 0000000..76f57e7
--- /dev/null
+++ b/apps/CtsVerifier/jni/audio_loopback/analyzer/RoundedManchesterEncoder.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#ifndef ANALYZER_ROUNDED_MANCHESTER_ENCODER_H
+#define ANALYZER_ROUNDED_MANCHESTER_ENCODER_H
+
+#include <math.h>
+#include <memory.h>
+#include <stdlib.h>
+#include "ManchesterEncoder.h"
+
+/**
+ * Encode bytes using Manchester Code.
+ * Round the edges using a half cosine to reduce ringing caused by a hard edge.
+ */
+
+class RoundedManchesterEncoder : public ManchesterEncoder {
+public:
+ RoundedManchesterEncoder(int samplesPerPulse)
+ : ManchesterEncoder(samplesPerPulse) {
+ int rampSize = samplesPerPulse / 4;
+ mZeroAfterZero = std::make_unique<float[]>(samplesPerPulse);
+ mZeroAfterOne = std::make_unique<float[]>(samplesPerPulse);
+
+ int sampleIndex = 0;
+ for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
+ float phase = (rampIndex + 1) * M_PI / rampSize;
+ float sample = -cosf(phase);
+ mZeroAfterZero[sampleIndex] = sample;
+ mZeroAfterOne[sampleIndex] = 1.0f;
+ sampleIndex++;
+ }
+ for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
+ mZeroAfterZero[sampleIndex] = 1.0f;
+ mZeroAfterOne[sampleIndex] = 1.0f;
+ sampleIndex++;
+ }
+ for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
+ float phase = (rampIndex + 1) * M_PI / rampSize;
+ float sample = cosf(phase);
+ mZeroAfterZero[sampleIndex] = sample;
+ mZeroAfterOne[sampleIndex] = sample;
+ sampleIndex++;
+ }
+ for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
+ mZeroAfterZero[sampleIndex] = -1.0f;
+ mZeroAfterOne[sampleIndex] = -1.0f;
+ sampleIndex++;
+ }
+ }
+
+ void onNextBit(bool current) override {
+ // Do we need to use the rounded edge?
+ mCurrentSamples = (current ^ mPreviousBit)
+ ? mZeroAfterOne.get()
+ : mZeroAfterZero.get();
+ mPreviousBit = current;
+ }
+
+ float nextFloat() override {
+ advanceSample();
+ float output = mCurrentSamples[mCursor];
+ if (getCurrentBit()) output = -output;
+ return output;
+ }
+
+private:
+
+ bool mPreviousBit = false;
+ float *mCurrentSamples = nullptr;
+ std::unique_ptr<float[]> mZeroAfterZero;
+ std::unique_ptr<float[]> mZeroAfterOne;
+};
+
+#endif //ANALYZER_ROUNDED_MANCHESTER_ENCODER_H
diff --git a/apps/CtsVerifier/jni/audio_loopback/audio_utils/atomic.c b/apps/CtsVerifier/jni/audio_loopback/audio_utils/atomic.c
deleted file mode 100644
index db2b3fc..0000000
--- a/apps/CtsVerifier/jni/audio_loopback/audio_utils/atomic.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "atomic.h"
-
-#include <stdatomic.h>
-
-int32_t android_atomic_acquire_load(volatile const int32_t* addr)
-{
- volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr;
- return atomic_load_explicit(a, memory_order_acquire);
-}
-
-void android_atomic_release_store(int32_t value, volatile int32_t* addr)
-{
- volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*)addr;
- atomic_store_explicit(a, value, memory_order_release);
-}
diff --git a/apps/CtsVerifier/jni/audio_loopback/audio_utils/atomic.h b/apps/CtsVerifier/jni/audio_loopback/audio_utils/atomic.h
deleted file mode 100644
index 535c926..0000000
--- a/apps/CtsVerifier/jni/audio_loopback/audio_utils/atomic.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_AUDIO_ATOMIC_H
-#define ANDROID_AUDIO_ATOMIC_H
-
-#include <stdlib.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int32_t android_atomic_acquire_load(volatile const int32_t* addr);
-void android_atomic_release_store(int32_t value, volatile int32_t* addr);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // ANDROID_AUDIO_ATOMIC_H
diff --git a/apps/CtsVerifier/jni/audio_loopback/audio_utils/fifo.c b/apps/CtsVerifier/jni/audio_loopback/audio_utils/fifo.c
deleted file mode 100644
index ea9a8d1..0000000
--- a/apps/CtsVerifier/jni/audio_loopback/audio_utils/fifo.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "audio_utils_fifo"
-
-#include <stdlib.h>
-#include <string.h>
-#include "fifo.h"
-#include "roundup.h"
-#include "atomic.h"
-//#include <cutils/log.h>
-#define ALOG_ASSERT(exp)
-
-void audio_utils_fifo_init(struct audio_utils_fifo *fifo, size_t frameCount, size_t frameSize,
- void *buffer)
-{
- // We would need a 64-bit roundup to support larger frameCount.
- ALOG_ASSERT(fifo != NULL && frameCount > 0 && frameSize > 0 && buffer != NULL);
- fifo->mFrameCount = frameCount;
- fifo->mFrameCountP2 = roundup(frameCount);
- fifo->mFudgeFactor = fifo->mFrameCountP2 - fifo->mFrameCount;
- fifo->mFrameSize = frameSize;
- fifo->mBuffer = buffer;
- fifo->mFront = 0;
- fifo->mRear = 0;
-}
-
-void audio_utils_fifo_deinit(struct audio_utils_fifo *fifo __unused)
-{
-}
-
-// Return a new index as the sum of an old index (either mFront or mRear) and a specified increment.
-static inline int32_t audio_utils_fifo_sum(struct audio_utils_fifo *fifo, int32_t index,
- uint32_t increment)
-{
- if (fifo->mFudgeFactor) {
- uint32_t mask = fifo->mFrameCountP2 - 1;
- ALOG_ASSERT((index & mask) < fifo->mFrameCount);
- ALOG_ASSERT(/*0 <= increment &&*/ increment <= fifo->mFrameCountP2);
- if ((index & mask) + increment >= fifo->mFrameCount) {
- increment += fifo->mFudgeFactor;
- }
- index += increment;
- ALOG_ASSERT((index & mask) < fifo->mFrameCount);
- return index;
- } else {
- return index + increment;
- }
-}
-
-// Return the difference between two indices: rear - front, where 0 <= difference <= mFrameCount.
-static inline size_t audio_utils_fifo_diff(struct audio_utils_fifo *fifo, int32_t rear,
- int32_t front)
-{
- int32_t diff = rear - front;
- if (fifo->mFudgeFactor) {
- uint32_t mask = ~(fifo->mFrameCountP2 - 1);
- int32_t genDiff = (rear & mask) - (front & mask);
- if (genDiff != 0) {
- ALOG_ASSERT(genDiff == (int32_t) fifo->mFrameCountP2);
- diff -= fifo->mFudgeFactor;
- }
- }
- // FIFO should not be overfull
- ALOG_ASSERT(0 <= diff && diff <= (int32_t) fifo->mFrameCount);
- return (size_t) diff;
-}
-
-ssize_t audio_utils_fifo_write(struct audio_utils_fifo *fifo, const void *buffer, size_t count)
-{
- int32_t front = android_atomic_acquire_load(&fifo->mFront);
- int32_t rear = fifo->mRear;
- size_t availToWrite = fifo->mFrameCount - audio_utils_fifo_diff(fifo, rear, front);
- if (availToWrite > count) {
- availToWrite = count;
- }
- rear &= fifo->mFrameCountP2 - 1;
- size_t part1 = fifo->mFrameCount - rear;
- if (part1 > availToWrite) {
- part1 = availToWrite;
- }
- if (part1 > 0) {
- memcpy((char *) fifo->mBuffer + (rear * fifo->mFrameSize), buffer,
- part1 * fifo->mFrameSize);
- size_t part2 = availToWrite - part1;
- if (part2 > 0) {
- memcpy(fifo->mBuffer, (char *) buffer + (part1 * fifo->mFrameSize),
- part2 * fifo->mFrameSize);
- }
- android_atomic_release_store(audio_utils_fifo_sum(fifo, fifo->mRear, availToWrite),
- &fifo->mRear);
- }
- return availToWrite;
-}
-
-ssize_t audio_utils_fifo_read(struct audio_utils_fifo *fifo, void *buffer, size_t count)
-{
- int32_t rear = android_atomic_acquire_load(&fifo->mRear);
- int32_t front = fifo->mFront;
- size_t availToRead = audio_utils_fifo_diff(fifo, rear, front);
- if (availToRead > count) {
- availToRead = count;
- }
- front &= fifo->mFrameCountP2 - 1;
- size_t part1 = fifo->mFrameCount - front;
- if (part1 > availToRead) {
- part1 = availToRead;
- }
- if (part1 > 0) {
- memcpy(buffer, (char *) fifo->mBuffer + (front * fifo->mFrameSize),
- part1 * fifo->mFrameSize);
- size_t part2 = availToRead - part1;
- if (part2 > 0) {
- memcpy((char *) buffer + (part1 * fifo->mFrameSize), fifo->mBuffer,
- part2 * fifo->mFrameSize);
- }
- android_atomic_release_store(audio_utils_fifo_sum(fifo, fifo->mFront, availToRead),
- &fifo->mFront);
- }
- return availToRead;
-}
diff --git a/apps/CtsVerifier/jni/audio_loopback/audio_utils/fifo.h b/apps/CtsVerifier/jni/audio_loopback/audio_utils/fifo.h
deleted file mode 100644
index ba4c5c6..0000000
--- a/apps/CtsVerifier/jni/audio_loopback/audio_utils/fifo.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_AUDIO_FIFO_H
-#define ANDROID_AUDIO_FIFO_H
-
-#include <stdlib.h>
-
-// FIXME use atomic_int_least32_t and new atomic operations instead of legacy Android ones
-// #include <stdatomic.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Single writer, single reader non-blocking FIFO.
-// Writer and reader must be in same process.
-
-// No user-serviceable parts within.
-struct audio_utils_fifo {
- // These fields are const after initialization
- size_t mFrameCount; // max number of significant frames to be stored in the FIFO > 0
- size_t mFrameCountP2; // roundup(mFrameCount)
- size_t mFudgeFactor; // mFrameCountP2 - mFrameCount, the number of "wasted" frames after
- // the end of mBuffer. Only the indices are wasted, not any memory.
- size_t mFrameSize; // size of each frame in bytes
- void *mBuffer; // pointer to caller-allocated buffer of size mFrameCount frames
-
- volatile int32_t mFront; // frame index of first frame slot available to read, or read index
- volatile int32_t mRear; // frame index of next frame slot available to write, or write index
-};
-
-// Initialize a FIFO object.
-// Input parameters:
-// fifo Pointer to the FIFO object.
-// frameCount Max number of significant frames to be stored in the FIFO > 0.
-// If writes and reads always use the same count, and that count is a divisor of
-// frameCount, then the writes and reads will never do a partial transfer.
-// frameSize Size of each frame in bytes.
-// buffer Pointer to a caller-allocated buffer of frameCount frames.
-void audio_utils_fifo_init(struct audio_utils_fifo *fifo, size_t frameCount, size_t frameSize,
- void *buffer);
-
-// De-initialize a FIFO object.
-// Input parameters:
-// fifo Pointer to the FIFO object.
-void audio_utils_fifo_deinit(struct audio_utils_fifo *fifo);
-
-// Write to FIFO.
-// Input parameters:
-// fifo Pointer to the FIFO object.
-// buffer Pointer to source buffer containing 'count' frames of data.
-// Returns actual number of frames written <= count.
-// The actual transfer count may be zero if the FIFO is full,
-// or partial if the FIFO was almost full.
-// A negative return value indicates an error. Currently there are no errors defined.
-ssize_t audio_utils_fifo_write(struct audio_utils_fifo *fifo, const void *buffer, size_t count);
-
-// Read from FIFO.
-// Input parameters:
-// fifo Pointer to the FIFO object.
-// buffer Pointer to destination buffer to be filled with up to 'count' frames of data.
-// Returns actual number of frames read <= count.
-// The actual transfer count may be zero if the FIFO is empty,
-// or partial if the FIFO was almost empty.
-// A negative return value indicates an error. Currently there are no errors defined.
-ssize_t audio_utils_fifo_read(struct audio_utils_fifo *fifo, void *buffer, size_t count);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // !ANDROID_AUDIO_FIFO_H
diff --git a/apps/CtsVerifier/jni/audio_loopback/audio_utils/roundup.c b/apps/CtsVerifier/jni/audio_loopback/audio_utils/roundup.c
deleted file mode 100644
index 4f9af6a..0000000
--- a/apps/CtsVerifier/jni/audio_loopback/audio_utils/roundup.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "roundup.h"
-
-unsigned roundup(unsigned v)
-{
- // __builtin_clz is undefined for zero input
- if (v == 0) {
- v = 1;
- }
- int lz = __builtin_clz((int) v);
- unsigned rounded = ((unsigned) 0x80000000) >> lz;
- // 0x800000001 and higher are actually rounded _down_ to prevent overflow
- if (v > rounded && lz > 0) {
- rounded <<= 1;
- }
- return rounded;
-}
diff --git a/apps/CtsVerifier/jni/audio_loopback/jni-bridge.cpp b/apps/CtsVerifier/jni/audio_loopback/jni-bridge.cpp
new file mode 100644
index 0000000..a851cbe
--- /dev/null
+++ b/apps/CtsVerifier/jni/audio_loopback/jni-bridge.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2020 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 <cassert>
+#include <cstring>
+#include <jni.h>
+#include <stdint.h>
+
+#include "NativeAudioAnalyzer.h"
+
+extern "C" {
+
+JNIEXPORT jlong JNICALL Java_com_android_cts_verifier_audio_NativeAnalyzerThread_openAudio
+ (JNIEnv * /*env */, jobject /* obj */,
+ jint /* micSource */) {
+ // It is OK to use a raw pointer here because the pointer will be passed back
+ // to Java and only used from one thread.
+ // Java then deletes it from that same thread by calling _closeAudio() below.
+ NativeAudioAnalyzer * analyzer = new NativeAudioAnalyzer();
+ aaudio_result_t result = analyzer->openAudio();
+ if (result != AAUDIO_OK) {
+ delete analyzer;
+ analyzer = nullptr;
+ }
+ return (jlong) analyzer;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_cts_verifier_audio_NativeAnalyzerThread_startAudio
+ (JNIEnv *env __unused, jobject obj __unused, jlong pAnalyzer) {
+ NativeAudioAnalyzer * analyzer = (NativeAudioAnalyzer *) pAnalyzer;
+ int result = AAUDIO_ERROR_NULL;
+ if (analyzer != nullptr) {
+ result = analyzer->startAudio();
+ }
+ return result;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_cts_verifier_audio_NativeAnalyzerThread_stopAudio
+ (JNIEnv *env __unused, jobject obj __unused, jlong pAnalyzer) {
+ NativeAudioAnalyzer * analyzer = (NativeAudioAnalyzer *) pAnalyzer;
+ if (analyzer != nullptr) {
+ return analyzer->stopAudio();
+ }
+ return AAUDIO_ERROR_NULL;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_cts_verifier_audio_NativeAnalyzerThread_closeAudio
+ (JNIEnv *env __unused, jobject obj __unused, jlong pAnalyzer) {
+ NativeAudioAnalyzer * analyzer = (NativeAudioAnalyzer *) pAnalyzer;
+ int result = AAUDIO_ERROR_NULL;
+ if (analyzer != nullptr) {
+ result = analyzer->closeAudio();
+ delete analyzer;
+ }
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_com_android_cts_verifier_audio_NativeAnalyzerThread_isRecordingComplete
+ (JNIEnv *env __unused, jobject obj __unused, jlong pAnalyzer) {
+ NativeAudioAnalyzer * analyzer = (NativeAudioAnalyzer *) pAnalyzer;
+ if (analyzer != nullptr) {
+ return analyzer->isRecordingComplete();
+ }
+ return false;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_cts_verifier_audio_NativeAnalyzerThread_getError
+ (JNIEnv *env __unused, jobject obj __unused, jlong pAnalyzer) {
+ NativeAudioAnalyzer * analyzer = (NativeAudioAnalyzer *) pAnalyzer;
+ if (analyzer != nullptr) {
+ return (jint) analyzer->getError();
+ }
+ return (jint) AAUDIO_ERROR_NULL;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_cts_verifier_audio_NativeAnalyzerThread_analyze
+ (JNIEnv *env __unused, jobject obj __unused, jlong pAnalyzer) {
+ NativeAudioAnalyzer * analyzer = (NativeAudioAnalyzer *) pAnalyzer;
+ if (analyzer != nullptr) {
+ return analyzer->analyze();
+ }
+ return AAUDIO_ERROR_NULL;
+}
+
+JNIEXPORT jdouble JNICALL Java_com_android_cts_verifier_audio_NativeAnalyzerThread_getLatencyMillis
+ (JNIEnv *env __unused, jobject obj __unused, jlong pAnalyzer) {
+ NativeAudioAnalyzer * analyzer = (NativeAudioAnalyzer *) pAnalyzer;
+ if (analyzer != nullptr) {
+ return analyzer->getLatencyMillis();
+ }
+ return -1.0;
+}
+
+JNIEXPORT jdouble JNICALL Java_com_android_cts_verifier_audio_NativeAnalyzerThread_getConfidence
+ (JNIEnv *env __unused, jobject obj __unused, jlong pAnalyzer) {
+ NativeAudioAnalyzer * analyzer = (NativeAudioAnalyzer *) pAnalyzer;
+ if (analyzer != nullptr) {
+ return analyzer->getConfidence();
+ }
+ return 0.0;
+}
+
+}
diff --git a/apps/CtsVerifier/jni/audio_loopback/jni_sles.c b/apps/CtsVerifier/jni/audio_loopback/jni_sles.c
deleted file mode 100644
index e8a837e..0000000
--- a/apps/CtsVerifier/jni/audio_loopback/jni_sles.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android/log.h>
-#include "sles.h"
-#include "jni_sles.h"
-#include <stdio.h>
-#include <stddef.h>
-
-/////
-JNIEXPORT jlong JNICALL Java_com_android_cts_verifier_audio_NativeAudioThread_slesInit
- (JNIEnv *env __unused, jobject obj __unused, jint samplingRate, jint frameCount,
- jint micSource, jint numFramesToIgnore) {
-
- sles_data * pSles = NULL;
-
- if (slesInit(&pSles, samplingRate, frameCount, micSource, numFramesToIgnore) != SLES_FAIL) {
-
- return (long)pSles;
- }
- // FIXME This should be stored as a (long) field in the object,
- // so that incorrect Java code could not synthesize a bad sles pointer.
- return 0;
-}
-
-JNIEXPORT jint JNICALL Java_com_android_cts_verifier_audio_NativeAudioThread_slesProcessNext
- (JNIEnv *env __unused, jobject obj __unused, jlong sles, jdoubleArray samplesArray,
- jlong offset) {
- sles_data * pSles= (sles_data*) ((long)sles);
-
- long maxSamples = (*env)->GetArrayLength(env, samplesArray);
- double *pSamples = (*env)->GetDoubleArrayElements(env, samplesArray,0);
-
- long availableSamples = maxSamples-offset;
- double *pCurrentSample = pSamples+offset;
-
- SLES_PRINTF("jni slesProcessNext pSles:%p, currentSample %p, availableSamples %ld ", pSles,
- pCurrentSample, availableSamples);
-
- int samplesRead = slesProcessNext(pSles, pCurrentSample, availableSamples);
-
- return samplesRead;
-}
-
-JNIEXPORT jint JNICALL Java_com_android_cts_verifier_audio_NativeAudioThread_slesDestroy
- (JNIEnv *env __unused, jobject obj __unused, jlong sles) {
- sles_data * pSles= (sles_data*) ((long) sles);
-
- int status = slesDestroy(&pSles);
-
- return status;
-}
diff --git a/apps/CtsVerifier/jni/audio_loopback/jni_sles.h b/apps/CtsVerifier/jni/audio_loopback/jni_sles.h
deleted file mode 100644
index d7aa625..0000000
--- a/apps/CtsVerifier/jni/audio_loopback/jni_sles.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <jni.h>
-
-#ifndef _Included_org_drrickorang_loopback_jni
-#define _Included_org_drrickorang_loopback_jni
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-////////////////////////
-JNIEXPORT jlong JNICALL Java_com_android_cts_verifier_audio_NativeAudioThread_slesInit
- (JNIEnv *, jobject, jint, jint, jint, jint );
-
-JNIEXPORT jint JNICALL Java_com_android_cts_verifier_audio_NativeAudioThread_slesProcessNext
- (JNIEnv *, jobject , jlong, jdoubleArray, jlong );
-
-JNIEXPORT jint JNICALL Java_com_android_cts_verifier_audio_NativeAudioThread_slesDestroy
- (JNIEnv *, jobject , jlong );
-
-
-#ifdef __cplusplus
-}
-#endif
-#endif //_Included_org_drrickorang_loopback_jni
diff --git a/apps/CtsVerifier/jni/audio_loopback/sles.cpp b/apps/CtsVerifier/jni/audio_loopback/sles.cpp
deleted file mode 100644
index 586c60f..0000000
--- a/apps/CtsVerifier/jni/audio_loopback/sles.cpp
+++ /dev/null
@@ -1,673 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-////////////////////////////////////////////
-/// Actual sles functions.
-
-
-// Test program to record from default audio input and playback to default audio output.
-// It will generate feedback (Larsen effect) if played through on-device speakers,
-// or acts as a delay if played through headset.
-
-#include "sles.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-
-#include <assert.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-int slesInit(sles_data ** ppSles, int samplingRate, int frameCount, int micSource,
- int numFramesToIgnore) {
- int status = SLES_FAIL;
- if (ppSles != NULL) {
- sles_data * pSles = (sles_data*) calloc(1, sizeof (sles_data));
-
- SLES_PRINTF("malloc %zu bytes at %p", sizeof(sles_data), pSles);
- *ppSles = pSles;
- if (pSles != NULL)
- {
- SLES_PRINTF("creating server. Sampling rate =%d, frame count = %d",samplingRate,
- frameCount);
- status = slesCreateServer(pSles, samplingRate, frameCount, micSource,
- numFramesToIgnore);
- SLES_PRINTF("slesCreateServer =%d", status);
- }
- }
- return status;
-}
-int slesDestroy(sles_data ** ppSles) {
- int status = SLES_FAIL;
- if (ppSles != NULL) {
- slesDestroyServer(*ppSles);
-
- if (*ppSles != NULL)
- {
- free(*ppSles);
- *ppSles = 0;
- }
- status = SLES_SUCCESS;
- }
- return status;
-}
-
-#define ASSERT_EQ(x, y) do { if ((x) == (y)) ; else { fprintf(stderr, "0x%x != 0x%x\n", \
- (unsigned) (x), (unsigned) (y)); assert((x) == (y)); } } while (0)
-
-
-// Called after audio recorder fills a buffer with data
-static void recorderCallback(SLAndroidSimpleBufferQueueItf caller __unused, void *context) {
- sles_data *pSles = (sles_data*) context;
- if (pSles != NULL) {
-
-
-
- SLresult result;
-
- pthread_mutex_lock(&(pSles->mutex));
- //ee SLES_PRINTF("<R");
-
- // We should only be called when a recording buffer is done
- assert(pSles->rxFront <= pSles->rxBufCount);
- assert(pSles->rxRear <= pSles->rxBufCount);
- assert(pSles->rxFront != pSles->rxRear);
- char *buffer = pSles->rxBuffers[pSles->rxFront];
-
- // Remove buffer from record queue
- if (++pSles->rxFront > pSles->rxBufCount) {
- pSles->rxFront = 0;
- }
-
- // Throw out first frames
- if (pSles->numFramesToIgnore) {
- SLuint32 framesToErase = pSles->numFramesToIgnore;
- if (framesToErase > pSles->bufSizeInFrames) {
- framesToErase = pSles->bufSizeInFrames;
- }
- pSles->numFramesToIgnore -= framesToErase;
- // FIXME: this assumes each sample is a short
- memset(buffer, 0, framesToErase * pSles->channels * sizeof(short));
- }
-
- ssize_t actual = audio_utils_fifo_write(&(pSles->fifo), buffer,
- (size_t) pSles->bufSizeInFrames);
- if (actual != (ssize_t) pSles->bufSizeInFrames) {
- write(1, "?", 1);
- }
-
- // This is called by a realtime (SCHED_FIFO) thread,
- // and it is unsafe to do I/O as it could block for unbounded time.
- // Flash filesystem is especially notorious for blocking.
- if (pSles->fifo2Buffer != NULL) {
- actual = audio_utils_fifo_write(&(pSles->fifo2), buffer,
- (size_t) pSles->bufSizeInFrames);
- if (actual != (ssize_t) pSles->bufSizeInFrames) {
- write(1, "?", 1);
- }
- }
-
- // Enqueue this same buffer for the recorder to fill again.
- result = (*(pSles->recorderBufferQueue))->Enqueue(pSles->recorderBufferQueue, buffer,
- pSles->bufSizeInBytes);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- // Update our model of the record queue
- SLuint32 rxRearNext = pSles->rxRear+1;
- if (rxRearNext > pSles->rxBufCount) {
- rxRearNext = 0;
- }
- assert(rxRearNext != pSles->rxFront);
- pSles->rxBuffers[pSles->rxRear] = buffer;
- pSles->rxRear = rxRearNext;
-
-
-
- //ee SLES_PRINTF("r>");
- pthread_mutex_unlock(&(pSles->mutex));
-
- } //pSles not null
-}
-
-
-// Called after audio player empties a buffer of data
-static void playerCallback(SLBufferQueueItf caller __unused, void *context) {
- sles_data *pSles = (sles_data*) context;
- if (pSles != NULL) {
-
- SLresult result;
-
- pthread_mutex_lock(&(pSles->mutex));
- //ee SLES_PRINTF("<P");
-
- // Get the buffer that just finished playing
- assert(pSles->txFront <= pSles->txBufCount);
- assert(pSles->txRear <= pSles->txBufCount);
- assert(pSles->txFront != pSles->txRear);
- char *buffer = pSles->txBuffers[pSles->txFront];
- if (++pSles->txFront > pSles->txBufCount) {
- pSles->txFront = 0;
- }
-
-
- ssize_t actual = audio_utils_fifo_read(&(pSles->fifo), buffer, pSles->bufSizeInFrames);
- if (actual != (ssize_t) pSles->bufSizeInFrames) {
- write(1, "/", 1);
- // on underrun from pipe, substitute silence
- memset(buffer, 0, pSles->bufSizeInFrames * pSles->channels * sizeof(short));
- }
-
- if (pSles->injectImpulse == -1) {
- // Experimentally, a single frame impulse was insufficient to trigger feedback.
- // Also a Nyquist frequency signal was also insufficient, probably because
- // the response of output and/or input path was not adequate at high frequencies.
- // This short burst of a few cycles of square wave at Nyquist/4 was found to work well.
- for (unsigned i = 0; i < pSles->bufSizeInFrames / 8; i += 8) {
- for (int j = 0; j < 8; j++) {
- for (unsigned k = 0; k < pSles->channels; k++) {
- ((short *)buffer)[(i+j)*pSles->channels+k] = j < 4 ? 0x7FFF : 0x8000;
- }
- }
- }
- pSles->injectImpulse = 0;
- }
-
- // Enqueue the filled buffer for playing
- result = (*(pSles->playerBufferQueue))->Enqueue(pSles->playerBufferQueue, buffer,
- pSles->bufSizeInBytes);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- // Update our model of the player queue
- assert(pSles->txFront <= pSles->txBufCount);
- assert(pSles->txRear <= pSles->txBufCount);
- SLuint32 txRearNext = pSles->txRear+1;
- if (txRearNext > pSles->txBufCount) {
- txRearNext = 0;
- }
- assert(txRearNext != pSles->txFront);
- pSles->txBuffers[pSles->txRear] = buffer;
- pSles->txRear = txRearNext;
-
-
- //ee SLES_PRINTF("p>");
- pthread_mutex_unlock(&(pSles->mutex));
-
- } //pSles not null
-}
-
-int slesCreateServer(sles_data *pSles, int samplingRate, int frameCount,
- int micSource, int numFramesToIgnore) {
- int status = SLES_FAIL;
-
- if (pSles == NULL) {
- return status;
- }
-
- // adb shell slesTest_feedback -r1 -t1 -s48000 -f240 -i300 -e3 -o/sdcard/log.wav
- // r1 and t1 are the receive and transmit buffer counts, typically 1
- // s is the sample rate, typically 48000 or 44100
- // f is the frame count per buffer, typically 240 or 256
- // i is the number of milliseconds before impulse. You may need to adjust this.
- // e is number of seconds to record
- // o is output .wav file name
-
-
- // // default values
- // SLuint32 rxBufCount = 1; // -r#
- // SLuint32 txBufCount = 1; // -t#
- // SLuint32 bufSizeInFrames = 240; // -f#
- // SLuint32 channels = 1; // -c#
- // SLuint32 sampleRate = 48000; // -s#
- // SLuint32 exitAfterSeconds = 3; // -e#
- // SLuint32 freeBufCount = 0; // calculated
- // SLuint32 bufSizeInBytes = 0; // calculated
- // int injectImpulse = 300; // -i#i
- //
- // // Storage area for the buffer queues
- // char **rxBuffers;
- // char **txBuffers;
- // char **freeBuffers;
- //
- // // Buffer indices
- // SLuint32 rxFront; // oldest recording
- // SLuint32 rxRear; // next to be recorded
- // SLuint32 txFront; // oldest playing
- // SLuint32 txRear; // next to be played
- // SLuint32 freeFront; // oldest free
- // SLuint32 freeRear; // next to be freed
- //
- // audio_utils_fifo fifo; //(*)
- // SLAndroidSimpleBufferQueueItf recorderBufferQueue;
- // SLBufferQueueItf playerBufferQueue;
-
- // default values
- pSles->rxBufCount = 1; // -r#
- pSles->txBufCount = 1; // -t#
- pSles->bufSizeInFrames = frameCount;//240; // -f#
- pSles->channels = 1; // -c#
- pSles->sampleRate = samplingRate;//48000; // -s#
- pSles->exitAfterSeconds = 3; // -e#
- pSles->freeBufCount = 0; // calculated
- pSles->bufSizeInBytes = 0; // calculated
- pSles->injectImpulse = 300; // -i#i
-
- if (numFramesToIgnore > 0) {
- pSles->numFramesToIgnore = numFramesToIgnore;
- } else {
- pSles->numFramesToIgnore = 0;
- }
-
- // Storage area for the buffer queues
- // char **rxBuffers;
- // char **txBuffers;
- // char **freeBuffers;
-
- // Buffer indices
-/*
- pSles->rxFront; // oldest recording
- pSles->rxRear; // next to be recorded
- pSles->txFront; // oldest playing
- pSles->txRear; // next to be played
- pSles->freeFront; // oldest free
- pSles->freeRear; // next to be freed
-
- pSles->fifo; //(*)
-*/
- pSles->fifo2Buffer = NULL;
-
- // compute total free buffers as -r plus -t
- pSles->freeBufCount = pSles->rxBufCount + pSles->txBufCount;
- // compute buffer size
- pSles->bufSizeInBytes = pSles->channels * pSles->bufSizeInFrames * sizeof(short);
-
- // Initialize free buffers
- pSles->freeBuffers = (char **) calloc(pSles->freeBufCount+1, sizeof(char *));
- unsigned j;
- for (j = 0; j < pSles->freeBufCount; ++j) {
- pSles->freeBuffers[j] = (char *) malloc(pSles->bufSizeInBytes);
- }
- pSles->freeFront = 0;
- pSles->freeRear = pSles->freeBufCount;
- pSles->freeBuffers[j] = NULL;
-
- // Initialize record queue
- pSles->rxBuffers = (char **) calloc(pSles->rxBufCount+1, sizeof(char *));
- pSles->rxFront = 0;
- pSles->rxRear = 0;
-
- // Initialize play queue
- pSles->txBuffers = (char **) calloc(pSles->txBufCount+1, sizeof(char *));
- pSles->txFront = 0;
- pSles->txRear = 0;
-
- size_t frameSize = pSles->channels * sizeof(short);
-#define FIFO_FRAMES 1024
- pSles->fifoBuffer = new short[FIFO_FRAMES * pSles->channels];
- audio_utils_fifo_init(&(pSles->fifo), FIFO_FRAMES, frameSize, pSles->fifoBuffer);
-
- // SNDFILE *sndfile;
- // if (outFileName != NULL) {
- // create .wav writer
- // SF_INFO info;
- // info.frames = 0;
- // info.samplerate = sampleRate;
- // info.channels = channels;
- // info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
- // sndfile = sf_open(outFileName, SFM_WRITE, &info);
- // if (sndfile != NULL) {
-#define FIFO2_FRAMES 65536
- pSles->fifo2Buffer = new short[FIFO2_FRAMES * pSles->channels];
- audio_utils_fifo_init(&(pSles->fifo2), FIFO2_FRAMES, frameSize, pSles->fifo2Buffer);
- // } else {
- // fprintf(stderr, "sf_open failed\n");
- // }
- // } else {
- // sndfile = NULL;
- // }
-
- SLresult result;
-
- // create engine
- result = slCreateEngine(&(pSles->engineObject), 0, NULL, 0, NULL, NULL);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- result = (*(pSles->engineObject))->Realize(pSles->engineObject, SL_BOOLEAN_FALSE);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- SLEngineItf engineEngine;
- result = (*(pSles->engineObject))->GetInterface(pSles->engineObject, SL_IID_ENGINE,
- &engineEngine);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- // create output mix
- result = (*engineEngine)->CreateOutputMix(engineEngine, &(pSles->outputmixObject), 0, NULL,
- NULL);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- result = (*(pSles->outputmixObject))->Realize(pSles->outputmixObject, SL_BOOLEAN_FALSE);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- // create an audio player with buffer queue source and output mix sink
- SLDataSource audiosrc;
- SLDataSink audiosnk;
- SLDataFormat_PCM pcm;
- SLDataLocator_OutputMix locator_outputmix;
- SLDataLocator_BufferQueue locator_bufferqueue_tx;
- locator_bufferqueue_tx.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
- locator_bufferqueue_tx.numBuffers = pSles->txBufCount;
- locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
- locator_outputmix.outputMix = pSles->outputmixObject;
- pcm.formatType = SL_DATAFORMAT_PCM;
- pcm.numChannels = pSles->channels;
- pcm.samplesPerSec = pSles->sampleRate * 1000;
- pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
- pcm.containerSize = 16;
- pcm.channelMask = pSles->channels == 1 ? SL_SPEAKER_FRONT_CENTER :
- (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
- pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
- audiosrc.pLocator = &locator_bufferqueue_tx;
- audiosrc.pFormat = &pcm;
- audiosnk.pLocator = &locator_outputmix;
- audiosnk.pFormat = NULL;
- pSles->playerObject = NULL;
- pSles->recorderObject = NULL;
- SLInterfaceID ids_tx[1] = {SL_IID_BUFFERQUEUE};
- SLboolean flags_tx[1] = {SL_BOOLEAN_TRUE};
- result = (*engineEngine)->CreateAudioPlayer(engineEngine, &(pSles->playerObject),
- &audiosrc, &audiosnk, 1, ids_tx, flags_tx);
- if (SL_RESULT_CONTENT_UNSUPPORTED == result) {
- fprintf(stderr, "Could not create audio player (result %x), check sample rate\n",
- result);
- SLES_PRINTF("ERROR: Could not create audio player (result %x), check sample rate\n",
- result);
- goto cleanup;
- }
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- result = (*(pSles->playerObject))->Realize(pSles->playerObject, SL_BOOLEAN_FALSE);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- SLPlayItf playerPlay;
- result = (*(pSles->playerObject))->GetInterface(pSles->playerObject, SL_IID_PLAY,
- &playerPlay);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- result = (*(pSles->playerObject))->GetInterface(pSles->playerObject, SL_IID_BUFFERQUEUE,
- &(pSles->playerBufferQueue));
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- result = (*(pSles->playerBufferQueue))->RegisterCallback(pSles->playerBufferQueue,
- playerCallback, pSles);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- // Enqueue some zero buffers for the player
- for (j = 0; j < pSles->txBufCount; ++j) {
-
- // allocate a free buffer
- assert(pSles->freeFront != pSles->freeRear);
- char *buffer = pSles->freeBuffers[pSles->freeFront];
- if (++pSles->freeFront > pSles->freeBufCount) {
- pSles->freeFront = 0;
- }
-
- // put on play queue
- SLuint32 txRearNext = pSles->txRear + 1;
- if (txRearNext > pSles->txBufCount) {
- txRearNext = 0;
- }
- assert(txRearNext != pSles->txFront);
- pSles->txBuffers[pSles->txRear] = buffer;
- pSles->txRear = txRearNext;
- result = (*(pSles->playerBufferQueue))->Enqueue(pSles->playerBufferQueue,
- buffer, pSles->bufSizeInBytes);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- }
-
- result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- // Create an audio recorder with microphone device source and buffer queue sink.
- // The buffer queue as sink is an Android-specific extension.
-
- SLDataLocator_IODevice locator_iodevice;
- SLDataLocator_AndroidSimpleBufferQueue locator_bufferqueue_rx;
- locator_iodevice.locatorType = SL_DATALOCATOR_IODEVICE;
- locator_iodevice.deviceType = SL_IODEVICE_AUDIOINPUT;
- locator_iodevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
- locator_iodevice.device = NULL;
- audiosrc.pLocator = &locator_iodevice;
- audiosrc.pFormat = NULL;
- locator_bufferqueue_rx.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
- locator_bufferqueue_rx.numBuffers = pSles->rxBufCount;
- audiosnk.pLocator = &locator_bufferqueue_rx;
- audiosnk.pFormat = &pcm;
- {
- SLInterfaceID ids_rx[2] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
- SL_IID_ANDROIDCONFIGURATION};
- SLboolean flags_rx[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
- result = (*engineEngine)->CreateAudioRecorder(engineEngine, &(pSles->recorderObject),
- &audiosrc, &audiosnk, 2, ids_rx, flags_rx);
- if (SL_RESULT_SUCCESS != result) {
- fprintf(stderr, "Could not create audio recorder (result %x), "
- "check sample rate and channel count\n", result);
- status = SLES_FAIL;
-
- SLES_PRINTF("ERROR: Could not create audio recorder (result %x), "
- "check sample rate and channel count\n", result);
- goto cleanup;
- }
- }
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- {
- /* Get the Android configuration interface which is explicit */
- SLAndroidConfigurationItf configItf;
- result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject,
- SL_IID_ANDROIDCONFIGURATION, (void*)&configItf);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- SLuint32 presetValue = micSource;
- /* Use the configuration interface to configure the recorder before it's realized */
- if (presetValue != SL_ANDROID_RECORDING_PRESET_NONE) {
- result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET,
- &presetValue, sizeof(SLuint32));
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- }
-
- }
-
- result = (*(pSles->recorderObject))->Realize(pSles->recorderObject, SL_BOOLEAN_FALSE);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- SLRecordItf recorderRecord;
- result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject, SL_IID_RECORD,
- &recorderRecord);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject,
- SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(pSles->recorderBufferQueue));
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- result = (*(pSles->recorderBufferQueue))->RegisterCallback(pSles->recorderBufferQueue,
- recorderCallback, pSles);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- // Enqueue some empty buffers for the recorder
- for (j = 0; j < pSles->rxBufCount; ++j) {
-
- // allocate a free buffer
- assert(pSles->freeFront != pSles->freeRear);
- char *buffer = pSles->freeBuffers[pSles->freeFront];
- if (++pSles->freeFront > pSles->freeBufCount) {
- pSles->freeFront = 0;
- }
-
- // put on record queue
- SLuint32 rxRearNext = pSles->rxRear + 1;
- if (rxRearNext > pSles->rxBufCount) {
- rxRearNext = 0;
- }
- assert(rxRearNext != pSles->rxFront);
- pSles->rxBuffers[pSles->rxRear] = buffer;
- pSles->rxRear = rxRearNext;
- result = (*(pSles->recorderBufferQueue))->Enqueue(pSles->recorderBufferQueue,
- buffer, pSles->bufSizeInBytes);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- }
-
- // Kick off the recorder
- result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- // Tear down the objects and exit
- status = SLES_SUCCESS;
- cleanup:
- SLES_PRINTF("Finished initialization with status: %d", status);
-
- return status;
-}
-
-int slesProcessNext(sles_data *pSles, double *pSamples, long maxSamples) {
- //int status = SLES_FAIL;
-
- SLES_PRINTF("slesProcessNext: pSles = %p, currentSample: %p, maxSamples = %ld", pSles,
- pSamples, maxSamples);
-
- int samplesRead = 0;
-
- int currentSample = 0;
- double *pCurrentSample = pSamples;
- int maxValue = 32768;
-
- if (pSles == NULL) {
- return samplesRead;
- }
-
- SLresult result;
- for (int i = 0; i < 10; i++) {
- usleep(100000);
- if (pSles->fifo2Buffer != NULL) {
- for (;;) {
- short buffer[pSles->bufSizeInFrames * pSles->channels];
- ssize_t actual = audio_utils_fifo_read(&(pSles->fifo2), buffer,
- pSles->bufSizeInFrames);
- if (actual <= 0)
- break;
- {
- for (int jj =0; jj<actual && currentSample < maxSamples; jj++) {
- *(pCurrentSample++) = ((double)buffer[jj])/maxValue;
- currentSample++;
- }
- }
- samplesRead +=actual;
- }
- }
- if (pSles->injectImpulse > 0) {
- if (pSles->injectImpulse <= 100) {
- pSles->injectImpulse = -1;
- write(1, "I", 1);
- } else {
- if ((pSles->injectImpulse % 1000) < 100) {
- write(1, "i", 1);
- }
- pSles->injectImpulse -= 100;
- }
- } else if (i == 9) {
- write(1, ".", 1);
- }
- }
- SLBufferQueueState playerBQState;
- result = (*(pSles->playerBufferQueue))->GetState(pSles->playerBufferQueue,
- &playerBQState);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- SLAndroidSimpleBufferQueueState recorderBQState;
- result = (*(pSles->recorderBufferQueue))->GetState(pSles->recorderBufferQueue,
- &recorderBQState);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- SLES_PRINTF("End of slesProcessNext: pSles = %p, samplesRead = %d, maxSamples= %ld", pSles,
- samplesRead, maxSamples);
-
- return samplesRead;
-}
-
-int slesDestroyServer(sles_data *pSles) {
- int status = SLES_FAIL;
-
- SLES_PRINTF("Start slesDestroyServer: pSles = %p", pSles);
- if (pSles == NULL) {
- return status;
- }
-
- if (NULL != pSles->playerObject) {
-
- SLES_PRINTF("stopping player...");
- SLPlayItf playerPlay;
- SLresult result = (*(pSles->playerObject))->GetInterface(pSles->playerObject,
- SL_IID_PLAY, &playerPlay);
-
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- //stop player and recorder if they exist
- result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_STOPPED);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- }
-
- if (NULL != pSles->recorderObject) {
- SLES_PRINTF("stopping recorder...");
- SLRecordItf recorderRecord;
- SLresult result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject,
- SL_IID_RECORD, &recorderRecord);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- }
-
- usleep(1000);
-
- audio_utils_fifo_deinit(&(pSles->fifo));
- delete[] pSles->fifoBuffer;
-
- SLES_PRINTF("slesDestroyServer 2");
-
- // if (sndfile != NULL) {
- audio_utils_fifo_deinit(&(pSles->fifo2));
- delete[] pSles->fifo2Buffer;
-
- SLES_PRINTF("slesDestroyServer 3");
-
- // sf_close(sndfile);
- // }
- if (NULL != pSles->playerObject) {
- (*(pSles->playerObject))->Destroy(pSles->playerObject);
- }
-
- SLES_PRINTF("slesDestroyServer 4");
-
- if (NULL != pSles->recorderObject) {
- (*(pSles->recorderObject))->Destroy(pSles->recorderObject);
- }
-
- SLES_PRINTF("slesDestroyServer 5");
-
- (*(pSles->outputmixObject))->Destroy(pSles->outputmixObject);
- SLES_PRINTF("slesDestroyServer 6");
- (*(pSles->engineObject))->Destroy(pSles->engineObject);
- SLES_PRINTF("slesDestroyServer 7");
-
- // free(pSles);
- // pSles=NULL;
-
- status = SLES_SUCCESS;
-
- SLES_PRINTF("End slesDestroyServer: status = %d", status);
- return status;
-}
-
diff --git a/apps/CtsVerifier/jni/audio_loopback/sles.h b/apps/CtsVerifier/jni/audio_loopback/sles.h
deleted file mode 100644
index 607f724..0000000
--- a/apps/CtsVerifier/jni/audio_loopback/sles.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <SLES/OpenSLES.h>
-#include <SLES/OpenSLES_Android.h>
-#include <pthread.h>
-#include <android/log.h>
-
-#ifndef _Included_org_drrickorang_loopback_sles
-#define _Included_org_drrickorang_loopback_sles
-
-//struct audio_utils_fifo;
-#define SLES_PRINTF(...) __android_log_print(ANDROID_LOG_INFO, "sles_jni", __VA_ARGS__);
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-#include <audio_utils/fifo.h>
-
-typedef struct {
- SLuint32 rxBufCount; // -r#
- SLuint32 txBufCount; // -t#
- SLuint32 bufSizeInFrames; // -f#
- SLuint32 channels; // -c#
- SLuint32 sampleRate; // -s#
- SLuint32 exitAfterSeconds; // -e#
- SLuint32 freeBufCount; // calculated
- SLuint32 bufSizeInBytes; // calculated
- int injectImpulse; // -i#i
- SLuint32 numFramesToIgnore;
-
- // Storage area for the buffer queues
- char **rxBuffers;
- char **txBuffers;
- char **freeBuffers;
-
- // Buffer indices
- SLuint32 rxFront; // oldest recording
- SLuint32 rxRear; // next to be recorded
- SLuint32 txFront; // oldest playing
- SLuint32 txRear; // next to be played
- SLuint32 freeFront; // oldest free
- SLuint32 freeRear; // next to be freed
-
- struct audio_utils_fifo fifo; //(*)
- struct audio_utils_fifo fifo2;
- short *fifo2Buffer;
- short *fifoBuffer;
- SLAndroidSimpleBufferQueueItf recorderBufferQueue;
- SLBufferQueueItf playerBufferQueue;
-
- pthread_mutex_t mutex;// = PTHREAD_MUTEX_INITIALIZER;
-
- //other things that belong here
- SLObjectItf playerObject;
- SLObjectItf recorderObject;
- SLObjectItf outputmixObject;
- SLObjectItf engineObject;
-} sles_data;
-
-enum {
- SLES_SUCCESS = 0,
- SLES_FAIL = 1,
-} SLES_STATUS_ENUM;
-
-int slesInit(sles_data ** ppSles, int samplingRate, int frameCount,
- int micSource, int numFramesToIgnore);
-
-//note the double pointer to properly free the memory of the structure
-int slesDestroy(sles_data ** ppSles);
-
-///full
-int slesFull(sles_data *pSles);
-
-int slesCreateServer(sles_data *pSles, int samplingRate, int frameCount, int micSource, int numFramesToIgnore);
-int slesProcessNext(sles_data *pSles, double *pSamples, long maxSamples);
-int slesDestroyServer(sles_data *pSles);
-
-#ifdef __cplusplus
-}
-#endif
-#endif //_Included_org_drrickorang_loopback_sles
diff --git a/apps/CtsVerifier/res/layout/biometric_test_strong_tests.xml b/apps/CtsVerifier/res/layout/biometric_test_strong_tests.xml
index e0236dc..20cf86b 100644
--- a/apps/CtsVerifier/res/layout/biometric_test_strong_tests.xml
+++ b/apps/CtsVerifier/res/layout/biometric_test_strong_tests.xml
@@ -64,6 +64,13 @@
android:text="@string/biometric_test_strong_authenticate_ui_button"
android:enabled="false"/>
<Button
+ android:id="@+id/authenticate_negative_button_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:text="@string/biometric_test_negative_button_button"
+ android:enabled="false"/>
+ <Button
android:id="@+id/authenticate_credential_setDeviceCredentialAllowed_biometric_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/apps/CtsVerifier/res/layout/biometric_test_user_authentication_credential_tests.xml b/apps/CtsVerifier/res/layout/biometric_test_user_authentication_credential_tests.xml
new file mode 100644
index 0000000..eded805
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/biometric_test_user_authentication_credential_tests.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <ScrollView android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <TextView
+ style="@style/InstructionsFont"
+ android:id="@+id/instructions"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:gravity="center" />
+
+ <!-- This section contains tests that will be repeated again below with/without strongbox -->
+
+ <Button
+ android:id="@+id/per_use_auth_with_credential"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:text="@string/biometric_test_set_user_authentication_credential_per_use_auth_with_credential"/>
+
+ <Button
+ android:id="@+id/duration_auth_with_credential"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:text="@string/biometric_test_set_user_authentication_credential_duration_auth_with_credential"/>
+
+ <Button
+ android:id="@+id/per_use_auth_with_biometric"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:text="@string/biometric_test_set_user_authentication_credential_per_use_auth_with_biometric"/>
+
+ <Button
+ android:id="@+id/duration_auth_with_biometric"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:text="@string/biometric_test_set_user_authentication_credential_duration_auth_with_biometric"/>
+
+ <!-- The below are the same as above, except with strongbox -->
+
+ <Button
+ android:id="@+id/per_use_auth_with_credential_strongbox"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:text="@string/biometric_test_set_user_authentication_credential_per_use_auth_with_credential_strongbox"/>
+
+ <Button
+ android:id="@+id/duration_auth_with_credential_strongbox"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:text="@string/biometric_test_set_user_authentication_credential_duration_auth_with_credential_strongbox"/>
+
+ <Button
+ android:id="@+id/per_use_auth_with_biometric_strongbox"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:text="@string/biometric_test_set_user_authentication_credential_per_use_auth_with_biometric_strongbox"/>
+
+ <Button
+ android:id="@+id/duration_auth_with_biometric_strongbox"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:text="@string/biometric_test_set_user_authentication_credential_duration_auth_with_biometric_strongbox"/>
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ <include
+ layout="@layout/pass_fail_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ </LinearLayout>
+
+ </ScrollView>
+
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/biometric_test_weak_tests.xml b/apps/CtsVerifier/res/layout/biometric_test_weak_tests.xml
index fbec4ac..456552d 100644
--- a/apps/CtsVerifier/res/layout/biometric_test_weak_tests.xml
+++ b/apps/CtsVerifier/res/layout/biometric_test_weak_tests.xml
@@ -85,6 +85,13 @@
android:layout_centerInParent="true"
android:text="@string/biometric_test_reject_first"
android:enabled="false"/>
+ <Button
+ android:id="@+id/authenticate_negative_button_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:text="@string/biometric_test_negative_button_button"
+ android:enabled="false"/>
<Space
android:layout_width="match_parent"
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 0f708d7..c09aaed 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -229,11 +229,12 @@
<!-- Strings for BiometricTest -->
<string name="biometric_test">Biometric Tests</string>
- <string name="biometric_test_category_credential">Credential Tests</string>
- <string name="biometric_test_category_strong">Strong Biometric Tests</string>
- <string name="biometric_test_category_weak">Weak Biometric Tests</string>
+ <string name="biometric_test_category_credential">1) Credential Tests</string>
+ <string name="biometric_test_category_strong">2) Strong Biometric Tests</string>
+ <string name="biometric_test_category_weak">3) Weak Biometric Tests</string>
+ <string name="biometric_test_category_combination">4) setUserAuthParams Tests</string>
- <string name="biometric_test_credential_not_enrolled_label">1) Credential Not Enrolled Tests</string>
+ <string name="biometric_test_credential_not_enrolled_label">1a: Credential Not Enrolled Tests</string>
<string name="biometric_test_credential_not_enrolled_instructions">This test checks that the BiometricManager/BiometricPrompt
APIs return results consistent with credential (PIN/Pattern/Password) state. Before starting this test, please ensure that you do
NOT have a credential set up.</string>
@@ -241,7 +242,7 @@
<string name="biometric_test_credential_not_enrolled_bp_setAllowedAuthenticators_button">Check BiometricPrompt setAllowedAuthenticators(DEVICE_CREDENTIAL)</string>
<string name="biometric_test_credential_not_enrolled_bp_setDeviceCredentialAllowed_button">Check BiometricPrompt setDeviceCredentialAllowed(true)</string>
- <string name="biometric_test_credential_enrolled_label">2) Credential Enrolled Tests</string>
+ <string name="biometric_test_credential_enrolled_label">1b: Credential Enrolled Tests</string>
<string name="biometric_test_credential_enrolled_instructions">This test checks that apps are able to request credential enrollment, and that the BiometricManager/BiometricPrompt
APIs return results consistent with credential (PIN/Pattern/Password) state.</string>
<string name="biometric_test_credential_enroll_button">Enroll credential</string>
@@ -249,7 +250,7 @@
<string name="biometric_test_credential_enrolled_bp_setAllowedAuthenticators_button">Check BiometricPrompt setAllowedAuthenticators(DEVICE_CREDENTIAL)</string>
<string name="biometric_test_credential_enrolled_bp_setDeviceCredentialAllowed_button">Check BiometricPrompt setDeviceCredentialAllowed(true)</string>
- <string name="biometric_test_credential_crypto_label">3) Credential Crypto</string>
+ <string name="biometric_test_credential_crypto_label">1c: Credential Crypto</string>
<string name="biometric_test_credential_crypto_instructions">This test checks that PIN/Pattern/Password successfully unlocks the relevant KeyStore operations. Please
ensure that you have a PIN/Pattern/Password set up.</string>
<string name="biometric_test_credential_crypto_timed_key_strongbox">Create and unlock timed key (StrongBox)</string>
@@ -271,12 +272,14 @@
<string name="biometric_test_invalid_inputs">Test invalid inputs</string>
<!-- Rejecting does not end the authentication lifecycle -->
<string name="biometric_test_reject_first">Reject, then authenticate</string>
+ <!-- Negative button callback is received -->
+ <string name="biometric_test_negative_button_button">Test Negative Button</string>
<string name="biometric_test_reject_continues_instruction_title">Instructions</string>
<string name="biometric_test_reject_continues_instruction_contents">Please authenticate with a non-enrolled biometric before authenticating with the actual enrolled biometric.</string>
<string name="biometric_test_reject_continues_instruction_continue">Continue</string>
- <string name="biometric_test_strong_label">4) Strong Biometrics + Crypto</string>
+ <string name="biometric_test_strong_label">2a: Strong Biometrics + Crypto</string>
<string name="biometric_test_strong_instructions">This test checks that the Settings.ACTION_BIOMETRIC_ENROLL and its corresponding
EXTRA_BIOMETRIC_AUTHENTICATOR_REQUIREMENTS APIs enroll only a STRONG biometric. Please ensure that the device
does NOT have ANY biometrics enrolled before starting this test. After passing the first part of the test, it will check various use cases
@@ -290,7 +293,7 @@
<string name="biometric_test_strong_authenticate_invalidated_instruction_contents">Before starting the next test, please add another enrollment to your strong biometric sensor. If only one enrollment is supported, please remove the current enrollment, then enroll.</string>
<string name="biometric_test_strong_authenticate_invalidated_instruction_continue">Continue</string>
- <string name="biometric_test_weak_label">5) Weak Biometrics</string>
+ <string name="biometric_test_weak_label">3a: Weak Biometrics</string>
<string name="biometric_test_weak_instructions">This test checks that the Settings.ACTION_BIOMETRIC_ENROLL and its corresponding
EXTRA_BIOMETRIC_AUTHENTICATOR_REQUIREMENTS APIs enroll a biometric that meets or exceeds WEAK. Please ensure that the device
does NOT have ANY biometrics enrolled before starting this test. After passing the first part of the test, it will check various use cases
@@ -298,6 +301,32 @@
<string name="biometric_test_weak_enroll">Start enrollment</string>
<string name="biometric_test_weak_authenticate">Authenticate</string>
+ <string name="biometric_test_set_user_authentication_credential_cipher_label">4a: Cipher, Credential</string>
+ <string name="biometric_test_set_user_authentication_biometric_cipher_label">4b: Cipher, Biometric</string>
+ <string name="biometric_test_set_user_authentication_biometric_credential_cipher_label">4c: Cipher, Biometric|Credential</string>
+ <string name="biometric_test_set_user_authentication_credential_signature_label">4d: Signature, Credential</string>
+ <string name="biometric_test_set_user_authentication_biometric_signature_label">4e: Signature, Biometric</string>
+ <string name="biometric_test_set_user_authentication_biometric_or_credential_signature_label">4f: Signature, Biometric|Credential</string>
+ <string name="biometric_test_set_user_authentication_credential_mac_label">4g: MAC, Credential</string>
+ <string name="biometric_test_set_user_authentication_biometric_mac_label">4h: MAC, Biometric</string>
+ <string name="biometric_test_set_user_authentication_biometric_or_credential_mac_label">4h: MAC, Biometric|Credential</string>
+ <string name="biometric_test_set_user_authentication_credential_instructions">This test checks the correctness of the KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int) API for AUTH_DEVICE_CREDENTIAL.
+ Buttons for completed tasks will become invisible. It\'s normal for buttons to be disabled for a few seconds during this test.</string>
+ <string name="biometric_test_set_user_authentication_biometric_instructions">This test checks the correctness of the KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int) API for AUTH_BIOMETRIC_STRONG.
+ Buttons for completed tasks will become invisible. It\'s normal for buttons to be disabled for a few seconds during this test.</string>
+ <string name="biometric_test_set_user_authentication_biometric_or_credential_instructions">This test checks the correctness of the KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int) API for AUTH_BIOMETRIC_STRONG|AUTH_DEVICE_CREDENTIAL.
+ Buttons for completed tasks will become invisible. It\'s normal for buttons to be disabled for a few seconds during this test.</string>
+ <!-- no strongbox-->
+ <string name="biometric_test_set_user_authentication_credential_per_use_auth_with_credential">auth-per-use key with credential</string>
+ <string name="biometric_test_set_user_authentication_credential_duration_auth_with_credential">time-based key with credential</string>
+ <string name="biometric_test_set_user_authentication_credential_per_use_auth_with_biometric">auth-per-use key with biometric</string>
+ <string name="biometric_test_set_user_authentication_credential_duration_auth_with_biometric">time-based key with biometric</string>
+ <!-- strongbox -->
+ <string name="biometric_test_set_user_authentication_credential_per_use_auth_with_credential_strongbox">auth-per-use key with credential (strongbox)</string>
+ <string name="biometric_test_set_user_authentication_credential_duration_auth_with_credential_strongbox">time-based key with credential (strongbox)</string>
+ <string name="biometric_test_set_user_authentication_credential_per_use_auth_with_biometric_strongbox">auth-per-use key with biometric (strongbox)</string>
+ <string name="biometric_test_set_user_authentication_credential_duration_auth_with_biometric_strongbox">time-based key with biometric (strongbox)</string>
+
<!-- Strings for lock bound keys test -->
<string name="sec_lock_bound_key_test">Lock Bound Keys Test</string>
<string name="sec_lock_bound_key_test_info">
@@ -1673,8 +1702,8 @@
<string name="wifi_status_suggestion_get_failure">Failed to get suggestions.</string>
<string name="wifi_status_suggestion_remove">Removing suggestions from the device.</string>
<string name="wifi_status_suggestion_remove_failure">Failed to remove suggestions.</string>
- <string name="wifi_status_suggestion_wait_for_connect">Waiting for network connection. Please click \"Yes\" in the notification that pops up for approving the request.</string>
- <string name="wifi_status_suggestion_ensure_no_connect">Ensuring no network connection. Please click \"Yes\" in the notification that pops up for approving the request.</string>
+ <string name="wifi_status_suggestion_wait_for_connect">Waiting for network connection. Please click \"Allow\" in the dialog that pops up for approving the app.</string>
+ <string name="wifi_status_suggestion_ensure_no_connect">Ensuring no network connection. Please click \"Allow\" in the dialog that pops up for approving the app.</string>
<string name="wifi_status_suggestion_connect">Connected to the network.</string>
<string name="wifi_status_suggestion_not_connected">Did not connect to the network.</string>
<string name="wifi_status_suggestion_wait_for_post_connect_bcast">Waiting for post connection broadcast.</string>
@@ -2808,7 +2837,7 @@
<string name="provisioning_byod_cross_profile_permission_disabled_by_default">Cross profile permission disabled by default</string>
<string name="provisioning_byod_cross_profile_permission_disabled_by_default_instruction">
Press the Go button to go to Settings > Apps & notifications > Special app access >\n
- Connected personal and work apps.\n
+ Connected work and personal apps.\n
Choose the \"Cross profile test app\" from the list and check that the switch is disabled.\n
Go back to CTS Verifier and mark the test as \"Pass\" or \"Fail\".
</string>
@@ -2816,7 +2845,7 @@
<string name="provisioning_byod_cross_profile_permission_enabled_instruction">
Press the Go button to open the \"Cross Profile Test App\".\n
Press the \"Open Settings\" button to go to Settings > Apps & notifications > Special app access >
- Connected personal and work apps > Cross profile test app, then enable the switch.\n
+ Connected work and personal apps > Cross profile test app, then enable the switch.\n
Verify that when you go back it takes you to the \"Cross Profile Test App\".\n
Now verify that it shows \"INTERACTING ACROSS PROFILES ALLOWED\" message.\n
Go back to CTS Verifier and mark the test as \"Pass\" or \"Fail\".
@@ -2825,7 +2854,7 @@
<string name="provisioning_byod_cross_profile_permission_disabled_instruction">
Press the Go button to open the \"Cross Profile Test App\".\n
Press the \"Open Settings\" button to go to Settings > Apps & notifications > Special app access >
- Connected personal and work apps > Cross profile test app, then disable the switch.\n
+ Connected work and personal apps > Cross profile test app, then disable the switch.\n
Verify that when you go back it takes you to the \"Cross Profile Test App\".\n
Now verify that it shows \"INTERACTING ACROSS PROFILES NOT ALLOWED\" message.\n
Go back to CTS Verifier and mark the test as \"Pass\" or \"Fail\".
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackActivity.java
index f5cf4e1..5c3fa9f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackActivity.java
@@ -27,6 +27,7 @@
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.AudioTrack;
+import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Handler;
@@ -51,15 +52,14 @@
public static final int BYTES_PER_FRAME = 2;
- NativeAudioThread nativeAudioThread = null;
+ NativeAnalyzerThread mNativeAnalyzerThread = null;
private int mSamplingRate = 44100;
private int mMinBufferSizeInFrames = 0;
private static final double CONFIDENCE_THRESHOLD = 0.6;
- private Correlation mCorrelation = new Correlation();
- // TODO: remove this variable
- private int mNumFramesToIgnore = 0;
+ private double mLatencyMillis;
+ private double mConfidence;
OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
Context mContext;
@@ -92,13 +92,13 @@
case R.id.audio_general_headset_yes:
Log.i(TAG, "User confirms Headset Port existence");
mLoopbackPlugReady.setEnabled(true);
- recordHeasetPortFound(true);
+ recordHeadsetPortFound(true);
mHeadsetPortYes.setEnabled(false);
mHeadsetPortNo.setEnabled(false);
break;
case R.id.audio_general_headset_no:
Log.i(TAG, "User denies Headset Port existence");
- recordHeasetPortFound(false);
+ recordHeadsetPortFound(false);
getPassButton().setEnabled(true);
mHeadsetPortYes.setEnabled(false);
mHeadsetPortNo.setEnabled(false);
@@ -161,6 +161,7 @@
setPassFailButtonClickListeners();
getPassButton().setEnabled(false);
setInfoResources(R.string.audio_loopback_test, R.string.audio_loopback_info, -1);
+
}
/**
@@ -204,41 +205,43 @@
*/
private void startAudioTest() {
getPassButton().setEnabled(false);
+ mTestButton.setEnabled(false);
+ mLatencyMillis = 0.0;
+ mConfidence = 0.0;
- //get system defaults for sampling rate, buffers.
- AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
- String value = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
- mMinBufferSizeInFrames = Integer.parseInt(value);
-
- int minBufferSizeInBytes = BYTES_PER_FRAME * mMinBufferSizeInFrames;
-
- mSamplingRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
-
- Log.i(TAG, String.format("startAudioTest sr:%d , buffer:%d frames",
- mSamplingRate, mMinBufferSizeInFrames));
-
- nativeAudioThread = new NativeAudioThread();
- if (nativeAudioThread != null) {
- nativeAudioThread.setMessageHandler(mMessageHandler);
- nativeAudioThread.mSessionId = 0;
- nativeAudioThread.setParams(mSamplingRate,
- minBufferSizeInBytes,
- minBufferSizeInBytes,
- 0x03 /*voice recognition*/,
- mNumFramesToIgnore);
- nativeAudioThread.start();
+ mNativeAnalyzerThread = new NativeAnalyzerThread();
+ if (mNativeAnalyzerThread != null) {
+ mNativeAnalyzerThread.setMessageHandler(mMessageHandler);
+ // This value matches AAUDIO_INPUT_PRESET_VOICE_RECOGNITION
+ mNativeAnalyzerThread.setInputPreset(MediaRecorder.AudioSource.VOICE_RECOGNITION);
+ mNativeAnalyzerThread.startTest();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
-
- nativeAudioThread.runTest();
-
}
}
+ private void handleTestCompletion() {
+ recordTestResults();
+ boolean resultValid = mConfidence >= CONFIDENCE_THRESHOLD
+ && mLatencyMillis > 1.0;
+ getPassButton().setEnabled(resultValid);
+
+ // Make sure the test thread is finished. It should already be done.
+ if (mNativeAnalyzerThread != null) {
+ try {
+ mNativeAnalyzerThread.stopTest(2 * 1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ showWait(false);
+ mTestButton.setEnabled(true);
+ }
+
/**
* handler for messages from audio thread
*/
@@ -246,45 +249,35 @@
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch(msg.what) {
- case NativeAudioThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_STARTED:
+ case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_STARTED:
Log.v(TAG,"got message native rec started!!");
showWait(true);
mResultText.setText("Test Running...");
break;
- case NativeAudioThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_ERROR:
+ case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_OPEN_ERROR:
Log.v(TAG,"got message native rec can't start!!");
- showWait(false);
- mResultText.setText("Test Error.");
+ mResultText.setText("Test Error opening streams.");
+ handleTestCompletion();
break;
- case NativeAudioThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE:
- case NativeAudioThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE_ERRORS:
- if (nativeAudioThread != null) {
- Log.v(TAG,"Finished recording.");
- double [] waveData = nativeAudioThread.getWaveData();
- mCorrelation.computeCorrelation(waveData, mSamplingRate);
- mResultText.setText(String.format(
- "Test Finished\nLatency:%.2f ms\nConfidence: %.2f",
- mCorrelation.mEstimatedLatencyMs,
- mCorrelation.mEstimatedLatencyConfidence));
-
- recordTestResults();
- if (mCorrelation.mEstimatedLatencyConfidence >= CONFIDENCE_THRESHOLD) {
- getPassButton().setEnabled(true);
- }
-
- //close
- if (nativeAudioThread != null) {
- nativeAudioThread.isRunning = false;
- try {
- nativeAudioThread.finish();
- nativeAudioThread.join();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- nativeAudioThread = null;
- }
- showWait(false);
+ case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_ERROR:
+ Log.v(TAG,"got message native rec can't start!!");
+ mResultText.setText("Test Error while recording.");
+ handleTestCompletion();
+ break;
+ case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE_ERRORS:
+ mResultText.setText("Test FAILED due to errors.");
+ handleTestCompletion();
+ break;
+ case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE:
+ if (mNativeAnalyzerThread != null) {
+ mLatencyMillis = mNativeAnalyzerThread.getLatencyMillis();
+ mConfidence = mNativeAnalyzerThread.getConfidence();
}
+ mResultText.setText(String.format(
+ "Test Finished\nLatency:%.2f ms\nConfidence: %.2f",
+ mLatencyMillis,
+ mConfidence));
+ handleTestCompletion();
break;
default:
break;
@@ -299,13 +292,13 @@
getReportLog().addValue(
"Estimated Latency",
- mCorrelation.mEstimatedLatencyMs,
+ mLatencyMillis,
ResultType.LOWER_BETTER,
ResultUnit.MS);
getReportLog().addValue(
"Confidence",
- mCorrelation.mEstimatedLatencyConfidence,
+ mConfidence,
ResultType.HIGHER_BETTER,
ResultUnit.NONE);
@@ -331,7 +324,7 @@
Log.v(TAG,"Results Recorded");
}
- private void recordHeasetPortFound(boolean found) {
+ private void recordHeadsetPortFound(boolean found) {
getReportLog().addValue(
"User Reported Headset Port",
found ? 1.0 : 0,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/Correlation.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/Correlation.java
deleted file mode 100644
index c653d1d..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/Correlation.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.audio;
-
-import android.util.Log;
-
-
-public class Correlation {
-
- private int mBlockSize = 4096;
- private int mSamplingRate = 44100;
- private double [] mDataDownsampled = new double [mBlockSize];
- private double [] mDataAutocorrelated = new double[mBlockSize];
-
- public double mEstimatedLatencySamples = 0;
- public double mEstimatedLatencyMs = 0;
- public double mEstimatedLatencyConfidence = 0.0;
-
- private double mAmplitudeThreshold = 0.001; // 0.001 = -60 dB noise
-
- public void init(int blockSize, int samplingRate) {
- mBlockSize = blockSize;
- mSamplingRate = samplingRate;
- }
-
- public boolean computeCorrelation(double [] data, int samplingRate) {
- boolean status = false;
- log("Started Auto Correlation for data with " + data.length + " points");
- mSamplingRate = samplingRate;
-
- downsampleData(data, mDataDownsampled, mAmplitudeThreshold);
-
- //correlation vector
- autocorrelation(mDataDownsampled, mDataAutocorrelated);
-
- int N = data.length; //all samples available
- double groupSize = (double) N / mBlockSize; //samples per downsample point.
-
- double maxValue = 0;
- int maxIndex = -1;
-
- double minLatencyMs = 8; //min latency expected. This algorithm should be improved.
- int minIndex = (int)(0.5 + minLatencyMs * mSamplingRate / (groupSize*1000));
-
- double average = 0;
- double rms = 0;
- //find max
- for (int i=minIndex; i<mDataAutocorrelated.length; i++) {
- average += mDataAutocorrelated[i];
- rms += mDataAutocorrelated[i]*mDataAutocorrelated[i];
- if (mDataAutocorrelated[i] > maxValue) {
- maxValue = mDataAutocorrelated[i];
- maxIndex = i;
- }
- }
-
- rms = Math.sqrt(rms/mDataAutocorrelated.length);
- average = average/mDataAutocorrelated.length;
- log(String.format(" Maxvalue %f, max Index : %d/%d (%d) minIndex=%d",maxValue, maxIndex,
- mDataAutocorrelated.length, data.length, minIndex));
-
- log(String.format(" average : %.3f rms: %.3f", average, rms));
-
- mEstimatedLatencyConfidence = 0.0;
- if (average>0) {
- double factor = 3.0;
-
- double raw = (rms-average) /(factor*average);
- log(String.format("Raw: %.3f",raw));
- mEstimatedLatencyConfidence = Math.max(Math.min(raw, 1.0),0.0);
- }
-
- log(String.format(" ****Confidence: %.2f",mEstimatedLatencyConfidence));
-
- mEstimatedLatencySamples = maxIndex*groupSize;
-
- mEstimatedLatencyMs = mEstimatedLatencySamples *1000/mSamplingRate;
-
- log(String.format(" latencySamples: %.2f %.2f ms", mEstimatedLatencySamples,
- mEstimatedLatencyMs));
-
- status = true;
- return status;
- }
-
- private boolean downsampleData(double [] data, double [] dataDownsampled, double threshold) {
-
- boolean status = false;
- // mDataDownsampled = new double[mBlockSize];
- for (int i=0; i<mBlockSize; i++) {
- dataDownsampled[i] = 0;
- }
-
- int N = data.length; //all samples available
- double groupSize = (double) N / mBlockSize;
-
- int ignored = 0;
-
- int currentIndex = 0;
- double nextGroup = groupSize;
- for (int i = 0; i<N && currentIndex<mBlockSize; i++) {
-
- if (i> nextGroup) { //advanced to next group.
- currentIndex++;
- nextGroup += groupSize;
- }
-
- if (currentIndex>=mBlockSize) {
- break;
- }
-
- double value = Math.abs(data[i]);
- if (value >= threshold) {
- dataDownsampled[currentIndex] += value;
- } else {
- ignored++;
- }
- }
-
- log(String.format(" Threshold: %.3f, ignored:%d/%d (%.2f)", threshold, ignored, N,
- (double) ignored/(double)N));
-
- status = true;
- return status;
- }
-
- private boolean autocorrelation(double [] data, double [] dataOut) {
- boolean status = false;
-
- double sumsquared = 0;
- int N = data.length;
- for (int i=0; i<N; i++) {
- double value = data[i];
- sumsquared += value*value;
- }
-
- if (sumsquared>0) {
- for (int i = 0; i < N; i++) {
- dataOut[i] = 0;
- for (int j = 0; j < N - i; j++) {
-
- dataOut[i] += data[j] * data[i + j];
- }
- dataOut[i] = dataOut[i] / sumsquared;
- }
- status = true;
- }
-
- return status;
- }
-
- private static void log(String msg) {
- Log.v("Recorder", msg);
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/NativeAnalyzerThread.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/NativeAnalyzerThread.java
new file mode 100644
index 0000000..42f22aa
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/NativeAnalyzerThread.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.cts.verifier.audio;
+
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.media.MediaRecorder;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
+import android.util.Log;
+
+import android.os.Handler;
+import android.os.Message;
+
+/**
+ * A thread that runs a native audio loopback analyzer.
+ */
+public class NativeAnalyzerThread {
+ private final int mSecondsToRun = 5;
+ private Handler mMessageHandler;
+ private Thread mThread;
+ private volatile boolean mEnabled = false;
+ private volatile double mLatencyMillis = 0.0;
+ private volatile double mConfidence = 0.0;
+ private int mInputPreset = 0;
+
+ static final int NATIVE_AUDIO_THREAD_MESSAGE_REC_STARTED = 892;
+ static final int NATIVE_AUDIO_THREAD_MESSAGE_OPEN_ERROR = 893;
+ static final int NATIVE_AUDIO_THREAD_MESSAGE_REC_ERROR = 894;
+ static final int NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE = 895;
+ static final int NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE_ERRORS = 896;
+
+ public void setInputPreset(int inputPreset) {
+ mInputPreset = inputPreset;
+ }
+
+ //JNI load
+ static {
+ try {
+ System.loadLibrary("audioloopback_jni");
+ } catch (UnsatisfiedLinkError e) {
+ log("Error loading loopback JNI library");
+ e.printStackTrace();
+ }
+
+ /* TODO: gracefully fail/notify if the library can't be loaded */
+ }
+
+ /**
+ * @return native audio context
+ */
+ private native long openAudio(int micSource);
+ private native int startAudio(long audio_context);
+ private native int stopAudio(long audio_context);
+ private native int closeAudio(long audio_context);
+ private native int getError(long audio_context);
+ private native boolean isRecordingComplete(long audio_context);
+ private native int analyze(long audio_context);
+ private native double getLatencyMillis(long audio_context);
+ private native double getConfidence(long audio_context);
+
+ public double getLatencyMillis() {
+ return mLatencyMillis;
+ }
+
+ public double getConfidence() {
+ return mConfidence;
+ }
+
+ public synchronized void startTest() {
+ if (mThread == null) {
+ mEnabled = true;
+ mThread = new Thread(mBackGroundTask);
+ mThread.start();
+ }
+ }
+
+ public synchronized void stopTest(int millis) throws InterruptedException {
+ mEnabled = false;
+ if (mThread != null) {
+ mThread.interrupt();
+ mThread.join(millis);
+ mThread = null;
+ }
+ }
+
+ private void sendMessage(int what) {
+ if (mMessageHandler != null) {
+ Message msg = Message.obtain();
+ msg.what = what;
+ mMessageHandler.sendMessage(msg);
+ }
+ }
+
+ private Runnable mBackGroundTask = () -> {
+ mLatencyMillis = 0.0;
+ mConfidence = 0.0;
+ boolean analysisComplete = false;
+
+ log(" Started capture test");
+ sendMessage(NATIVE_AUDIO_THREAD_MESSAGE_REC_STARTED);
+
+ long audioContext = openAudio(mInputPreset);
+ log(String.format("audioContext = 0x%X",audioContext));
+
+ if (audioContext == 0 ) {
+ log(" ERROR at JNI initialization");
+ sendMessage(NATIVE_AUDIO_THREAD_MESSAGE_OPEN_ERROR);
+ } else if (mEnabled) {
+ int result = startAudio(audioContext);
+ if (result < 0) {
+ sendMessage(NATIVE_AUDIO_THREAD_MESSAGE_REC_ERROR);
+ mEnabled = false;
+ }
+
+ final long timeoutMillis = mSecondsToRun * 1000;
+ final long startedAtMillis = System.currentTimeMillis();
+ boolean timedOut = false;
+ int loopCounter = 0;
+ while (mEnabled && !timedOut) {
+ result = getError(audioContext);
+ if (result < 0) {
+ sendMessage(NATIVE_AUDIO_THREAD_MESSAGE_REC_ERROR);
+ break;
+ } else if (isRecordingComplete(audioContext)) {
+ result = stopAudio(audioContext);
+ if (result < 0) {
+ sendMessage(NATIVE_AUDIO_THREAD_MESSAGE_REC_ERROR);
+ break;
+ }
+
+ // Analyze the recording and measure latency.
+ mThread.setPriority(Thread.MAX_PRIORITY);
+ result = analyze(audioContext);
+ if (result < 0) {
+ break;
+ } else {
+ analysisComplete = true;
+ }
+ mLatencyMillis = getLatencyMillis(audioContext);
+ mConfidence = getConfidence(audioContext);
+ break;
+ } else {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ long now = System.currentTimeMillis();
+ timedOut = (now - startedAtMillis) > timeoutMillis;
+ }
+ log("latency: analyze returns " + result);
+ closeAudio(audioContext);
+
+ int what = (analysisComplete && result == 0)
+ ? NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE
+ : NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE_ERRORS;
+ sendMessage(what);
+ }
+ };
+
+ public void setMessageHandler(Handler messageHandler) {
+ mMessageHandler = messageHandler;
+ }
+
+ private static void log(String msg) {
+ Log.v("Loopback", msg);
+ }
+
+} //end thread.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/NativeAudioThread.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/NativeAudioThread.java
deleted file mode 100644
index 0bb1298..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/NativeAudioThread.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//package org.drrickorang.loopback;
-
-package com.android.cts.verifier.audio;
-
-import android.media.AudioFormat;
-import android.media.AudioManager;
-import android.media.AudioTrack;
-//import android.media.MediaPlayer;
-import android.media.AudioRecord;
-import android.media.MediaRecorder;
-import android.util.Log;
-
-import android.os.Handler;
-import android.os.Message;
-
-/**
- * A thread/audio track based audio synth.
- */
-public class NativeAudioThread extends Thread {
-
- public boolean isRunning = false;
- double twoPi = 6.28318530718;
-
- public int mSessionId;
-
- public double[] mvSamples; //captured samples
- int mSamplesIndex;
-
- private final int mSecondsToRun = 2;
- public int mSamplingRate = 48000;
- private int mChannelConfigIn = AudioFormat.CHANNEL_IN_MONO;
- private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
-
- int mMinPlayBufferSizeInBytes = 0;
- int mMinRecordBuffSizeInBytes = 0;
- private int mChannelConfigOut = AudioFormat.CHANNEL_OUT_MONO;
-
- int mMicSource = 0;
-
- int mNumFramesToIgnore;
-
-// private double [] samples = new double[50000];
-
- boolean isPlaying = false;
- private Handler mMessageHandler;
- boolean isDestroying = false;
- boolean hasDestroyingErrors = false;
-
- static final int NATIVE_AUDIO_THREAD_MESSAGE_REC_STARTED = 892;
- static final int NATIVE_AUDIO_THREAD_MESSAGE_REC_ERROR = 893;
- static final int NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE = 894;
- static final int NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE_ERRORS = 895;
-
- public void setParams(int samplingRate, int playBufferInBytes, int recBufferInBytes,
- int micSource, int numFramesToIgnore) {
- mSamplingRate = samplingRate;
- mMinPlayBufferSizeInBytes = playBufferInBytes;
- mMinRecordBuffSizeInBytes = recBufferInBytes;
- mMicSource = micSource;
- mNumFramesToIgnore = numFramesToIgnore;
- }
-
- //JNI load
- static {
- try {
- System.loadLibrary("audioloopback_jni");
- } catch (UnsatisfiedLinkError e) {
- log("Error loading loopback JNI library");
- e.printStackTrace();
- }
-
- /* TODO: gracefully fail/notify if the library can't be loaded */
- }
-
- //jni calls
- public native long slesInit(int samplingRate, int frameCount, int micSource,
- int numFramesToIgnore);
- public native int slesProcessNext(long sles_data, double[] samples, long offset);
- public native int slesDestroy(long sles_data);
-
- public void run() {
-
- setPriority(Thread.MAX_PRIORITY);
- isRunning = true;
-
- //erase output buffer
- if (mvSamples != null)
- mvSamples = null;
-
- //resize
- int nNewSize = (int)(1.1* mSamplingRate * mSecondsToRun ); //10% more just in case
- mvSamples = new double[nNewSize];
- mSamplesIndex = 0; //reset index
-
- //clear samples
- for (int i=0; i<nNewSize; i++) {
- mvSamples[i] = 0;
- }
-
- //start playing
- isPlaying = true;
-
-
- log(" Started capture test");
- if (mMessageHandler != null) {
- Message msg = Message.obtain();
- msg.what = NATIVE_AUDIO_THREAD_MESSAGE_REC_STARTED;
- mMessageHandler.sendMessage(msg);
- }
-
-
-
- log(String.format("about to init, sampling rate: %d, buffer:%d", mSamplingRate,
- mMinPlayBufferSizeInBytes/2 ));
- long sles_data = slesInit(mSamplingRate, mMinPlayBufferSizeInBytes/2, mMicSource,
- mNumFramesToIgnore);
- log(String.format("sles_data = 0x%X",sles_data));
-
- if (sles_data == 0 ) {
- log(" ERROR at JNI initialization");
- if (mMessageHandler != null) {
- Message msg = Message.obtain();
- msg.what = NATIVE_AUDIO_THREAD_MESSAGE_REC_ERROR;
- mMessageHandler.sendMessage(msg);
- }
- } else {
-
- //wait a little bit...
- try {
- sleep(10); //just to let it start properly?
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
-
-
- mSamplesIndex = 0;
- int totalSamplesRead = 0;
- long offset = 0;
- for (int ii = 0; ii < mSecondsToRun; ii++) {
- log(String.format("block %d...", ii));
- int samplesRead = slesProcessNext(sles_data, mvSamples,offset);
- totalSamplesRead += samplesRead;
-
- offset += samplesRead;
- log(" [" + ii + "] jni samples read:" + samplesRead + " currentOffset:" + offset);
- }
-
- log(String.format(" samplesRead: %d, sampleOffset:%d", totalSamplesRead, offset));
- log(String.format("about to destroy..."));
-
- runDestroy(sles_data);
-
- int maxTry = 20;
- int tryCount = 0;
- //isDestroying = true;
- while (isDestroying) {
-
- try {
- sleep(40);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
- tryCount++;
-
- log("destroy try: " + tryCount);
-
- if (tryCount >= maxTry) {
- hasDestroyingErrors = true;
- log("WARNING: waited for max time to properly destroy JNI.");
- break;
- }
- }
- log(String.format("after destroying. TotalSamplesRead = %d", totalSamplesRead));
-
- if (totalSamplesRead==0)
- {
- hasDestroyingErrors = true;
- }
-
- endTest();
- }
- }
-
- public void setMessageHandler(Handler messageHandler) {
- mMessageHandler = messageHandler;
- }
-
- private void runDestroy(final long sles_data ) {
- isDestroying = true;
-
- //start thread
-
- final long local_sles_data = sles_data;
- ////
- Thread thread = new Thread(new Runnable() {
- public void run() {
- isDestroying = true;
- log("**Start runnable destroy");
-
- int status = slesDestroy(local_sles_data);
- log(String.format("**End runnable destroy sles delete status: %d", status));
- isDestroying = false;
- }
- });
-
- thread.start();
-
-
-
- log("end of runDestroy()");
-
-
- }
-
- public void togglePlay() {
-
- }
-
- public void runTest() {
-
-
- }
-
- public void endTest() {
- log("--Ending capture test--");
- isPlaying = false;
-
-
- if (mMessageHandler != null) {
- Message msg = Message.obtain();
- if (hasDestroyingErrors)
- msg.what = NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE_ERRORS;
- else
- msg.what = NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE;
- mMessageHandler.sendMessage(msg);
- }
-
- }
-
- public void finish() {
-
- if (isRunning) {
- isRunning = false;
- try {
- sleep(20);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
-
- private static void log(String msg) {
- Log.v("Loopback", msg);
- }
-
- double [] getWaveData () {
- return mvSamples;
- }
-
-} //end thread.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractBaseTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractBaseTest.java
index a79d82a..aa58ba8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractBaseTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractBaseTest.java
@@ -43,7 +43,6 @@
public abstract class AbstractBaseTest extends PassFailButtons.Activity {
private static final int REQUEST_ENROLL_WHEN_NONE_ENROLLED = 1;
- private static final int REQUEST_ENROLL_WHEN_ENROLLED = 2;
abstract protected String getTag();
abstract protected boolean isOnPauseAllowed();
@@ -72,7 +71,7 @@
// Assume we only enable the pass button when all tests pass. There actually isn't a way
// to easily do something like `this.isTestPassed()`
if (!getPassButton().isEnabled() && !isOnPauseAllowed()) {
- showToastAndLog("This test must be completed without going onPause");
+ showToastAndLog("This test must be completed without pausing the app");
// Do not allow the test to continue if it loses foreground. Testers must start over.
// 1) This is to avoid any potential change to the current enrollment / biometric state.
// 2) The authentication UI must not affect the caller's activity lifecycle.
@@ -85,19 +84,7 @@
mCurrentlyEnrolling = false;
if (requestCode == REQUEST_ENROLL_WHEN_NONE_ENROLLED) {
- if (resultCode == RESULT_OK) {
- startBiometricEnroll(REQUEST_ENROLL_WHEN_ENROLLED, mRequestedStrength);
- } else {
- showToastAndLog("Unexpected result when requesting enrollment when not enrolled"
- + " yet: " + resultCode);
- }
- } else if (requestCode == REQUEST_ENROLL_WHEN_ENROLLED) {
- if (resultCode == RESULT_CANCELED) {
- onBiometricEnrollFinished();
- } else {
- showToastAndLog("Unexpected result when requesting enrollment when already"
- + " enrolled: " + resultCode);
- }
+ onBiometricEnrollFinished();
}
}
@@ -396,4 +383,19 @@
});
}
+ void testNegativeButtonCallback(int allowedAuthenticators, Runnable successRunnable) {
+ final BiometricPrompt.Builder builder = new BiometricPrompt.Builder(this);
+ builder.setTitle("Press the negative button");
+ builder.setAllowedAuthenticators(allowedAuthenticators);
+ builder.setNegativeButton("Press me", mExecutor, (dialog1, which1) -> {
+ mExecutor.execute(successRunnable);
+ });
+
+ final BiometricPrompt prompt = builder.build();
+ prompt.authenticate(new CancellationSignal(), mExecutor,
+ new AuthenticationCallback() {
+ // Do nothing
+ });
+ }
+
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractUserAuthenticationCipherTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractUserAuthenticationCipherTest.java
new file mode 100644
index 0000000..dff9023
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractUserAuthenticationCipherTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.biometrics;
+
+import android.hardware.biometrics.BiometricPrompt;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+
+public abstract class AbstractUserAuthenticationCipherTest extends AbstractUserAuthenticationTest {
+ private Cipher mCipher;
+
+ @Override
+ void createUserAuthenticationKey(String keyName, int timeout, int authType,
+ boolean useStrongBox) throws Exception {
+ KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
+ keyName, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT);
+ builder.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
+ .setUserAuthenticationRequired(true)
+ .setUserAuthenticationParameters(timeout, authType)
+ .setIsStrongBoxBacked(useStrongBox);
+
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(
+ KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
+ keyGenerator.init(builder.build());
+ keyGenerator.generateKey();
+ }
+
+ @Override
+ void initializeKeystoreOperation(String keyName) throws Exception {
+ mCipher = Utils.initCipher(keyName);
+ }
+
+ @Override
+ BiometricPrompt.CryptoObject getCryptoObject() {
+ return new BiometricPrompt.CryptoObject(mCipher);
+ }
+
+ @Override
+ void doKeystoreOperation(byte[] payload) throws Exception {
+ try {
+ Utils.doEncrypt(mCipher, payload);
+ } finally {
+ mCipher = null;
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractUserAuthenticationMacTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractUserAuthenticationMacTest.java
new file mode 100644
index 0000000..638ba80
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractUserAuthenticationMacTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.biometrics;
+
+import android.hardware.biometrics.BiometricPrompt;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+
+public abstract class AbstractUserAuthenticationMacTest extends AbstractUserAuthenticationTest {
+ private Mac mMac;
+
+ @Override
+ void createUserAuthenticationKey(String keyName, int timeout, int authType,
+ boolean useStrongBox) throws Exception {
+ KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
+ keyName, KeyProperties.PURPOSE_SIGN);
+ builder.setUserAuthenticationRequired(true)
+ .setIsStrongBoxBacked(useStrongBox)
+ .setUserAuthenticationParameters(timeout, authType);
+
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(
+ KeyProperties.KEY_ALGORITHM_HMAC_SHA256, "AndroidKeyStore");
+ keyGenerator.init(builder.build());
+ keyGenerator.generateKey();
+ }
+
+ @Override
+ void initializeKeystoreOperation(String keyName) throws Exception {
+ mMac = Utils.initMac(keyName);
+ }
+
+ @Override
+ BiometricPrompt.CryptoObject getCryptoObject() {
+ return new BiometricPrompt.CryptoObject(mMac);
+ }
+
+ @Override
+ void doKeystoreOperation(byte[] payload) throws Exception {
+ try {
+ mMac.doFinal(payload);
+ } finally {
+ mMac = null;
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractUserAuthenticationSignatureTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractUserAuthenticationSignatureTest.java
new file mode 100644
index 0000000..4708620
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractUserAuthenticationSignatureTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.biometrics;
+
+import android.hardware.biometrics.BiometricPrompt;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+
+import java.security.KeyPairGenerator;
+import java.security.Signature;
+import java.security.spec.ECGenParameterSpec;
+
+public abstract class AbstractUserAuthenticationSignatureTest
+ extends AbstractUserAuthenticationTest {
+ private Signature mSignature;
+
+ @Override
+ void createUserAuthenticationKey(String keyName, int timeout, int authType,
+ boolean useStrongBox) throws Exception {
+ KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
+ keyName, KeyProperties.PURPOSE_SIGN);
+ builder.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
+ .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
+ .setUserAuthenticationRequired(true)
+ .setIsStrongBoxBacked(useStrongBox)
+ .setUserAuthenticationParameters(timeout, authType);
+
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
+ KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
+ keyPairGenerator.initialize(builder.build());
+ keyPairGenerator.generateKeyPair();
+ }
+
+ @Override
+ void initializeKeystoreOperation(String keyName) throws Exception {
+ mSignature = Utils.initSignature(keyName);
+ }
+
+ @Override
+ BiometricPrompt.CryptoObject getCryptoObject() {
+ return new BiometricPrompt.CryptoObject(mSignature);
+ }
+
+ @Override
+ void doKeystoreOperation(byte[] payload) throws Exception {
+ try {
+ Utils.doSign(mSignature, payload);
+ } finally {
+ mSignature = null;
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractUserAuthenticationTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractUserAuthenticationTest.java
new file mode 100644
index 0000000..c6e3cb7
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/AbstractUserAuthenticationTest.java
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.biometrics;
+
+import android.content.pm.PackageManager;
+import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.BiometricManager.Authenticators;
+import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback;
+import android.hardware.biometrics.BiometricPrompt.AuthenticationResult;
+import android.hardware.biometrics.BiometricPrompt.CryptoObject;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.Looper;
+import android.security.keystore.KeyProperties;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import java.util.concurrent.Executor;
+
+/**
+ * This is the abstract base class for testing/checking that keys generated via
+ * setUserAuthenticationParameters(timeout, CREDENTIAL) can be unlocked (or not) depending on the
+ * type of authenticator used. This tests various combinations of
+ * {timeout, authenticator, strongbox}. Extending classes currently consist of:
+ * {@link UserAuthenticationCredentialCipherTest} for testing {@link javax.crypto.Cipher}.
+ */
+public abstract class AbstractUserAuthenticationTest extends PassFailButtons.Activity {
+
+ private static final String TAG = "AbstractUserAuthenticationCredentialTest";
+
+ private static final int TIMED_KEY_DURATION = 1;
+ private static final byte[] PAYLOAD = new byte[] {1, 2, 3, 4, 5, 6};
+
+ abstract class ExpectedResults {
+ abstract boolean shouldCredentialUnlockPerUseKey();
+ abstract boolean shouldCredentialUnlockTimedKey();
+ abstract boolean shouldBiometricUnlockPerUseKey();
+ abstract boolean shouldBiometricUnlockTimedKey();
+ }
+
+ /**
+ * @return Log tag.
+ */
+ abstract String getTag();
+
+ abstract int getInstructionsResourceId();
+
+ abstract void createUserAuthenticationKey(String keyName, int timeout, int authType,
+ boolean useStrongBox) throws Exception;
+
+ abstract ExpectedResults getExpectedResults();
+
+ /**
+ * @return The authenticators allowed to unlock the cryptographic operation. See
+ * {@link KeyProperties#AUTH_DEVICE_CREDENTIAL} and {@link KeyProperties#AUTH_BIOMETRIC_STRONG}
+ */
+ abstract int getKeyAuthenticators();
+
+ /**
+ * Due to the differences between auth-per-use operations and time-based operations, the
+ * initialization of the keystore operation may be before or after authentication. Initializing
+ * the operation will require the extending class to store it somewhere for later use. This
+ * cached operation should be cleared after {@link #doKeystoreOperation(byte[])} is invoked.
+ */
+ abstract void initializeKeystoreOperation(String keyName) throws Exception;
+
+ /**
+ * This method is used only for auth-per-use keys. This requires the keystore operation to
+ * already be initialized and cached within the extending class.
+ */
+ abstract CryptoObject getCryptoObject();
+
+ /**
+ * Attempts to perform the initialized/cached keystore operation. This method must guarantee
+ * that the cached operation is null after it's run (both passing and failing cases).
+ */
+ abstract void doKeystoreOperation(byte[] payload) throws Exception;
+
+ protected final Handler mHandler = new Handler(Looper.getMainLooper());
+ protected final Executor mExecutor = mHandler::post;
+
+ private BiometricManager mBiometricManager;
+
+ private Button mCredentialPerUseButton;
+ private Button mCredentialTimedButton;
+ private Button mBiometricPerUseButton;
+ private Button mBiometricTimedButton;
+ private Button mCredentialPerUseButton_strongbox;
+ private Button mCredentialTimedButton_strongbox;
+ private Button mBiometricPerUseButton_strongbox;
+ private Button mBiometricTimedButton_strongbox;
+
+ private Button[] mButtons;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.biometric_test_user_authentication_credential_tests);
+ setPassFailButtonClickListeners();
+ getPassButton().setEnabled(false);
+
+ mBiometricManager = getSystemService(BiometricManager.class);
+
+ TextView instructionsText = findViewById(R.id.instructions);
+ instructionsText.setText(getInstructionsResourceId());
+
+ mCredentialPerUseButton = findViewById(R.id.per_use_auth_with_credential);
+ mCredentialTimedButton = findViewById(R.id.duration_auth_with_credential);
+ mBiometricPerUseButton = findViewById(R.id.per_use_auth_with_biometric);
+ mBiometricTimedButton = findViewById(R.id.duration_auth_with_biometric);
+ mCredentialPerUseButton_strongbox
+ = findViewById(R.id.per_use_auth_with_credential_strongbox);
+ mCredentialTimedButton_strongbox
+ = findViewById(R.id.duration_auth_with_credential_strongbox);
+ mBiometricPerUseButton_strongbox
+ = findViewById(R.id.per_use_auth_with_biometric_strongbox);
+ mBiometricTimedButton_strongbox
+ = findViewById(R.id.duration_auth_with_biometric_strongbox);
+
+ mButtons = new Button[] {
+ mCredentialPerUseButton,
+ mCredentialTimedButton,
+ mBiometricPerUseButton,
+ mBiometricTimedButton,
+ mCredentialPerUseButton_strongbox,
+ mCredentialTimedButton_strongbox,
+ mBiometricPerUseButton_strongbox,
+ mBiometricTimedButton_strongbox
+ };
+
+ final boolean hasStrongBox = getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_STRONGBOX_KEYSTORE);
+ final boolean noStrongBiometricHardware =
+ mBiometricManager.canAuthenticate(Authenticators.BIOMETRIC_STRONG)
+ == BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE;
+
+ if (!hasStrongBox) {
+ mCredentialPerUseButton_strongbox.setVisibility(View.GONE);
+ mCredentialTimedButton_strongbox.setVisibility(View.GONE);
+ mBiometricPerUseButton_strongbox.setVisibility(View.GONE);
+ mBiometricTimedButton_strongbox.setVisibility(View.GONE);
+ }
+
+ if (noStrongBiometricHardware) {
+ mBiometricPerUseButton.setVisibility(View.GONE);
+ mBiometricTimedButton.setVisibility(View.GONE);
+ mBiometricPerUseButton_strongbox.setVisibility(View.GONE);
+ mBiometricTimedButton_strongbox.setVisibility(View.GONE);
+ }
+
+ // No strongbox
+
+ mCredentialPerUseButton.setOnClickListener((view) -> {
+ testCredentialBoundEncryption("key1",
+ 0 /* timeout */,
+ false /* useStrongBox */,
+ Authenticators.DEVICE_CREDENTIAL,
+ getExpectedResults().shouldCredentialUnlockPerUseKey(),
+ PAYLOAD,
+ mCredentialPerUseButton);
+ });
+
+ mCredentialTimedButton.setOnClickListener((view) -> {
+ testCredentialBoundEncryption("key2",
+ TIMED_KEY_DURATION /* timeout */,
+ false /* useStrongBox */,
+ Authenticators.DEVICE_CREDENTIAL,
+ getExpectedResults().shouldCredentialUnlockTimedKey(),
+ PAYLOAD,
+ mCredentialTimedButton);
+ });
+
+ mBiometricPerUseButton.setOnClickListener((view) -> {
+ testCredentialBoundEncryption("key3",
+ 0 /* timeout */,
+ false /* useStrongBox */,
+ Authenticators.BIOMETRIC_STRONG,
+ getExpectedResults().shouldBiometricUnlockPerUseKey(),
+ PAYLOAD,
+ mBiometricPerUseButton);
+ });
+
+ mBiometricTimedButton.setOnClickListener((view) -> {
+ testCredentialBoundEncryption("key4",
+ TIMED_KEY_DURATION /* timeout */,
+ false /* useStrongBox */,
+ Authenticators.BIOMETRIC_STRONG,
+ getExpectedResults().shouldBiometricUnlockTimedKey(),
+ PAYLOAD,
+ mBiometricTimedButton);
+ });
+
+ // Strongbox
+
+ mCredentialPerUseButton_strongbox.setOnClickListener((view) -> {
+ testCredentialBoundEncryption("key5",
+ 0 /* timeout */,
+ true /* useStrongBox */,
+ Authenticators.DEVICE_CREDENTIAL,
+ getExpectedResults().shouldCredentialUnlockPerUseKey(),
+ PAYLOAD,
+ mCredentialPerUseButton_strongbox);
+ });
+
+ mCredentialTimedButton_strongbox.setOnClickListener((view) -> {
+ testCredentialBoundEncryption("key6",
+ TIMED_KEY_DURATION /* timeout */,
+ true /* useStrongBox */,
+ Authenticators.DEVICE_CREDENTIAL,
+ getExpectedResults().shouldCredentialUnlockTimedKey(),
+ PAYLOAD,
+ mCredentialTimedButton_strongbox);
+ });
+
+ mBiometricPerUseButton_strongbox.setOnClickListener((view) -> {
+ testCredentialBoundEncryption("key7",
+ 0 /* timeout */,
+ true /* useStrongBox */,
+ Authenticators.BIOMETRIC_STRONG,
+ getExpectedResults().shouldBiometricUnlockPerUseKey(),
+ PAYLOAD,
+ mBiometricPerUseButton_strongbox);
+ });
+
+ mBiometricTimedButton_strongbox.setOnClickListener((view) -> {
+ testCredentialBoundEncryption("key8",
+ TIMED_KEY_DURATION /* timeout */,
+ true /* useStrongBox */,
+ Authenticators.BIOMETRIC_STRONG,
+ getExpectedResults().shouldBiometricUnlockTimedKey(),
+ PAYLOAD,
+ mBiometricTimedButton_strongbox);
+ });
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ if (!getPassButton().isEnabled()) {
+ // This test is affected by PIN/Pattern/Password authentication. So, do not allow
+ // the test to complete if the user leaves the app (lockscreen, etc will affect this
+ // test).
+ showToastAndLog("This test must be completed without pausing the app");
+ finish();
+ }
+ }
+
+ private void testCredentialBoundEncryption(String keyName, int timeout, boolean useStrongBox,
+ int allowedAuthenticators, boolean shouldKeyBeUsable, byte[] payload,
+ Button testButton) {
+
+ final boolean requiresCryptoObject = timeout == 0;
+
+ final int canAuthenticate = mBiometricManager.canAuthenticate(allowedAuthenticators);
+ if (canAuthenticate != BiometricManager.BIOMETRIC_SUCCESS) {
+ showToastAndLog("Please ensure you can authenticate with the following authenticators: "
+ + allowedAuthenticators + " Result: " + canAuthenticate);
+ return;
+ }
+
+ try {
+ if (mBiometricManager.canAuthenticate(allowedAuthenticators)
+ != BiometricManager.BIOMETRIC_SUCCESS) {
+ showToastAndLog("Please ensure you have the authenticator combination set up: "
+ + allowedAuthenticators);
+ return;
+ }
+
+ createUserAuthenticationKey(keyName, timeout, getKeyAuthenticators(), useStrongBox);
+
+ CryptoObject crypto;
+
+ // For auth-per-use keys, the keystore operation needs to be initialized before
+ // authenticating, so we can wrap it into a CryptoObject. For time-based keys, the
+ // keystore operation can only be initialized after authentication has occurred.
+ if (requiresCryptoObject) {
+ initializeKeystoreOperation(keyName);
+ crypto = getCryptoObject();
+ } else {
+ crypto = null;
+ }
+
+ final BiometricPrompt.Builder builder = new BiometricPrompt.Builder(this);
+ builder.setTitle("Please authenticate");
+ builder.setAllowedAuthenticators(allowedAuthenticators);
+
+ // The BiometricPrompt API requires a negative button if credential is not allowed.
+ if ((allowedAuthenticators & Authenticators.DEVICE_CREDENTIAL) == 0) {
+ builder.setNegativeButton("Cancel", mExecutor, (dialog, which) -> {
+ // Do nothing
+ });
+ }
+
+ final AuthenticationCallback callback = new AuthenticationCallback() {
+ @Override
+ public void onAuthenticationSucceeded(AuthenticationResult result) {
+ // Key generation / initialization can depend on past authentication. Ensure
+ // that the user has not authenticated within n+1 seconds before allowing the
+ // next test to start.
+ disableTestsForFewSeconds();
+
+ Exception exception = null;
+ boolean keyUsed;
+ try {
+ if (!requiresCryptoObject) {
+ initializeKeystoreOperation(keyName);
+ }
+
+ doKeystoreOperation(payload);
+
+ keyUsed = true;
+ } catch (Exception e) {
+ keyUsed = false;
+ exception = e;
+ }
+
+ if (keyUsed != shouldKeyBeUsable) {
+ showToastAndLog("Test failed. shouldKeyBeUsable: " + shouldKeyBeUsable
+ + " keyUsed: " + keyUsed + " Exception: " + exception);
+ if (exception != null) {
+ exception.printStackTrace();
+ }
+ } else {
+ // Set them to invisible, because for this test, disabled actually means
+ // something else. For the initialization of some keys, its success/failure
+ // can depend on if the user has entered their credential within the last
+ // "n" seconds. Those tests need to be disabled until "n" has passed.
+ testButton.setVisibility(View.INVISIBLE);
+ }
+ updatePassButton();
+ }
+ };
+
+
+ final BiometricPrompt prompt = builder.build();
+
+ if (requiresCryptoObject) {
+ prompt.authenticate(crypto, new CancellationSignal(), mExecutor, callback);
+ } else {
+ prompt.authenticate(new CancellationSignal(), mExecutor, callback);
+ }
+
+ } catch (Exception e) {
+ showToastAndLog("Failed during Crypto test: " + e);
+ e.printStackTrace();
+ }
+ }
+
+ private void disableTestsForFewSeconds() {
+ for (Button b : mButtons) {
+ b.setEnabled(false);
+ }
+
+ mHandler.postDelayed(() -> {
+ for (Button b : mButtons) {
+ b.setEnabled(true);
+ }
+ }, TIMED_KEY_DURATION * 1000 + 1000);
+ }
+
+ private void updatePassButton() {
+ for (Button b : mButtons) {
+ if (b.getVisibility() == View.VISIBLE) {
+ return;
+ }
+ }
+
+ showToastAndLog("All tests passed");
+ getPassButton().setEnabled(true);
+ }
+
+ private void showToastAndLog(String s) {
+ Log.d(getTag(), s);
+ Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricStrongTests.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricStrongTests.java
index 079c56f..0d54cbd 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricStrongTests.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricStrongTests.java
@@ -75,6 +75,7 @@
private Button mAuthenticateCredential3Button; // setAllowedAuthenticators(CREDENTIAL|BIOMETRIC)
private Button mCheckInvalidInputsButton;
private Button mRejectThenAuthenticateButton;
+ private Button mNegativeButtonButton;
private Button mKeyInvalidatedButton;
private boolean mAuthenticateWithoutStrongBoxPassed;
@@ -85,6 +86,7 @@
private boolean mAuthenticateCredential3Passed;
private boolean mCheckInvalidInputsPassed;
private boolean mRejectThenAuthenticatePassed;
+ private boolean mNegativeButtonPassed;
private boolean mKeyInvalidatedStrongboxPassed;
private boolean mKeyInvalidatedNoStrongboxPassed;
@@ -108,6 +110,7 @@
mAuthenticateCredential3Button.setEnabled(true);
mCheckInvalidInputsButton.setEnabled(true);
mRejectThenAuthenticateButton.setEnabled(true);
+ mNegativeButtonButton.setEnabled(true);
} else {
showToastAndLog("Unexpected result after enrollment: " + biometricStatus);
}
@@ -132,6 +135,7 @@
R.id.authenticate_credential_setAllowedAuthenticators_credential_button);
mCheckInvalidInputsButton = findViewById(R.id.authenticate_invalid_inputs);
mRejectThenAuthenticateButton = findViewById(R.id.authenticate_reject_first);
+ mNegativeButtonButton = findViewById(R.id.authenticate_negative_button_button);
mKeyInvalidatedButton = findViewById(R.id.authenticate_key_invalidated_button);
mHasStrongBox = getPackageManager()
@@ -210,6 +214,14 @@
});
});
+ mNegativeButtonButton.setOnClickListener((view) -> {
+ testNegativeButtonCallback(Authenticators.BIOMETRIC_STRONG, () -> {
+ mNegativeButtonPassed = true;
+ mNegativeButtonButton.setEnabled(false);
+ updatePassButton();
+ });
+ });
+
mKeyInvalidatedButton.setOnClickListener((view) -> {
Utils.showInstructionDialog(this,
R.string.biometric_test_strong_authenticate_invalidated_instruction_title,
@@ -254,7 +266,8 @@
if (mAuthenticateWithoutStrongBoxPassed && mAuthenticateWithStrongBoxPassed
&& mAuthenticateUIPassed && mAuthenticateCredential1Passed
&& mAuthenticateCredential2Passed && mAuthenticateCredential3Passed
- && mCheckInvalidInputsPassed && mRejectThenAuthenticatePassed) {
+ && mCheckInvalidInputsPassed && mRejectThenAuthenticatePassed
+ && mNegativeButtonPassed) {
return true;
}
@@ -345,7 +358,8 @@
if (mAuthenticateWithoutStrongBoxPassed && mAuthenticateWithStrongBoxPassed
&& mAuthenticateUIPassed && mAuthenticateCredential1Passed
&& mAuthenticateCredential2Passed && mAuthenticateCredential3Passed
- && mCheckInvalidInputsPassed && mRejectThenAuthenticatePassed) {
+ && mCheckInvalidInputsPassed && mRejectThenAuthenticatePassed
+ && mNegativeButtonPassed) {
if (!mKeyInvalidatedStrongboxPassed || !mKeyInvalidatedNoStrongboxPassed) {
mKeyInvalidatedButton.setEnabled(true);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricWeakTests.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricWeakTests.java
index 3ce9ccb..3cac14b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricWeakTests.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricWeakTests.java
@@ -56,6 +56,7 @@
private Button mAuthenticateCredential3Button; // setAllowedAuthenticators(CREDENTIAL|BIOMETRIC)
private Button mCheckInvalidInputsButton;
private Button mRejectThenAuthenticateButton;
+ private Button mNegativeButtonButton;
private boolean mAuthenticatePassed;
private boolean mAuthenticateCredential1Passed;
@@ -63,6 +64,7 @@
private boolean mAuthenticateCredential3Passed;
private boolean mCheckInvalidInputsPassed;
private boolean mRejectThenAuthenticatePassed;
+ private boolean mNegativeButtonPassed;
@Override
protected String getTag() {
@@ -86,6 +88,7 @@
R.id.authenticate_credential_setAllowedAuthenticators_credential_button);
mCheckInvalidInputsButton = findViewById(R.id.authenticate_invalid_inputs);
mRejectThenAuthenticateButton = findViewById(R.id.authenticate_reject_first);
+ mNegativeButtonButton = findViewById(R.id.authenticate_negative_button_button);
mEnrollButton.setOnClickListener((view) -> {
checkAndEnroll(mEnrollButton, Authenticators.BIOMETRIC_WEAK,
@@ -181,6 +184,14 @@
updatePassButton();
});
});
+
+ mNegativeButtonButton.setOnClickListener((view) -> {
+ testNegativeButtonCallback(Authenticators.BIOMETRIC_WEAK, () -> {
+ mNegativeButtonPassed = true;
+ mNegativeButtonButton.setEnabled(false);
+ updatePassButton();
+ });
+ });
}
@Override
@@ -200,7 +211,8 @@
private void updatePassButton() {
if (mAuthenticatePassed && mAuthenticateCredential1Passed
&& mAuthenticateCredential2Passed && mAuthenticateCredential3Passed
- && mCheckInvalidInputsPassed && mRejectThenAuthenticatePassed) {
+ && mCheckInvalidInputsPassed && mRejectThenAuthenticatePassed
+ && mNegativeButtonPassed) {
showToastAndLog("All tests passed");
getPassButton().setEnabled(true);
}
@@ -219,6 +231,7 @@
mAuthenticateCredential3Button.setEnabled(true);
mCheckInvalidInputsButton.setEnabled(true);
mRejectThenAuthenticateButton.setEnabled(true);
+ mNegativeButtonButton.setEnabled(true);
} else {
showToastAndLog("Unexpected result after enrollment: " + biometricStatus);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/CredentialEnrolledTests.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/CredentialEnrolledTests.java
index 0186ecb..9b07146 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/CredentialEnrolledTests.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/CredentialEnrolledTests.java
@@ -25,11 +25,8 @@
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
-import android.util.Log;
import android.widget.Button;
-import android.widget.Toast;
-import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
import java.util.concurrent.Executor;
@@ -41,8 +38,7 @@
public class CredentialEnrolledTests extends AbstractBaseTest {
private static final String TAG = "CredentialEnrolledTests";
- private static final int REQUEST_ENROLL_WHEN_NONE_ENROLLED = 1;
- private static final int REQUEST_ENROLL_WHEN_ENROLLED = 2;
+ private static final int REQUEST_ENROLL = 1;
private Button mEnrollButton;
private Button mBiometricManagerButton;
@@ -79,7 +75,7 @@
return;
}
- requestCredentialEnrollment(REQUEST_ENROLL_WHEN_NONE_ENROLLED);
+ requestCredentialEnrollment(REQUEST_ENROLL);
});
// Test BiometricManager#canAuthenticate(DEVICE_CREDENTIAL)
@@ -189,31 +185,19 @@
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == REQUEST_ENROLL_WHEN_NONE_ENROLLED) {
- if (resultCode == RESULT_OK) {
- final BiometricManager bm = getSystemService(BiometricManager.class);
- final int result = bm.canAuthenticate(Authenticators.DEVICE_CREDENTIAL);
- if (result == BiometricManager.BIOMETRIC_SUCCESS) {
- // Request enrollment one more time. Ensure that we receive RESULT_CANCELED
- requestCredentialEnrollment(REQUEST_ENROLL_WHEN_ENROLLED);
- } else {
- showToastAndLog("Unexpected result: " + result + ". Please ensure that tapping"
- + " the button sends you to credential enrollment, and that you have"
- + " enrolled a credential.");
- }
- } else {
- showToastAndLog("Unexpected result after enroll: " + resultCode);
- }
- } else if (requestCode == REQUEST_ENROLL_WHEN_ENROLLED) {
- if (resultCode == RESULT_CANCELED) {
+ if (requestCode == REQUEST_ENROLL) {
+ final BiometricManager bm = getSystemService(BiometricManager.class);
+ final int result = bm.canAuthenticate(Authenticators.DEVICE_CREDENTIAL);
+ if (result == BiometricManager.BIOMETRIC_SUCCESS) {
mEnrollPass = true;
mEnrollButton.setEnabled(false);
mBiometricManagerButton.setEnabled(true);
mBPSetAllowedAuthenticatorsButton.setEnabled(true);
mBPSetDeviceCredentialAllowedButton.setEnabled(true);
} else {
- showToastAndLog("Unexpected result when requesting enrolling with"
- + " pre-existing credential: " + resultCode);
+ showToastAndLog("Unexpected result: " + result + ". Please ensure that tapping"
+ + " the button sends you to credential enrollment, and that you have"
+ + " enrolled a credential.");
}
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricCipherTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricCipherTest.java
new file mode 100644
index 0000000..e73c902
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricCipherTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.biometrics;
+
+import android.security.keystore.KeyProperties;
+
+import com.android.cts.verifier.R;
+
+public class UserAuthenticationBiometricCipherTest extends AbstractUserAuthenticationCipherTest {
+
+ private static final String TAG = "UserAuthenticationBiometricCipherTest";
+
+ @Override
+ String getTag() {
+ return TAG;
+ }
+
+ @Override
+ int getInstructionsResourceId() {
+ return R.string.biometric_test_set_user_authentication_biometric_instructions;
+ }
+
+ @Override
+ ExpectedResults getExpectedResults() {
+ return new ExpectedResults() {
+ @Override
+ boolean shouldCredentialUnlockPerUseKey() {
+ return false;
+ }
+
+ @Override
+ boolean shouldCredentialUnlockTimedKey() {
+ return false;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockPerUseKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockTimedKey() {
+ return true;
+ }
+ };
+ }
+
+ @Override
+ int getKeyAuthenticators() {
+ return KeyProperties.AUTH_BIOMETRIC_STRONG;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricMacTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricMacTest.java
new file mode 100644
index 0000000..6e7c8ef
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricMacTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.biometrics;
+
+import android.security.keystore.KeyProperties;
+
+import com.android.cts.verifier.R;
+
+public class UserAuthenticationBiometricMacTest extends AbstractUserAuthenticationMacTest {
+ private static final String TAG = "UserAuthenticationBiometricMacTest";
+
+ @Override
+ String getTag() {
+ return TAG;
+ }
+
+ @Override
+ int getInstructionsResourceId() {
+ return R.string.biometric_test_set_user_authentication_biometric_instructions;
+ }
+
+ @Override
+ ExpectedResults getExpectedResults() {
+ return new ExpectedResults() {
+ @Override
+ boolean shouldCredentialUnlockPerUseKey() {
+ return false;
+ }
+
+ @Override
+ boolean shouldCredentialUnlockTimedKey() {
+ return false;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockPerUseKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockTimedKey() {
+ return true;
+ }
+ };
+ }
+
+ @Override
+ int getKeyAuthenticators() {
+ return KeyProperties.AUTH_BIOMETRIC_STRONG;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricOrCredentialCipherTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricOrCredentialCipherTest.java
new file mode 100644
index 0000000..03f4ff6
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricOrCredentialCipherTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.biometrics;
+
+import android.security.keystore.KeyProperties;
+
+import com.android.cts.verifier.R;
+
+public class UserAuthenticationBiometricOrCredentialCipherTest
+ extends AbstractUserAuthenticationCipherTest {
+
+ private static final String TAG = "UserAuthenticationBiometricOrCredentialCipherTest";
+
+ @Override
+ String getTag() {
+ return TAG;
+ }
+
+ @Override
+ int getInstructionsResourceId() {
+ return R.string.biometric_test_set_user_authentication_biometric_or_credential_instructions;
+ }
+
+ @Override
+ ExpectedResults getExpectedResults() {
+ return new ExpectedResults() {
+ @Override
+ boolean shouldCredentialUnlockPerUseKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldCredentialUnlockTimedKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockPerUseKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockTimedKey() {
+ return true;
+ }
+ };
+ }
+
+ @Override
+ int getKeyAuthenticators() {
+ return KeyProperties.AUTH_DEVICE_CREDENTIAL | KeyProperties.AUTH_BIOMETRIC_STRONG;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricOrCredentialMacTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricOrCredentialMacTest.java
new file mode 100644
index 0000000..8657b8b
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricOrCredentialMacTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.biometrics;
+
+import android.security.keystore.KeyProperties;
+
+import com.android.cts.verifier.R;
+
+public class UserAuthenticationBiometricOrCredentialMacTest
+ extends AbstractUserAuthenticationMacTest {
+ private static final String TAG = "UserAuthenticationBiometricOrCredentialMacTest";
+ @Override
+ String getTag() {
+ return TAG;
+ }
+
+ @Override
+ int getInstructionsResourceId() {
+ return R.string.biometric_test_set_user_authentication_biometric_or_credential_instructions;
+ }
+
+ @Override
+ ExpectedResults getExpectedResults() {
+ return new ExpectedResults() {
+ @Override
+ boolean shouldCredentialUnlockPerUseKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldCredentialUnlockTimedKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockPerUseKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockTimedKey() {
+ return true;
+ }
+ };
+ }
+
+ @Override
+ int getKeyAuthenticators() {
+ return KeyProperties.AUTH_DEVICE_CREDENTIAL | KeyProperties.AUTH_BIOMETRIC_STRONG;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricOrCredentialSignatureTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricOrCredentialSignatureTest.java
new file mode 100644
index 0000000..a88b081
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricOrCredentialSignatureTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.biometrics;
+
+import android.security.keystore.KeyProperties;
+
+import com.android.cts.verifier.R;
+
+public class UserAuthenticationBiometricOrCredentialSignatureTest
+ extends AbstractUserAuthenticationSignatureTest {
+ private static final String TAG = "UserAuthenticationBiometricOrCredentialSignatureTest";
+
+ @Override
+ String getTag() {
+ return TAG;
+ }
+
+ @Override
+ int getInstructionsResourceId() {
+ return R.string.biometric_test_set_user_authentication_biometric_or_credential_instructions;
+ }
+
+ @Override
+ ExpectedResults getExpectedResults() {
+ return new ExpectedResults() {
+ @Override
+ boolean shouldCredentialUnlockPerUseKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldCredentialUnlockTimedKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockPerUseKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockTimedKey() {
+ return true;
+ }
+ };
+ }
+
+ @Override
+ int getKeyAuthenticators() {
+ return KeyProperties.AUTH_DEVICE_CREDENTIAL | KeyProperties.AUTH_BIOMETRIC_STRONG;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricSignatureTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricSignatureTest.java
new file mode 100644
index 0000000..8e8a8b2
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationBiometricSignatureTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.biometrics;
+
+import android.security.keystore.KeyProperties;
+
+import com.android.cts.verifier.R;
+
+public class UserAuthenticationBiometricSignatureTest
+ extends AbstractUserAuthenticationSignatureTest {
+ private static final String TAG = "UserAuthenticationBiometricSignatureTest";
+
+ @Override
+ String getTag() {
+ return TAG;
+ }
+
+ @Override
+ int getInstructionsResourceId() {
+ return R.string.biometric_test_set_user_authentication_biometric_instructions;
+ }
+
+ @Override
+ ExpectedResults getExpectedResults() {
+ return new ExpectedResults() {
+ @Override
+ boolean shouldCredentialUnlockPerUseKey() {
+ return false;
+ }
+
+ @Override
+ boolean shouldCredentialUnlockTimedKey() {
+ return false;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockPerUseKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockTimedKey() {
+ return true;
+ }
+ };
+ }
+
+ @Override
+ int getKeyAuthenticators() {
+ return KeyProperties.AUTH_BIOMETRIC_STRONG;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationCredentialCipherTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationCredentialCipherTest.java
new file mode 100644
index 0000000..ccdee1a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationCredentialCipherTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.biometrics;
+
+import android.security.keystore.KeyProperties;
+
+import com.android.cts.verifier.R;
+
+public class UserAuthenticationCredentialCipherTest extends AbstractUserAuthenticationCipherTest {
+
+ private static final String TAG = "UserAuthenticationCredentialCipherTest";
+
+ @Override
+ String getTag() {
+ return TAG;
+ }
+
+ @Override
+ int getInstructionsResourceId() {
+ return R.string.biometric_test_set_user_authentication_credential_instructions;
+ }
+
+ @Override
+ ExpectedResults getExpectedResults() {
+ return new ExpectedResults() {
+ @Override
+ boolean shouldCredentialUnlockPerUseKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldCredentialUnlockTimedKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockPerUseKey() {
+ return false;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockTimedKey() {
+ return false;
+ }
+ };
+ }
+
+ @Override
+ int getKeyAuthenticators() {
+ return KeyProperties.AUTH_DEVICE_CREDENTIAL;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationCredentialMacTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationCredentialMacTest.java
new file mode 100644
index 0000000..9c4a63d
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationCredentialMacTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.biometrics;
+
+import android.security.keystore.KeyProperties;
+
+import com.android.cts.verifier.R;
+
+public class UserAuthenticationCredentialMacTest extends AbstractUserAuthenticationMacTest {
+ private static final String TAG = "UserAuthenticationCredentialMacTest";
+
+ @Override
+ String getTag() {
+ return TAG;
+ }
+
+ @Override
+ int getInstructionsResourceId() {
+ return R.string.biometric_test_set_user_authentication_credential_instructions;
+ }
+
+ @Override
+ ExpectedResults getExpectedResults() {
+ return new ExpectedResults() {
+ @Override
+ boolean shouldCredentialUnlockPerUseKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldCredentialUnlockTimedKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockPerUseKey() {
+ return false;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockTimedKey() {
+ return false;
+ }
+ };
+ }
+
+ @Override
+ int getKeyAuthenticators() {
+ return KeyProperties.AUTH_DEVICE_CREDENTIAL;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationCredentialSignatureTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationCredentialSignatureTest.java
new file mode 100644
index 0000000..16487ea
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/UserAuthenticationCredentialSignatureTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.biometrics;
+
+import android.security.keystore.KeyProperties;
+
+import com.android.cts.verifier.R;
+
+public class UserAuthenticationCredentialSignatureTest
+ extends AbstractUserAuthenticationSignatureTest {
+ private static final String TAG = "UserAuthenticationCredentialSignatureTest";
+
+ @Override
+ String getTag() {
+ return TAG;
+ }
+
+ @Override
+ int getInstructionsResourceId() {
+ return R.string.biometric_test_set_user_authentication_credential_instructions;
+ }
+
+ @Override
+ ExpectedResults getExpectedResults() {
+ return new ExpectedResults() {
+ @Override
+ boolean shouldCredentialUnlockPerUseKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldCredentialUnlockTimedKey() {
+ return true;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockPerUseKey() {
+ return false;
+ }
+
+ @Override
+ boolean shouldBiometricUnlockTimedKey() {
+ return false;
+ }
+ };
+ }
+
+ @Override
+ int getKeyAuthenticators() {
+ return KeyProperties.AUTH_DEVICE_CREDENTIAL;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java
index 3cce889..5d8db94 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java
@@ -28,11 +28,16 @@
import android.widget.LinearLayout;
import android.widget.Toast;
+import java.security.KeyPair;
import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
import javax.crypto.SecretKey;
public class Utils {
@@ -88,10 +93,42 @@
return cipher;
}
+ static Signature initSignature(String keyName) throws Exception {
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+
+ KeyStore.Entry entry = keyStore.getEntry(keyName, null);
+
+ PrivateKey privateKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();
+
+ // TODO: This can be used to verify signature
+ // PublicKey publicKey = keyStore.getCertificate(keyName).getPublicKey();
+
+ Signature signature = Signature.getInstance("SHA256withECDSA");
+ signature.initSign(privateKey);
+ return signature;
+ }
+
+ static Mac initMac(String keyName) throws Exception {
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+
+ SecretKey secretKey = (SecretKey) keyStore.getKey(keyName, null);
+
+ Mac mac = Mac.getInstance("HmacSHA256");
+ mac.init(secretKey);
+ return mac;
+ }
+
static byte[] doEncrypt(Cipher cipher, byte[] data) throws Exception {
return cipher.doFinal(data);
}
+ static byte[] doSign(Signature signature, byte[] data) throws Exception {
+ signature.update(data);
+ return signature.sign();
+ }
+
static void showInstructionDialog(Context context, int titleRes, int messageRes,
int positiveButtonRes, DialogInterface.OnClickListener listener) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
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 f39b590..e843ce7 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
@@ -92,6 +92,7 @@
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
@@ -664,6 +665,13 @@
public void processSocketCommand(String cmd)
throws ItsException {
+ // Default locale must be set to "en-us"
+ Locale locale = Locale.getDefault();
+ if (!Locale.US.equals(locale)) {
+ Logt.e(TAG, "Default language is not set to " + Locale.US + "!");
+ stopSelf();
+ }
+
// Each command is a serialized JSON object.
try {
JSONObject cmdObj = new JSONObject(cmd);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
index 7e244a1..66422eb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
@@ -37,6 +37,7 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
import java.util.Set;
import java.util.TreeSet;
import java.io.BufferedReader;
@@ -361,6 +362,18 @@
, 1.0, ResultType.NEUTRAL, ResultUnit.NONE);
setTestResultAndFinish(true);
}
+ // Default locale must be set to "en-us"
+ Locale locale = Locale.getDefault();
+ if (!Locale.US.equals(locale)) {
+ String toastMessage = "Unsupported default language " + locale + "! " +
+ "Please switch the default language to English (United States) in " +
+ "Settings > Language & input > Languages";
+ Toast.makeText(ItsTestActivity.this, toastMessage, Toast.LENGTH_LONG).show();
+ ItsTestActivity.this.getReportLog().setSummary(
+ "FAIL: Default language is not set to " + Locale.US,
+ 1.0, ResultType.NEUTRAL, ResultUnit.NONE);
+ setTestResultAndFinish(false);
+ }
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pBroadcastReceiverTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pBroadcastReceiverTest.java
index 5cc23f1..0e5f356 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pBroadcastReceiverTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pBroadcastReceiverTest.java
@@ -42,7 +42,7 @@
private WifiP2pManager mP2pMgr;
private Channel mChannel;
- private WifiP2pDeviceList mPeers;
+ private WifiP2pDeviceList mPeers = new WifiP2pDeviceList();
private WifiP2pInfo mP2pInfo;
private WifiP2pGroup mP2pGroup;
@@ -79,12 +79,9 @@
Timeout t = new Timeout(msec);
while (!t.isTimeout()) {
- if (mPeers != null) {
- for (WifiP2pDevice dev: mPeers.getDeviceList()) {
- if (dev.deviceAddress.equals(targetAddr)) {
- return dev;
- }
- }
+ WifiP2pDevice dev = mPeers.get(targetAddr);
+ if (dev != null) {
+ return dev;
}
wait(t.getRemainTime());
}
@@ -125,14 +122,9 @@
Timeout t = new Timeout(msec);
while (!t.isTimeout()) {
- if (mPeers != null) {
- for (WifiP2pDevice dev: mPeers.getDeviceList()) {
- if (dev.deviceAddress.equals(targetAddr)) {
- if (dev.status == WifiP2pDevice.CONNECTED) {
- return true;
- }
- }
- }
+ WifiP2pDevice dev = mPeers.get(targetAddr);
+ if (dev != null && dev.status == WifiP2pDevice.CONNECTED) {
+ return true;
}
wait(t.getRemainTime());
}
@@ -152,21 +144,14 @@
Timeout t = new Timeout(msec);
- boolean devicePresent;
-
while (!t.isTimeout()) {
- devicePresent = false;
- if (mPeers != null) {
- for (WifiP2pDevice dev: mPeers.getDeviceList()) {
- if (dev.deviceAddress.equals(targetAddr)) {
- if (dev.status != WifiP2pDevice.CONNECTED) {
- return true;
- }
- devicePresent = true;
- }
- }
+ WifiP2pDevice dev = mPeers.get(targetAddr);
+
+ if (dev == null ) return true;
+
+ if (dev.status != WifiP2pDevice.CONNECTED) {
+ return true;
}
- if (!devicePresent) return true;
wait(t.getRemainTime());
}
Log.e(TAG, "Appropriate WIFI_P2P_PEERS_CHANGED_ACTION didn't occur");
@@ -217,7 +202,7 @@
@Override
public synchronized void onPeersAvailable(WifiP2pDeviceList peers) {
Log.d(TAG, "onPeersAvailable()");
- mPeers = peers;
+ mPeers = new WifiP2pDeviceList(peers);
notifyAll();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java
index 395142d..68d3bb5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java
@@ -29,10 +29,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
-import android.net.LinkProperties;
import android.net.MacAddress;
import android.net.Network;
-import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
@@ -76,6 +74,7 @@
private ConnectivityManager mConnectivityManager;
private NetworkRequest mNetworkRequest;
private CallbackUtils.NetworkCallback mNetworkCallback;
+ private ConnectionStatusListener mConnectionStatusListener;
private BroadcastReceiver mBroadcastReceiver;
private String mFailureReason;
@@ -202,10 +201,10 @@
// Register the receiver for post connection broadcast.
mContext.registerReceiver(mBroadcastReceiver, intentFilter);
final CountDownLatch countDownLatchForConnectionStatusListener = new CountDownLatch(1);
- ConnectionStatusListener connectionStatusListener =
+ mConnectionStatusListener =
new ConnectionStatusListener(countDownLatchForConnectionStatusListener);
mWifiManager.addSuggestionConnectionStatusListener(
- Executors.newSingleThreadExecutor(), connectionStatusListener);
+ Executors.newSingleThreadExecutor(), mConnectionStatusListener);
// Step: Register network callback to wait for connection state.
mNetworkRequest = new NetworkRequest.Builder()
@@ -312,12 +311,12 @@
return false;
}
if (DBG) Log.v(TAG, "Received connection status");
- if (!Objects.equals(connectionStatusListener.wifiNetworkSuggestion, networkSuggestion)
- || connectionStatusListener.failureReason
+ if (!Objects.equals(mConnectionStatusListener.wifiNetworkSuggestion, networkSuggestion)
+ || mConnectionStatusListener.failureReason
!= WifiManager.STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION) {
Log.e(TAG, "Received wrong connection status for "
- + connectionStatusListener.wifiNetworkSuggestion
- + " with reason: " + connectionStatusListener.failureReason);
+ + mConnectionStatusListener.wifiNetworkSuggestion
+ + " with reason: " + mConnectionStatusListener.failureReason);
setFailureReason(mContext.getString(
R.string.wifi_status_suggestion_connection_status_failure));
return false;
@@ -404,6 +403,9 @@
if (mBroadcastReceiver != null) {
mContext.unregisterReceiver(mBroadcastReceiver);
}
+ if (mConnectionStatusListener != null) {
+ mWifiManager.removeSuggestionConnectionStatusListener(mConnectionStatusListener);
+ }
mWifiManager.removeNetworkSuggestions(new ArrayList<>());
super.tearDown();
}
diff --git a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
index f9bdc22..fa1e4ec 100644
--- a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
+++ b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
@@ -45,19 +45,23 @@
+ "(; name=(?<changeName>[^;]+))?"
+ "(; enableAfterTargetSdk=(?<targetSdk>[0-9]+))?"
+ "(; (?<disabled>disabled))?"
+ + "(; (?<loggingOnly>loggingOnly))?"
+ "(; packageOverrides=(?<overrides>[^\\)]+))?"
+ "\\)");
long changeId;
String changeName;
int targetSdk;
boolean disabled;
+ boolean loggingOnly;
boolean hasOverrides;
- private Change(long changeId, String changeName, int targetSdk, boolean disabled, boolean hasOverrides) {
+ private Change(long changeId, String changeName, int targetSdk, boolean disabled,
+ boolean loggingOnly, boolean hasOverrides) {
this.changeId = changeId;
this.changeName = changeName;
this.targetSdk = targetSdk;
this.disabled = disabled;
+ this.loggingOnly = loggingOnly;
this.hasOverrides = hasOverrides;
}
@@ -66,6 +70,7 @@
String changeName;
int targetSdk = 0;
boolean disabled = false;
+ boolean loggingOnly = false;
boolean hasOverrides = false;
Matcher matcher = CHANGE_REGEX.matcher(line);
@@ -90,10 +95,13 @@
if (matcher.group("disabled") != null) {
disabled = true;
}
+ if (matcher.group("loggingOnly") != null) {
+ loggingOnly = true;
+ }
if (matcher.group("overrides") != null) {
hasOverrides = true;
}
- return new Change(changeId, changeName, targetSdk, disabled, hasOverrides);
+ return new Change(changeId, changeName, targetSdk, disabled, loggingOnly, hasOverrides);
}
static Change fromNode(Node node) {
@@ -108,8 +116,12 @@
if (element.hasAttribute("disabled")) {
disabled = true;
}
+ boolean loggingOnly = false;
+ if (element.hasAttribute("loggingOnly")) {
+ loggingOnly = true;
+ }
boolean hasOverrides = false;
- return new Change(changeId, changeName, targetSdk, disabled, hasOverrides);
+ return new Change(changeId, changeName, targetSdk, disabled, loggingOnly, hasOverrides);
}
@Override
public int hashCode() {
@@ -128,6 +140,7 @@
&& Objects.equals(this.changeName, that.changeName)
&& this.targetSdk == that.targetSdk
&& this.disabled == that.disabled
+ && this.loggingOnly == that.loggingOnly
&& this.hasOverrides == that.hasOverrides;
}
@Override
diff --git a/hostsidetests/appsecurity/Android.mk b/hostsidetests/appsecurity/Android.mk
index ee149f0..55d7720 100644
--- a/hostsidetests/appsecurity/Android.mk
+++ b/hostsidetests/appsecurity/Android.mk
@@ -28,6 +28,9 @@
truth-prebuilt \
hamcrest-library
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ CompatChangeGatingTestBase
+
LOCAL_JAVA_RESOURCE_DIRS := res
LOCAL_CTS_TEST_PACKAGE := android.appsecurity
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
index 1465bc3..00ddbb0 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
@@ -18,6 +18,8 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.google.common.collect.ImmutableSet;
+
/**
* Set of tests that verify behavior of
* {@link android.provider.DocumentsContract} and related intents.
@@ -27,6 +29,8 @@
private static final String PROVIDER_APK = "CtsDocumentProvider.apk";
private static final String DUMMYIME_APK = "CtsDummyIme.apk";
+ private static final long RESTRICT_STORAGE_ACCESS_FRAMEWORK = 141600225L;
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -65,10 +69,6 @@
runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testTree");
}
- public void testTree_blockFromTree() throws Exception {
- runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testTree_blockFromTree");
- }
-
public void testGetContent_rootsShowing() throws Exception {
runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testGetContent_rootsShowing");
}
@@ -119,4 +119,18 @@
public void testEject() throws Exception {
runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testEject");
}
+
+ public void testRestrictStorageAccessFrameworkEnabled_blockFromTree() throws Exception {
+ runDeviceCompatTest(CLIENT_PKG, ".DocumentsClientTest",
+ "testRestrictStorageAccessFrameworkEnabled_blockFromTree",
+ /* enabledChanges */ ImmutableSet.of(RESTRICT_STORAGE_ACCESS_FRAMEWORK),
+ /* disabledChanges */ ImmutableSet.of());
+ }
+
+ public void testRestrictStorageAccessFrameworkDisabled_notBlockFromTree() throws Exception {
+ runDeviceCompatTest(CLIENT_PKG, ".DocumentsClientTest",
+ "testRestrictStorageAccessFrameworkDisabled_notBlockFromTree",
+ /* enabledChanges */ ImmutableSet.of(),
+ /* disabledChanges */ ImmutableSet.of(RESTRICT_STORAGE_ACCESS_FRAMEWORK));
+ }
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
index 1af0650..d7a9ffc 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
@@ -16,23 +16,21 @@
package android.appsecurity.cts;
+import android.compat.cts.CompatChangeGatingTestCase;
+
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.DeviceTestCase;
import com.android.tradefed.testtype.IAbi;
import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
/**
* Base class for {@link android.provider.DocumentsContract} and related test cases.
*/
-abstract class DocumentsTestCase extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+abstract class DocumentsTestCase extends CompatChangeGatingTestCase implements IAbiReceiver {
protected static final String CLIENT_PKG = "com.android.cts.documentclient";
protected static final String CLIENT_APK = "CtsDocumentClient.apk";
protected IAbi mAbi;
- protected IBuildInfo mCtsBuild;
@Override
public void setAbi(IAbi abi) {
@@ -40,17 +38,11 @@
}
@Override
- public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = buildInfo;
- }
-
- @Override
protected void setUp() throws Exception {
super.setUp();
Utils.prepareSingleUser(getDevice());
assertNotNull(mAbi);
- assertNotNull(mCtsBuild);
reinstallClientPackage();
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index 38a76d9..ab6e0bd 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -655,9 +655,6 @@
runDeviceTests(WRITE_PKG_2, WRITE_PKG + ".WriteGiftTest",
"testNotIsExternalStorageLegacy", user);
- updateAppOp(WRITE_PKG_2, user, "android:request_install_packages", true);
- runDeviceTests(WRITE_PKG_2, WRITE_PKG + ".WriteGiftTest",
- "testIsExternalStorageLegacy", user);
}
} finally {
getDevice().uninstallPackage(WRITE_PKG);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
index aa28a97..af9d4d2 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
@@ -17,21 +17,22 @@
package android.appsecurity.cts;
import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.LargeTest;
+
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.Log;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceTestCase;
import com.android.tradefed.testtype.IAbi;
import com.android.tradefed.testtype.IAbiReceiver;
import com.android.tradefed.testtype.IBuildReceiver;
import com.android.tradefed.util.AbiFormatter;
-import com.android.tradefed.util.AbiUtils;
/**
* Tests that verify intent filters.
*/
+@LargeTest
@AppModeFull(reason="Instant applications can never be system or privileged")
public class PrivilegedUpdateTests extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
private static final String TAG = "PrivilegedUpdateTests";
@@ -151,6 +152,28 @@
}
}
+ public void testUpdatedSystemAppPreservedOnReboot() throws Exception {
+ if (!isDefaultAbi()) {
+ Log.w(TAG, "Skipping test for non-default abi.");
+ return;
+ }
+
+ getDevice().executeShellCommand("pm enable " + SHIM_PKG);
+ runDeviceTests(TEST_PKG, ".PrivilegedAppDisableTest", "testPrivAppAndEnabled");
+ try {
+ assertNull(getDevice().installPackage(
+ mBuildHelper.getTestFile(SHIM_UPDATE_APK), true));
+ getDevice().executeShellCommand("pm enable " + SHIM_PKG);
+ runDeviceTests(TEST_PKG, ".PrivilegedAppDisableTest", "testUpdatedPrivAppAndEnabled");
+
+ getDevice().reboot();
+
+ runDeviceTests(TEST_PKG, ".PrivilegedAppDisableTest", "testUpdatedPrivAppAndEnabled");
+ } finally {
+ getDevice().uninstallPackage(SHIM_PKG);
+ }
+ }
+
private void runDeviceTests(String packageName, String testClassName, String testMethodName)
throws DeviceNotAvailableException {
Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/SessionReferrerUriTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/SessionReferrerUriTest.java
new file mode 100644
index 0000000..7477721
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/SessionReferrerUriTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appsecurity.cts;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.platform.test.annotations.AppModeFull;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class SessionReferrerUriTest extends BaseAppSecurityTest {
+
+ private static final String SESSION_INSPECTOR_A_APK = "CtsSessionInspectorAppA.apk";
+ private static final String SESSION_INSPECTOR_B_APK = "CtsSessionInspectorAppB.apk";
+ private static final String SESSION_INSPECTOR_PKG_A = "com.android.cts.sessioninspector.a";
+ private static final String SESSION_INSPECTOR_PKG_B = "com.android.cts.sessioninspector.b";
+
+ @Before
+ public void setup() throws Exception {
+ new InstallMultiple().addApk(SESSION_INSPECTOR_A_APK).run();
+ new InstallMultiple().addApk(SESSION_INSPECTOR_B_APK).run();
+ }
+
+ @After
+ public void teardown() throws Exception {
+ getDevice().uninstallPackage(SESSION_INSPECTOR_PKG_A);
+ getDevice().uninstallPackage(SESSION_INSPECTOR_PKG_B);
+ }
+
+ @Test
+ @AppModeFull(reason = "Only full apps may install")
+ public void testSessionReferrerUriVisibleToOwner() throws DeviceNotAvailableException {
+ Utils.runDeviceTests(getDevice(), SESSION_INSPECTOR_PKG_A,
+ "com.android.cts.sessioninspector.SessionInspectorTest", "testOnlyOwnerCanSee");
+ Utils.runDeviceTests(getDevice(), SESSION_INSPECTOR_PKG_B,
+ "com.android.cts.sessioninspector.SessionInspectorTest", "testOnlyOwnerCanSee");
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
index d9da67a..6f909d8 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
@@ -43,4 +43,6 @@
dex_preopt: {
enabled: false,
},
+ min_sdk_version: "29",
+ target_sdk_version: "29",
}
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/DocumentClient/AndroidManifest.xml
index 79eb44d..e87cd6f 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/AndroidManifest.xml
@@ -16,7 +16,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.documentclient">
- <application android:forceQueryable="true">
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
+
+ <application android:debuggable="true" android:forceQueryable="true">
<uses-library android:name="android.test.runner" />
<activity android:name=".MyActivity" />
</application>
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
index 1f302dd..40d8ff4 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
@@ -357,19 +357,58 @@
}
}
- public void testTree_blockFromTree() throws Exception {
+ public void testRestrictStorageAccessFrameworkEnabled_blockFromTree() throws Exception {
if (!supportedHardware()) return;
final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
mActivity.startActivityForResult(intent, REQUEST_CODE);
mDevice.waitForIdle();
+
+ // save button is disabled for the storage root
+ assertFalse(findSaveButton().isEnabled());
+
+ findDocument("Download").click();
+ mDevice.waitForIdle();
+
+ // save button is disabled for Download folder
+ assertFalse(findSaveButton().isEnabled());
+
findRoot("CtsCreate").click();
+ mDevice.waitForIdle();
+
+ // save button is disabled for CtsCreate root
+ assertFalse(findSaveButton().isEnabled());
+
+ findDocument("DIR2").click();
+
+ mDevice.waitForIdle();
+ // save button is enabled for dir2
+ assertTrue(findSaveButton().isEnabled());
+ }
+
+ public void testRestrictStorageAccessFrameworkDisabled_notBlockFromTree() throws Exception {
+ if (!supportedHardware()) return;
+
+ final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
+ mActivity.startActivityForResult(intent, REQUEST_CODE);
mDevice.waitForIdle();
- // save button is disabled for root
- assertFalse(findSaveButton().isEnabled());
+ // save button is enabled for for the storage root
+ assertTrue(findSaveButton().isEnabled());
+
+ findDocument("Download").click();
+ mDevice.waitForIdle();
+
+ // save button is enabled for Download folder
+ assertTrue(findSaveButton().isEnabled());
+
+ findRoot("CtsCreate").click();
+ mDevice.waitForIdle();
+
+ // save button is enabled for CtsCreate root
+ assertTrue(findSaveButton().isEnabled());
findDocument("DIR2").click();
@@ -661,14 +700,6 @@
// assert the default root is internal storage root
assertToolbarTitleEquals(title);
- // save button is disabled for the root
- assertFalse(findSaveButton().isEnabled());
-
- findDocument("Download").click();
- mDevice.waitForIdle();
- // save button is disabled for Download folder
- assertFalse(findSaveButton().isEnabled());
-
// no Downloads root
assertFalse(findRoot("Downloads").exists());
}
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
index 9b57550..7981db4 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
@@ -39,4 +39,6 @@
dex_preopt: {
enabled: false,
},
+ min_sdk_version: "29",
+ target_sdk_version: "29",
}
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/DocumentProvider/AndroidManifest.xml
index 2b2f1fd..2f4d5fe 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/AndroidManifest.xml
@@ -16,6 +16,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.documentprovider">
+
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
+
<application android:forceQueryable="true">
<uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java b/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
index 61f342c..0886269 100644
--- a/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
@@ -473,8 +473,7 @@
// Some dialogs may have granted access automatically, so we're willing
// to keep rolling forward if we can't find our grant button
- final UiSelector grant = new UiSelector()
- .textMatches("(Allow|Change|Move to trash|Move out of trash|Delete)");
+ final UiSelector grant = new UiSelector().textMatches("Allow");
if (new UiObject(grant).waitForExists(2_000)) {
device.findObject(grant).click();
}
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/AndroidManifest.xml
index 95169b6..a1487af 100644
--- a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/AndroidManifest.xml
@@ -17,6 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.privilegedupdate">
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+
<application android:label="PrivilegedUpdateApp">
<uses-library android:name="android.test.runner" />
<activity android:name=".MainActivity" />
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/src/com/android/cts/privilegedupdate/PrivilegedAppDisableTest.java b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/src/com/android/cts/privilegedupdate/PrivilegedAppDisableTest.java
index 606ada1..18962a9 100644
--- a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/src/com/android/cts/privilegedupdate/PrivilegedAppDisableTest.java
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/src/com/android/cts/privilegedupdate/PrivilegedAppDisableTest.java
@@ -35,29 +35,27 @@
private static final String PRIVILEGED_SHIM_PKG = "com.android.cts.priv.ctsshim";
public void testPrivAppAndEnabled() throws Exception {
- assertEquals((getApplicationFlags() & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP),
- 0);
+ assertEquals(0, (getApplicationFlags() & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
assertPackageEnabledState(PRIVILEGED_SHIM_PKG,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
}
public void testPrivAppAndDisabled() throws Exception {
- assertEquals((getApplicationFlags() & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP),
- 0);
+ assertEquals(0, (getApplicationFlags() & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
assertPackageEnabledState(PRIVILEGED_SHIM_PKG,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
}
public void testUpdatedPrivAppAndEnabled() throws Exception {
- assertEquals((getApplicationFlags() & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP),
- ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
+ assertEquals(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
+ (getApplicationFlags() & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
assertPackageEnabledState(PRIVILEGED_SHIM_PKG,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
}
public void testUpdatedPrivAppAndDisabled() throws Exception {
- assertEquals((getApplicationFlags() & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP),
- ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
+ assertEquals(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
+ (getApplicationFlags() & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
assertPackageEnabledState(PRIVILEGED_SHIM_PKG,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
}
diff --git a/hostsidetests/appsecurity/test-apps/SessionInspector/Android.bp b/hostsidetests/appsecurity/test-apps/SessionInspector/Android.bp
new file mode 100644
index 0000000..421c9de
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SessionInspector/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2020 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.
+
+android_test_helper_app {
+ name: "CtsSessionInspectorAppA",
+ defaults: ["cts_support_defaults"],
+ manifest: "AndroidManifestA.xml",
+ sdk_version: "test_current",
+ srcs: ["src/**/*.java"],
+ static_libs: ["androidx.test.rules"],
+ // tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+android_test_helper_app {
+ name: "CtsSessionInspectorAppB",
+ defaults: ["cts_support_defaults"],
+ manifest: "AndroidManifestB.xml",
+ sdk_version: "test_current",
+ srcs: ["src/**/*.java"],
+ static_libs: ["androidx.test.rules"],
+ // tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/SessionInspector/AndroidManifestA.xml b/hostsidetests/appsecurity/test-apps/SessionInspector/AndroidManifestA.xml
new file mode 100644
index 0000000..c68bc67
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SessionInspector/AndroidManifestA.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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="com.android.cts.sessioninspector.a">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.sessioninspector.a" />
+
+ <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
+
+ <application android:forceQueryable="true">
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="com.android.cts.sessioninspector.SessionInspectorActivity"
+ android:exported="true"/>
+ </application>
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/SessionInspector/AndroidManifestB.xml b/hostsidetests/appsecurity/test-apps/SessionInspector/AndroidManifestB.xml
new file mode 100644
index 0000000..7db8db6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SessionInspector/AndroidManifestB.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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="com.android.cts.sessioninspector.b">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.sessioninspector.b" />
+
+ <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
+
+ <application android:forceQueryable="true">
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="com.android.cts.sessioninspector.SessionInspectorActivity"
+ android:exported="true"/>
+ </application>
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/SessionInspector/OWNERS b/hostsidetests/appsecurity/test-apps/SessionInspector/OWNERS
new file mode 100644
index 0000000..9d4a924
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SessionInspector/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 533114
+patb@google.com
+toddke@google.com
+chiuwinson@google.com
diff --git a/hostsidetests/appsecurity/test-apps/SessionInspector/src/com/android/cts/sessioninspector/Constants.java b/hostsidetests/appsecurity/test-apps/SessionInspector/src/com/android/cts/sessioninspector/Constants.java
new file mode 100644
index 0000000..6957448
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SessionInspector/src/com/android/cts/sessioninspector/Constants.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.sessioninspector;
+
+import android.net.Uri;
+
+public class Constants {
+ private static final String PKG_BASE = "com.android.cts.sessioninspector.";
+
+ public static final String ACTION_CREATE_SESSION = PKG_BASE + "CREATE_SESSION";
+ public static final String ACTION_GET_SESSION = PKG_BASE + "GET_SESSION";
+ public static final String ACTION_ABANDON_SESSION = PKG_BASE + "ABANDON_SESSION";
+
+ public static final String PACKAGE_A = PKG_BASE + "a";
+ public static final String PACKAGE_B = PKG_BASE + "b";
+
+ public static final String ACTIVITY_NAME = PKG_BASE + "SessionInspectorActivity";
+
+ public static final Uri REFERRER_URI = Uri.parse("https://user-sensitive-domain.com/");
+}
diff --git a/hostsidetests/appsecurity/test-apps/SessionInspector/src/com/android/cts/sessioninspector/SessionInspectorActivity.java b/hostsidetests/appsecurity/test-apps/SessionInspector/src/com/android/cts/sessioninspector/SessionInspectorActivity.java
new file mode 100644
index 0000000..edf90f2
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SessionInspector/src/com/android/cts/sessioninspector/SessionInspectorActivity.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.sessioninspector;
+
+import static android.content.Intent.EXTRA_RESULT_RECEIVER;
+import static android.content.pm.PackageInstaller.EXTRA_SESSION;
+import static android.content.pm.PackageInstaller.EXTRA_SESSION_ID;
+import static android.content.pm.PackageInstaller.SessionInfo;
+import static android.content.pm.PackageInstaller.SessionParams;
+import static android.content.pm.PackageInstaller.SessionParams.MODE_FULL_INSTALL;
+
+import static com.android.cts.sessioninspector.Constants.ACTION_ABANDON_SESSION;
+import static com.android.cts.sessioninspector.Constants.ACTION_CREATE_SESSION;
+import static com.android.cts.sessioninspector.Constants.ACTION_GET_SESSION;
+import static com.android.cts.sessioninspector.Constants.REFERRER_URI;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.RemoteCallback;
+
+public class SessionInspectorActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ RemoteCallback remoteCallback = getIntent().getParcelableExtra(EXTRA_RESULT_RECEIVER);
+ final Bundle result = new Bundle();
+ String action = getIntent().getAction();
+ try {
+ switch (action) {
+ case ACTION_CREATE_SESSION:
+ SessionParams params = new SessionParams(MODE_FULL_INSTALL);
+ params.setReferrerUri(REFERRER_URI);
+ final int session =
+ getPackageManager().getPackageInstaller().createSession(params);
+ result.putInt(EXTRA_SESSION_ID, session);
+ break;
+ case ACTION_GET_SESSION: {
+ final int sessionId = getIntent().getIntExtra(EXTRA_SESSION_ID, 0);
+ final SessionInfo sessionInfo =
+ getPackageManager().getPackageInstaller().getSessionInfo(sessionId);
+ result.putParcelable(EXTRA_SESSION, sessionInfo);
+ break;
+ }
+ case ACTION_ABANDON_SESSION: {
+ final int sessionId = getIntent().getIntExtra(EXTRA_SESSION_ID, 0);
+ getPackageManager().getPackageInstaller().abandonSession(sessionId);
+ break;
+ }
+ default:
+ throw new IllegalArgumentException("Unrecognized action: " + action);
+ }
+ } catch (Exception e) {
+ result.putSerializable("error", e);
+ }
+ remoteCallback.sendResult(result);
+ finish();
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/SessionInspector/src/com/android/cts/sessioninspector/SessionInspectorTest.java b/hostsidetests/appsecurity/test-apps/SessionInspector/src/com/android/cts/sessioninspector/SessionInspectorTest.java
new file mode 100644
index 0000000..8afcdef
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SessionInspector/src/com/android/cts/sessioninspector/SessionInspectorTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.sessioninspector;
+
+import static com.android.cts.sessioninspector.Constants.ACTION_ABANDON_SESSION;
+import static com.android.cts.sessioninspector.Constants.ACTION_CREATE_SESSION;
+import static com.android.cts.sessioninspector.Constants.ACTION_GET_SESSION;
+import static com.android.cts.sessioninspector.Constants.ACTIVITY_NAME;
+import static com.android.cts.sessioninspector.Constants.REFERRER_URI;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInstaller;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.ConditionVariable;
+import android.os.RemoteCallback;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(JUnit4.class)
+public class SessionInspectorTest {
+
+ @Test
+ public void testOnlyOwnerCanSee() throws Exception {
+ String myPackage = Constants.PACKAGE_A.equals(getContext().getPackageName())
+ ? Constants.PACKAGE_A : Constants.PACKAGE_B;
+ String otherPackage = Constants.PACKAGE_A.equals(myPackage) ? Constants.PACKAGE_B
+ : Constants.PACKAGE_A;
+
+ int sessionId = createSession(myPackage);
+
+ final PackageInstaller.SessionInfo sessionToMe = getSessionInfo(myPackage, sessionId);
+ final PackageInstaller.SessionInfo sessionToOther = getSessionInfo(otherPackage, sessionId);
+
+ abandonSession(myPackage, sessionId);
+
+ assertEquals(REFERRER_URI, sessionToMe.getReferrerUri());
+ assertNull(sessionToOther.getReferrerUri());
+ }
+
+ private Context getContext() {
+ return InstrumentationRegistry.getContext();
+ }
+
+ private int createSession(String packageName) throws Exception {
+ Bundle result = sendCommand(new Intent(ACTION_CREATE_SESSION).setComponent(
+ new ComponentName(packageName, ACTIVITY_NAME)));
+ return result.getInt(PackageInstaller.EXTRA_SESSION_ID, 0);
+ }
+
+ private PackageInstaller.SessionInfo getSessionInfo(String packageName, int session)
+ throws Exception {
+ Bundle result = sendCommand(new Intent(ACTION_GET_SESSION).putExtra(
+ PackageInstaller.EXTRA_SESSION_ID, session).setComponent(
+ new ComponentName(packageName, ACTIVITY_NAME)));
+ return result.getParcelable(PackageInstaller.EXTRA_SESSION);
+ }
+
+ private void abandonSession(String packageName, int sessionId) throws Exception {
+ sendCommand(new Intent(ACTION_ABANDON_SESSION).putExtra(PackageInstaller.EXTRA_SESSION_ID,
+ sessionId).setComponent(new ComponentName(packageName, ACTIVITY_NAME)));
+ }
+
+ private Bundle sendCommand(Intent intent) throws Exception {
+ ConditionVariable condition = new ConditionVariable();
+ final Bundle[] resultHolder = new Bundle[1];
+ RemoteCallback callback = new RemoteCallback(result -> {
+ resultHolder[0] = result;
+ condition.open();
+ });
+ intent.putExtra(Intent.EXTRA_RESULT_RECEIVER, callback);
+ intent.setData(Uri.parse("https://" + UUID.randomUUID()));
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ getContext().startActivity(intent);
+ condition.block(TimeUnit.SECONDS.toMillis(10));
+ Bundle result = resultHolder[0];
+ if (result.containsKey("error")) {
+ throw (Exception) result.getSerializable("error");
+ }
+ return result;
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/Utils.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/Utils.java
index 42ba7f3..46ca3ae 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/Utils.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/Utils.java
@@ -134,7 +134,15 @@
public static long getSizeManual(File dir, boolean excludeObb) throws Exception {
long size = getAllocatedSize(dir);
- for (File f : dir.listFiles()) {
+ File[] files = dir.listFiles();
+
+ if (files == null) {
+ // This can happen on devices with scoped storage, where we're not allowed
+ // to iterate Android/ anymore.
+ return size;
+ }
+
+ for (File f : files) {
if (f.isDirectory()) {
if (excludeObb && f.getName().equalsIgnoreCase("obb")
&& f.getParentFile().getName().equalsIgnoreCase("Android")
diff --git a/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java b/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java
index 7b1abec..b1d07e2 100644
--- a/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java
@@ -230,7 +230,11 @@
// TODO: remove this once 34723223 is fixed
logCommand("sync");
- final long manualSize = getSizeManual(Environment.getExternalStorageDirectory(), true);
+ long manualSize = getSizeManual(Environment.getExternalStorageDirectory(), true);
+ // Since scoped storage, we can't walk the Android/ tree anymore; so pass in this
+ // app's files and cache dirs directly.
+ manualSize += getSizeManual(getContext().getExternalFilesDir(null), true);
+ manualSize += getSizeManual(getContext().getExternalCacheDir(), true);
final long statsSize = stats.queryExternalStatsForUser(UUID_DEFAULT, user).getTotalBytes();
assertMostlyEquals(manualSize, statsSize);
diff --git a/hostsidetests/appsecurity/test-apps/V3SigningSchemeRotation/Android.bp b/hostsidetests/appsecurity/test-apps/V3SigningSchemeRotation/Android.bp
index 4481d9e..9de8251 100644
--- a/hostsidetests/appsecurity/test-apps/V3SigningSchemeRotation/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/V3SigningSchemeRotation/Android.bp
@@ -20,6 +20,7 @@
"cts",
"vts",
"general-tests",
+ "sts",
],
srcs: ["src/**/*.java"],
sdk_version: "current",
diff --git a/hostsidetests/appsecurity/test-apps/dummyime/Android.bp b/hostsidetests/appsecurity/test-apps/dummyime/Android.bp
index b356368b..948e837 100644
--- a/hostsidetests/appsecurity/test-apps/dummyime/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/dummyime/Android.bp
@@ -33,4 +33,6 @@
dex_preopt: {
enabled: false,
},
+ min_sdk_version: "29",
+ target_sdk_version: "29",
}
diff --git a/hostsidetests/appsecurity/test-apps/dummyime/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/dummyime/AndroidManifest.xml
index ea88b38..2f71a4b 100644
--- a/hostsidetests/appsecurity/test-apps/dummyime/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/dummyime/AndroidManifest.xml
@@ -18,6 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.dummyime">
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
<application android:label="Dummy IME">
<service android:name=".CtsDummyIme"
android:permission="android.permission.BIND_INPUT_METHOD">
diff --git a/hostsidetests/backup/OtherSoundsSettingsApp/Android.bp b/hostsidetests/backup/OtherSoundsSettingsApp/Android.bp
index fac14e6..e34b256 100644
--- a/hostsidetests/backup/OtherSoundsSettingsApp/Android.bp
+++ b/hostsidetests/backup/OtherSoundsSettingsApp/Android.bp
@@ -27,5 +27,8 @@
"vts",
"general-tests",
],
- sdk_version: "test_current",
+ // Uncomment when b/78787392 is fixed
+ // sdk_version: "system_test_current",
+ platform_apis: true,
+
}
diff --git a/hostsidetests/backup/OtherSoundsSettingsApp/src/android/cts/backup/othersoundssettingsapp/OtherSoundsSettingsTest.java b/hostsidetests/backup/OtherSoundsSettingsApp/src/android/cts/backup/othersoundssettingsapp/OtherSoundsSettingsTest.java
index 46e6b95..868dc40 100644
--- a/hostsidetests/backup/OtherSoundsSettingsApp/src/android/cts/backup/othersoundssettingsapp/OtherSoundsSettingsTest.java
+++ b/hostsidetests/backup/OtherSoundsSettingsApp/src/android/cts/backup/othersoundssettingsapp/OtherSoundsSettingsTest.java
@@ -21,9 +21,13 @@
import static com.android.compatibility.common.util.BackupUtils.LOCAL_TRANSPORT_TOKEN;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+import android.app.UiAutomation;
import android.content.ContentResolver;
+import android.content.Context;
import android.os.ParcelFileDescriptor;
+import android.os.Vibrator;
import android.platform.test.annotations.AppModeFull;
import android.provider.Settings;
@@ -31,12 +35,15 @@
import com.android.compatibility.common.util.BackupUtils;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.IOException;
import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
/**
* Device side routines to be invoked by the host side OtherSoundsSettingsHostSideTest. These
@@ -48,9 +55,12 @@
public class OtherSoundsSettingsTest {
/** The name of the package for backup */
private static final String SETTINGS_PACKAGE_NAME = "com.android.providers.settings";
+ private static final int SETTING_ABSENT_VALUE = -1;
private ContentResolver mContentResolver;
private BackupUtils mBackupUtils;
+ private Map<String, Integer> mOriginalSettingValues;
+ private UiAutomation mUiAutomation;
@Before
public void setUp() throws Exception {
@@ -64,6 +74,15 @@
return new ParcelFileDescriptor.AutoCloseInputStream(pfd);
}
};
+ mOriginalSettingValues = new HashMap<>();
+ mUiAutomation = getInstrumentation().getUiAutomation();
+ mUiAutomation.adoptShellPermissionIdentity();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ restoreOriginalSettingValues();
+ mUiAutomation.dropShellPermissionIdentity();
}
/**
@@ -78,17 +97,13 @@
*/
@Test
public void testOtherSoundsSettings_dialPadTones() throws Exception {
- int originalValue =
- Settings.System.getInt(
- mContentResolver, Settings.System.DTMF_TONE_WHEN_DIALING, -1);
+ int originalValue = prepareSystemSetting(Settings.System.DTMF_TONE_WHEN_DIALING);
assertTrue("Dial pad tones does not exist.", originalValue != -1);
mBackupUtils.backupNowAndAssertSuccess(SETTINGS_PACKAGE_NAME);
- boolean ret =
- Settings.System.putInt(
- mContentResolver, Settings.System.DTMF_TONE_WHEN_DIALING,
- 1 - originalValue);
+ boolean ret = setSystemSetting(Settings.System.DTMF_TONE_WHEN_DIALING,
+ 1 - originalValue);
assertTrue("Toggle Dial pad tones fail.", ret);
mBackupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, SETTINGS_PACKAGE_NAME);
@@ -111,16 +126,13 @@
*/
@Test
public void testOtherSoundsSettings_touchSounds() throws Exception {
- int originalValue =
- Settings.System.getInt(
- mContentResolver, Settings.System.SOUND_EFFECTS_ENABLED, -1);
+ int originalValue = prepareSystemSetting(Settings.System.SOUND_EFFECTS_ENABLED);
assertTrue("Touch sounds does not exist.", originalValue != -1);
mBackupUtils.backupNowAndAssertSuccess(SETTINGS_PACKAGE_NAME);
- boolean ret =
- Settings.System.putInt(
- mContentResolver, Settings.System.SOUND_EFFECTS_ENABLED, 1 - originalValue);
+ boolean ret = setSystemSetting(Settings.System.SOUND_EFFECTS_ENABLED,
+ 1 - originalValue);
assertTrue("Toggle Touch sounds fail.", ret);
mBackupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, SETTINGS_PACKAGE_NAME);
@@ -143,17 +155,21 @@
*/
@Test
public void testOtherSoundsSettings_touchVibration() throws Exception {
- int originalValue =
- Settings.System.getInt(
- mContentResolver, Settings.System.HAPTIC_FEEDBACK_ENABLED, -1);
+ Vibrator mVibrator =
+ (Vibrator)
+ getInstrumentation()
+ .getTargetContext()
+ .getSystemService(Context.VIBRATOR_SERVICE);
+ assumeTrue(
+ "Device Under Test does not have a vibrator, skipping.", mVibrator.hasVibrator());
+
+ int originalValue = prepareSystemSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED);
assertTrue("Touch vibration does not exist.", originalValue != -1);
mBackupUtils.backupNowAndAssertSuccess(SETTINGS_PACKAGE_NAME);
- boolean ret =
- Settings.System.putInt(
- mContentResolver, Settings.System.HAPTIC_FEEDBACK_ENABLED,
- 1 - originalValue);
+ boolean ret = setSystemSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED,
+ 1 - originalValue);
assertTrue("Toggle Touch vibration fail.", ret);
mBackupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, SETTINGS_PACKAGE_NAME);
@@ -163,4 +179,33 @@
mContentResolver, Settings.System.HAPTIC_FEEDBACK_ENABLED, -1);
assertTrue("Touch vibration restore fail.", originalValue == restoreValue);
}
+
+ private int prepareSystemSetting(String name) throws Exception {
+ int value = Settings.System.getInt(mContentResolver, name, SETTING_ABSENT_VALUE);
+ if (value == SETTING_ABSENT_VALUE) {
+ return SETTING_ABSENT_VALUE;
+ }
+
+ mOriginalSettingValues.put(name, value);
+ clearSystemSettingState(name);
+ setSystemSetting(name, value);
+
+ return value;
+ }
+
+ private boolean setSystemSetting(String name, int value) {
+ return Settings.System.putString(mContentResolver, name, String.valueOf(value),
+ /* overrideableByRestore */ true);
+ }
+
+ private void restoreOriginalSettingValues() throws Exception {
+ for (String settingName : mOriginalSettingValues.keySet()) {
+ clearSystemSettingState(settingName);
+ setSystemSetting(settingName, mOriginalSettingValues.get(settingName));
+ }
+ }
+
+ private void clearSystemSettingState(String setting) throws Exception {
+ mBackupUtils.executeShellCommandSync("settings delete system " + setting);
+ }
}
\ No newline at end of file
diff --git a/hostsidetests/backup/PreservedSettingsApp/src/android/cts/backup/preservedsettingsapp/PreservedSettingsRestoreTest.java b/hostsidetests/backup/PreservedSettingsApp/src/android/cts/backup/preservedsettingsapp/PreservedSettingsRestoreTest.java
index 29a1bd2..0f1de51 100644
--- a/hostsidetests/backup/PreservedSettingsApp/src/android/cts/backup/preservedsettingsapp/PreservedSettingsRestoreTest.java
+++ b/hostsidetests/backup/PreservedSettingsApp/src/android/cts/backup/preservedsettingsapp/PreservedSettingsRestoreTest.java
@@ -94,10 +94,8 @@
@Test
public void modifySettings() {
- SystemUtil.runWithShellPermissionIdentity(() -> {
- Settings.Secure.putString(mContentResolver, OVERRIDEABLE_SETTING,
- OVERRIDEABLE_SETTING_NEW_VALUE, /* overrideableByRestore */ true);
- });
+ Settings.Secure.putString(mContentResolver, OVERRIDEABLE_SETTING,
+ OVERRIDEABLE_SETTING_NEW_VALUE, /* overrideableByRestore */ true);
Settings.Secure.putString(mContentResolver, NON_OVERRIDEABLE_SETTING,
NON_OVERRIDEABLE_SETTING_NEW_VALUE);
}
diff --git a/hostsidetests/blobstore/src/com/android/cts/host/blob/InstantAppAccessTest.java b/hostsidetests/blobstore/src/com/android/cts/host/blob/InstantAppAccessTest.java
new file mode 100644
index 0000000..0c2c13a
--- /dev/null
+++ b/hostsidetests/blobstore/src/com/android/cts/host/blob/InstantAppAccessTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.host.blob;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class InstantAppAccessTest extends BaseBlobStoreHostTest {
+ private static final String TEST_CLASS = TARGET_PKG + ".InstantAppAccessTest";
+
+ @Before
+ public void setUp() throws Exception {
+ uninstallPackage(TARGET_PKG);
+ installPackage(TARGET_APK, "--instant");
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ uninstallPackage(TARGET_PKG);
+ }
+
+ @Test
+ public void testInstantAppAccess() throws Exception {
+ runDeviceTest(TARGET_PKG, TEST_CLASS, "testInstantAppAccess");
+ }
+}
diff --git a/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/DataCleanupTest.java b/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/DataCleanupTest.java
index 5bb82b9..72b907e 100644
--- a/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/DataCleanupTest.java
+++ b/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/DataCleanupTest.java
@@ -34,7 +34,6 @@
import org.junit.runner.RunWith;
import java.util.Base64;
-import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@@ -59,7 +58,6 @@
private Context mContext;
private Instrumentation mInstrumentation;
private BlobStoreManager mBlobStoreManager;
- private Random mRandom;
@Before
public void setUp() {
@@ -67,12 +65,14 @@
mContext = mInstrumentation.getContext();
mBlobStoreManager = (BlobStoreManager) mContext.getSystemService(
Context.BLOB_STORE_SERVICE);
- mRandom = new Random(24 /* seed */);
}
@Test
public void testCreateSession() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext, mRandom, "test_data_blob");
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext)
+ .setRandomSeed(24)
+ .setFileName("test_blob_data")
+ .build();
blobData.prepare();
final long sessionId = createSession(blobData.getBlobHandle());
@@ -106,8 +106,11 @@
@Test
public void testCommitBlob() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext, mRandom,
- "test_data_blob", "test_data_blob");
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext)
+ .setRandomSeed(24)
+ .setFileName("test_blob_data")
+ .setLabel("test_data_blob_label")
+ .build();
blobData.prepare();
final long sessionId = createSession(blobData.getBlobHandle());
diff --git a/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/DataPersistenceTest.java b/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/DataPersistenceTest.java
index b4226a6..72c6847 100644
--- a/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/DataPersistenceTest.java
+++ b/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/DataPersistenceTest.java
@@ -31,7 +31,6 @@
import org.junit.runner.RunWith;
import java.util.Base64;
-import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@@ -53,19 +52,20 @@
private Context mContext;
private BlobStoreManager mBlobStoreManager;
- private Random mRandom;
@Before
public void setUp() {
mContext = InstrumentationRegistry.getInstrumentation().getContext();
mBlobStoreManager = (BlobStoreManager) mContext.getSystemService(
Context.BLOB_STORE_SERVICE);
- mRandom = new Random(22 /* seed */);
}
@Test
public void testCreateSession() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext, mRandom, "test_data_blob");
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext)
+ .setRandomSeed(22)
+ .setFileName("test_blob_data")
+ .build();
blobData.prepare();
final long sessionId = createSession(blobData.getBlobHandle());
@@ -84,7 +84,10 @@
@Test
public void testOpenSessionAndWrite() throws Exception {
final long sessionId = readSessionIdFromDisk();
- final DummyBlobData blobData = new DummyBlobData(mContext, mRandom, "test_data_blob");
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext)
+ .setRandomSeed(22)
+ .setFileName("test_blob_data")
+ .build();
try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
assertThat(session.getSize()).isEqualTo(PARTIAL_FILE_LENGTH_BYTES);
blobData.writeToSession(session, PARTIAL_FILE_LENGTH_BYTES,
diff --git a/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/InstantAppAccessTest.java b/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/InstantAppAccessTest.java
new file mode 100644
index 0000000..4d7fd48
--- /dev/null
+++ b/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/InstantAppAccessTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.device.blob;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+@RunWith(AndroidJUnit4.class)
+public class InstantAppAccessTest {
+ @Test
+ public void testInstantAppAccess() {
+ final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ assertThat(context.getPackageManager().isInstantApp()).isTrue();
+ assertThat(context.getSystemService(Context.BLOB_STORE_SERVICE)).isNull();
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsPermissionToInteractTest.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsPermissionToInteractTest.java
index 485aec8..1b44d36 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsPermissionToInteractTest.java
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsPermissionToInteractTest.java
@@ -18,6 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
@@ -129,10 +131,13 @@
}
@Test
- public void testCreateRequestInteractAcrossProfilesIntent_canNotRequestInteraction_returnsNull() {
- Intent intent = mCrossProfileApps.createRequestInteractAcrossProfilesIntent();
-
- assertThat(intent).isNull();
+ public void testCreateRequestInteractAcrossProfilesIntent_canNotRequestInteraction_throwsSecurityException() {
+ try {
+ mCrossProfileApps.createRequestInteractAcrossProfilesIntent();
+ } catch (SecurityException e) {
+ return;
+ }
+ fail("Should throw a Security Exception");
}
/**
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java
index be5c4b1..57eb0f8 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java
@@ -25,6 +25,7 @@
import static org.junit.Assert.fail;
import android.app.Activity;
+import android.app.ActivityOptions;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -202,6 +203,32 @@
}
@Test
+ public void testCanStartMainActivityByIntent_withOptionsBundle() throws Exception {
+ Intent mainActivityIntent = new Intent();
+ mainActivityIntent.setComponent(MainActivity.getComponentName(mContext));
+
+ try {
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ mCrossProfileApps,
+ crossProfileApps ->
+ mCrossProfileApps.startActivity(
+ mainActivityIntent,
+ mTargetUser,
+ /* callingActivity= */ null,
+ ActivityOptions.makeBasic().toBundle()));
+
+ // Look for the text view to verify that MainActivity is started.
+ UiObject2 textView = mDevice.wait(Until.findObject(By.res(ID_USER_TEXTVIEW)),
+ TIMEOUT_WAIT_UI);
+ assertNotNull("Failed to start main activity in target user", textView);
+ assertEquals("Main Activity is started in wrong user",
+ String.valueOf(mUserSerialNumber), textView.getText());
+ } catch (Exception e) {
+ fail("unable to start main activity via CrossProfileApps#startActivity: " + e);
+ }
+ }
+
+ @Test
public void testCanStartNonMainActivityByIntent() {
Intent nonMainActivityIntent = new Intent();
nonMainActivityIntent.setComponent(NonMainActivity.getComponentName(mContext));
@@ -250,8 +277,8 @@
}
/**
- * Calls {@link CrossProfileApps#startActivity(Intent, UserHandle, Activity)}. This can then be used by
- * host-side tests.
+ * Calls {@link CrossProfileApps#startActivity(Intent, UserHandle, Activity)}. This can then be
+ * used by host-side tests.
*/
@Test
public void testStartActivityByIntent_noAsserts() throws Exception {
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AudioRestrictionTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AudioRestrictionTest.java
index ffceb36..6fa0bcb 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AudioRestrictionTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AudioRestrictionTest.java
@@ -29,12 +29,14 @@
import java.util.Objects;
import java.util.concurrent.Callable;
+import java.util.regex.Pattern;
public class AudioRestrictionTest extends BaseDeviceAdminTest {
private static final String TAG = AudioRestrictionTest.class.getSimpleName();
private AudioManager mAudioManager;
private PackageManager mPackageManager;
private boolean mUseFixedVolume;
+ private boolean mUseFullVolume;
private final Callable<Boolean> mCheckIfMasterVolumeMuted = new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
@@ -49,6 +51,7 @@
mPackageManager = mContext.getPackageManager();
mUseFixedVolume = mContext.getResources().getBoolean(
Resources.getSystem().getIdentifier("config_useFixedVolume", "bool", "android"));
+ mUseFullVolume = isFullVolumeDevice();
}
// Here we test that DISALLOW_ADJUST_VOLUME disallows to unmute volume.
@@ -86,7 +89,8 @@
}
public void testDisallowAdjustVolume() throws Exception {
- if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT) || mUseFixedVolume) {
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)
+ || mUseFixedVolume || mUseFullVolume) {
return;
}
@@ -186,4 +190,17 @@
Thread.sleep(200);
}
}
+
+ private boolean isFullVolumeDevice() {
+ String commandOutput = runShellCommand("dumpsys audio");
+
+ for (String line : commandOutput.split("\\r?\\n")) {
+ if (Pattern.matches("\\s*mHdmiCecSink=true", line)
+ || (Pattern.matches("\\s*mHdmiPlayBackClient=", line)
+ && !Pattern.matches("=null$", line))) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CommonCriteriaModeTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CommonCriteriaModeTest.java
index 726dd87..e70e9a5 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CommonCriteriaModeTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CommonCriteriaModeTest.java
@@ -21,9 +21,11 @@
try {
// Default to false
assertFalse(mDevicePolicyManager.isCommonCriteriaModeEnabled(ADMIN_RECEIVER_COMPONENT));
+ assertFalse(mDevicePolicyManager.isCommonCriteriaModeEnabled(null));
mDevicePolicyManager.setCommonCriteriaModeEnabled(ADMIN_RECEIVER_COMPONENT, true);
assertTrue(mDevicePolicyManager.isCommonCriteriaModeEnabled(ADMIN_RECEIVER_COMPONENT));
+ assertTrue(mDevicePolicyManager.isCommonCriteriaModeEnabled(null));
} finally {
mDevicePolicyManager.setCommonCriteriaModeEnabled(ADMIN_RECEIVER_COMPONENT, false);
}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java
index 036f4a2..61fdb18 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java
@@ -154,11 +154,12 @@
mDevicePolicyManager.setAutoTimeRequired(ADMIN_RECEIVER_COMPONENT, initialValue);
}
- public void testSetAutoTime() {
- final boolean initialValue = mDevicePolicyManager.getAutoTime(ADMIN_RECEIVER_COMPONENT);
- mDevicePolicyManager.setAutoTime(ADMIN_RECEIVER_COMPONENT, true);
- mDevicePolicyManager.setAutoTime(ADMIN_RECEIVER_COMPONENT, false);
- mDevicePolicyManager.setAutoTime(ADMIN_RECEIVER_COMPONENT, initialValue);
+ public void testSetAutoTimeEnabled() {
+ final boolean initialValue = mDevicePolicyManager.getAutoTimeEnabled(
+ ADMIN_RECEIVER_COMPONENT);
+ mDevicePolicyManager.setAutoTimeEnabled(ADMIN_RECEIVER_COMPONENT, true);
+ mDevicePolicyManager.setAutoTimeEnabled(ADMIN_RECEIVER_COMPONENT, false);
+ mDevicePolicyManager.setAutoTimeEnabled(ADMIN_RECEIVER_COMPONENT, initialValue);
}
public void testEnableSystemAppLogged() {
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskTest.java
index 78b5b2e..c791f25 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskTest.java
@@ -346,6 +346,43 @@
mDevicePolicyManager.setLockTaskFeatures(ADMIN_COMPONENT, 0);
}
+ // When LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK is set, the system dialog will also be
+ // shown when an un-whitelisted app is being launched in a new task.
+ public void testStartActivity_newTask_blockInTask() throws Exception {
+ mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
+ mDevicePolicyManager.setLockTaskFeatures(
+ ADMIN_COMPONENT, LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK);
+ startLockTask(UTILITY_ACTIVITY);
+ waitForResume();
+
+ mIsReceiverActivityRunning = false;
+ Intent launchIntent = createReceiverActivityIntent(true /*newTask*/, false /*shouldWait*/);
+ Intent lockTaskUtility = getLockTaskUtility(UTILITY_ACTIVITY);
+ lockTaskUtility.putExtra(LockTaskUtilityActivity.START_ACTIVITY, launchIntent);
+ mContext.startActivity(lockTaskUtility);
+
+ synchronized (mReceiverActivityRunningLock) {
+ mReceiverActivityRunningLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
+ assertFalse(mIsReceiverActivityRunning);
+ }
+
+ Log.d(TAG, "Waiting for the system dialog");
+ mUiDevice.waitForIdle();
+ assertTrue(mUiDevice.wait(
+ Until.hasObject(By.textContains(RECEIVER_ACTIVITY_PACKAGE_NAME)),
+ ACTIVITY_RESUMED_TIMEOUT_MILLIS));
+ Log.d(TAG, "dialog found");
+
+ // Dismiss the system dialog
+ mUiDevice.pressKeyCode(KeyEvent.KEYCODE_ENTER);
+ mUiDevice.pressKeyCode(KeyEvent.KEYCODE_ENTER);
+ assertFalse(mUiDevice.wait(
+ Until.hasObject(By.textContains(RECEIVER_ACTIVITY_PACKAGE_NAME)),
+ ACTIVITY_RESUMED_TIMEOUT_MILLIS));
+
+ mDevicePolicyManager.setLockTaskFeatures(ADMIN_COMPONENT, 0);
+ }
+
// This launches a whitelisted activity that is not part of the current task.
// This should be permitted as a part of lock task.
public void testStartActivity_outsideTaskWhitelisted() throws Exception {
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SetPolicyActivity.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SetPolicyActivity.java
index 6e92dda..1469e5a 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SetPolicyActivity.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SetPolicyActivity.java
@@ -21,9 +21,9 @@
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
-import android.os.Handler;
import android.os.Process;
import android.util.Log;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -62,16 +62,6 @@
handleIntent(intent);
}
- @Override
- public void onResume() {
- super.onResume();
- // Posting finish() here because:
- // - calling it directly in onResume() or sooner makes
- // "adb shell am start" timeout if using the -W option.
- // - calling it in onPause() or later does nothing
- Handler.getMain().post(this::finish);
- }
-
private void handleIntent(Intent intent) {
DevicePolicyManager dpm = (DevicePolicyManager)
getSystemService(Context.DEVICE_POLICY_SERVICE);
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/TimeManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/TimeManagementTest.java
index 24428d8..1f33446 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/TimeManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/TimeManagementTest.java
@@ -39,18 +39,18 @@
super.tearDown();
}
- public void testSetAutoTimeZone() {
- mDevicePolicyManager.setAutoTimeZone(ADMIN_RECEIVER_COMPONENT, true);
+ public void testSetAutoTimeZoneEnabled() {
+ mDevicePolicyManager.setAutoTimeZoneEnabled(ADMIN_RECEIVER_COMPONENT, true);
- assertThat(mDevicePolicyManager.getAutoTimeZone(ADMIN_RECEIVER_COMPONENT)).isTrue();
+ assertThat(mDevicePolicyManager.getAutoTimeZoneEnabled(ADMIN_RECEIVER_COMPONENT)).isTrue();
- mDevicePolicyManager.setAutoTimeZone(ADMIN_RECEIVER_COMPONENT, false);
+ mDevicePolicyManager.setAutoTimeZoneEnabled(ADMIN_RECEIVER_COMPONENT, false);
- assertThat(mDevicePolicyManager.getAutoTimeZone(ADMIN_RECEIVER_COMPONENT)).isFalse();
+ assertThat(mDevicePolicyManager.getAutoTimeZoneEnabled(ADMIN_RECEIVER_COMPONENT)).isFalse();
}
public void testSetTime() {
- mDevicePolicyManager.setAutoTime(ADMIN_RECEIVER_COMPONENT, false);
+ mDevicePolicyManager.setAutoTimeEnabled(ADMIN_RECEIVER_COMPONENT, false);
final long estimatedNow = mStartTimeWallClockMillis +
TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - mStartTimeElapsedNanos);
@@ -59,20 +59,20 @@
}
public void testSetTime_failWhenAutoTimeEnabled() {
- mDevicePolicyManager.setAutoTime(ADMIN_RECEIVER_COMPONENT, true);
+ mDevicePolicyManager.setAutoTimeEnabled(ADMIN_RECEIVER_COMPONENT, true);
assertThat(mDevicePolicyManager.setTime(ADMIN_RECEIVER_COMPONENT, 0)).isFalse();
}
public void testSetTimeZone() {
- mDevicePolicyManager.setAutoTimeZone(ADMIN_RECEIVER_COMPONENT, false);
+ mDevicePolicyManager.setAutoTimeZoneEnabled(ADMIN_RECEIVER_COMPONENT, false);
assertThat(
mDevicePolicyManager.setTimeZone(ADMIN_RECEIVER_COMPONENT, "Singapore")).isTrue();
}
public void testSetTimeZone_failIfAutoTimeZoneEnabled() {
- mDevicePolicyManager.setAutoTimeZone(ADMIN_RECEIVER_COMPONENT, true);
+ mDevicePolicyManager.setAutoTimeZoneEnabled(ADMIN_RECEIVER_COMPONENT, true);
assertThat(
mDevicePolicyManager.setTimeZone(ADMIN_RECEIVER_COMPONENT, "Singapore")).isFalse();
@@ -84,12 +84,12 @@
}
private void restoreTime() {
- mDevicePolicyManager.setAutoTime(ADMIN_RECEIVER_COMPONENT, false);
+ mDevicePolicyManager.setAutoTimeEnabled(ADMIN_RECEIVER_COMPONENT, false);
final long estimatedNow = mStartTimeWallClockMillis +
TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - mStartTimeElapsedNanos);
mDevicePolicyManager.setTime(ADMIN_RECEIVER_COMPONENT, estimatedNow);
- mDevicePolicyManager.setAutoTime(ADMIN_RECEIVER_COMPONENT, true);
+ mDevicePolicyManager.setAutoTimeEnabled(ADMIN_RECEIVER_COMPONENT, true);
}
}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SetPolicyActivity.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SetPolicyActivity.java
index 514b9e8..5637912 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SetPolicyActivity.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SetPolicyActivity.java
@@ -50,14 +50,6 @@
handleIntent(intent);
}
- @Override
- public void onPause() {
- super.onPause();
- // Calling finish() here because doing it in onCreate(), onStart() or onResume() makes
- // "adb shell am start" timeout if using the -W option.
- finish();
- }
-
private void handleIntent(Intent intent) {
DevicePolicyManager dpm = (DevicePolicyManager)
getSystemService(Context.DEVICE_POLICY_SERVICE);
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SetTimeTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SetTimeTest.java
index acf142f..d296229 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SetTimeTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SetTimeTest.java
@@ -92,7 +92,7 @@
final BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (testTimeZone.equals(intent.getStringExtra("time-zone"))) {
+ if (testTimeZone.equals(intent.getStringExtra(Intent.EXTRA_TIMEZONE))) {
latch.countDown();
}
}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/ProtectedPackagesTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
similarity index 71%
rename from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/ProtectedPackagesTest.java
rename to hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
index 4489bdb..91ca612 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/ProtectedPackagesTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
@@ -21,13 +21,14 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import java.util.ArrayList;
+import java.util.Collections;
/**
- * Test {@link DevicePolicyManager#setProtectedPackages} and
- * {@link DevicePolicyManager#getProtectedPackages}
+ * Test {@link DevicePolicyManager#setUserControlDisabledPackages} and
+ * {@link DevicePolicyManager#getUserControlDisabledPackages}
* Hostside test uses "am force-stop" and verifies that app is not stopped.
*/
-public class ProtectedPackagesTest extends BaseDeviceOwnerTest {
+public class UserControlDisabledPackagesTest extends BaseDeviceOwnerTest {
private static final String TEST_APP_APK = "CtsEmptyTestApp.apk";
private static final String TEST_APP_PKG = "android.packageinstaller.emptytestapp.cts";
@@ -36,10 +37,10 @@
private static final String SIMPLE_APP_ACTIVITY =
"com.android.cts.launcherapps.simpleapp.SimpleActivityImmediateExit";
- public void testSetProtectedPackages() throws Exception {
+ public void testSetUserControlDisabledPackages() throws Exception {
ArrayList<String> protectedPackages= new ArrayList<>();
protectedPackages.add(SIMPLE_APP_PKG);
- mDevicePolicyManager.setProtectedPackages(getWho(), protectedPackages);
+ mDevicePolicyManager.setUserControlDisabledPackages(getWho(), protectedPackages);
// Launch app so that the app exits stopped state.
Intent intent = new Intent(Intent.ACTION_MAIN);
@@ -49,21 +50,23 @@
}
- public void testForceStopForProtectedPackages() throws Exception {
+ public void testForceStopWithUserControlDisabled() throws Exception {
final ArrayList<String> pkgs = new ArrayList<>();
pkgs.add(SIMPLE_APP_PKG);
assertFalse(isPackageStopped(SIMPLE_APP_PKG));
- assertEquals(pkgs, mDevicePolicyManager.getProtectedPackages(getWho()));
+ assertEquals(pkgs, mDevicePolicyManager.getUserControlDisabledPackages(getWho()));
}
- public void testClearProtectedPackages() throws Exception {
+ public void testClearSetUserControlDisabledPackages() throws Exception {
final ArrayList<String> pkgs = new ArrayList<>();
- mDevicePolicyManager.setProtectedPackages(getWho(), pkgs);
- assertEquals(pkgs, mDevicePolicyManager.getProtectedPackages(getWho()));
+ mDevicePolicyManager.setUserControlDisabledPackages(getWho(), pkgs);
+ assertEquals(pkgs, mDevicePolicyManager.getUserControlDisabledPackages(getWho()));
}
- public void testForceStopForUnprotectedPackages() throws Exception {
+ public void testForceStopWithUserControlEnabled() throws Exception {
assertTrue(isPackageStopped(SIMPLE_APP_PKG));
+ assertEquals(Collections.emptyList(),
+ mDevicePolicyManager.getUserControlDisabledPackages(getWho()));
}
private boolean isPackageStopped(String packageName) throws Exception {
diff --git a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java
index 5871ed8..bd95a35 100644
--- a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java
+++ b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java
@@ -3,7 +3,9 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
+import android.provider.Settings;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.Direction;
@@ -14,21 +16,11 @@
public class SuspendPackageTest extends InstrumentationTestCase {
private static final int WAIT_DIALOG_TIMEOUT_IN_MS = 5000;
- private static final BySelector POPUP_IMAGE_SELECTOR = By
- .clazz(android.widget.ImageView.class.getName())
- .res("com.android.settings:id/admin_support_icon")
- .pkg("com.android.settings");
-
private static final BySelector POPUP_TITLE_WATCH_SELECTOR = By
.clazz(android.widget.TextView.class.getName())
.res("android:id/alertTitle")
.pkg("com.google.android.apps.wearable.settings");
- private static final BySelector POPUP_BUTTON_SELECTOR = By
- .clazz(android.widget.Button.class.getName())
- .res("android:id/button1")
- .pkg("com.android.settings");
-
private static final BySelector SUSPEND_BUTTON_SELECTOR = By
.clazz(android.widget.Button.class.getName())
.res("android:id/button1");
@@ -100,11 +92,11 @@
assertNotNull("Policy transparency dialog title not found", title);
title.swipe(Direction.RIGHT, 1.0f);
} else {
- device.wait(Until.hasObject(POPUP_IMAGE_SELECTOR), WAIT_DIALOG_TIMEOUT_IN_MS);
- final UiObject2 icon = device.findObject(POPUP_IMAGE_SELECTOR);
+ device.wait(Until.hasObject(getPopUpImageSelector()), WAIT_DIALOG_TIMEOUT_IN_MS);
+ final UiObject2 icon = device.findObject(getPopUpImageSelector());
assertNotNull("Policy transparency dialog icon not found", icon);
// "OK" button only present in the dialog if it is blocked by policy.
- final UiObject2 button = device.findObject(POPUP_BUTTON_SELECTOR);
+ final UiObject2 button = device.findObject(getPopUpButtonSelector());
assertNotNull("OK button not found", button);
button.click();
}
@@ -122,4 +114,27 @@
return (getInstrumentation().getContext().getResources().getConfiguration().uiMode
& Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_WATCH;
}
+
+ private String getSettingsPackageName() {
+ String settingsPackageName = "com.android.settings";
+ ResolveInfo resolveInfo = mPackageManager.resolveActivity(
+ new Intent(Settings.ACTION_SETTINGS), PackageManager.MATCH_SYSTEM_ONLY);
+ if (resolveInfo != null && resolveInfo.activityInfo != null) {
+ settingsPackageName = resolveInfo.activityInfo.packageName;
+ }
+ return settingsPackageName;
+ }
+
+ private BySelector getPopUpButtonSelector() {
+ return By.clazz(android.widget.Button.class.getName())
+ .res("android:id/button1")
+ .pkg(getSettingsPackageName());
+ }
+
+ private BySelector getPopUpImageSelector() {
+ final String settingsPackageName = getSettingsPackageName();
+ return By.clazz(android.widget.ImageView.class.getName())
+ .res(settingsPackageName + ":id/admin_support_icon")
+ .pkg(settingsPackageName);
+ }
}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp b/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp
index c4f227c..4bd90fa 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp
@@ -31,7 +31,6 @@
"testng",
"androidx.legacy_legacy-support-v4",
],
- sdk_version: "test_current",
min_sdk_version: "27",
// tag this module as a cts test artifact
test_suites: [
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
index 3a3d7fb..5bcf4be 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
@@ -85,8 +85,8 @@
.add("isDeviceIdAttestationSupported")
.add("isUniqueDeviceAttestationSupported")
.add("wipeData")
- .add("getAutoTime")
- .add("setAutoTime")
+ .add("getAutoTimeEnabled")
+ .add("setAutoTimeEnabled")
.add("addUserRestriction")
.add("clearUserRestriction")
.add("getUserRestrictions")
@@ -169,10 +169,11 @@
public void testCannotCallAutoTimeMethodsOnParentProfile() {
assertThrows(SecurityException.class,
- () -> mParentDevicePolicyManager.setAutoTime(ADMIN_RECEIVER_COMPONENT, true));
+ () -> mParentDevicePolicyManager.setAutoTimeEnabled(ADMIN_RECEIVER_COMPONENT,
+ true));
assertThrows(SecurityException.class,
- () -> mParentDevicePolicyManager.getAutoTime(ADMIN_RECEIVER_COMPONENT));
+ () -> mParentDevicePolicyManager.getAutoTimeEnabled(ADMIN_RECEIVER_COMPONENT));
}
public void testCannotCallSetDefaultSmsApplicationOnParentProfile() {
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/SetPolicyActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/SetPolicyActivity.java
index f59363b..091d1b9 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/SetPolicyActivity.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/SetPolicyActivity.java
@@ -23,8 +23,6 @@
import android.os.Process;
import android.util.Log;
-import com.android.cts.managedprofile.BaseManagedProfileTest;
-
/**
* Simple activity that adds or clears a user restriction depending on the value of the extras.
*/
@@ -54,14 +52,6 @@
handleIntent(intent);
}
- @Override
- public void onPause() {
- super.onPause();
- // Calling finish() here because doing it in onCreate(), onStart() or onResume() makes
- // "adb shell am start" timeout if using the -W option.
- finish();
- }
-
private void handleIntent(Intent intent) {
DevicePolicyManager dpm = (DevicePolicyManager)
getSystemService(Context.DEVICE_POLICY_SERVICE);
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java
index 4f0ce40..57cbab9 100644
--- a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java
@@ -51,7 +51,7 @@
protected Context mContext;
protected UiDevice mDevice;
protected DevicePolicyManager mDevicePolicyManager;
- private PackageManager mPackageManager;
+ protected PackageManager mPackageManager;
private PackageInstaller mPackageInstaller;
private PackageInstaller.Session mSession;
protected boolean mCallbackReceived;
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java
index 88c3df9..3057273 100644
--- a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java
@@ -18,6 +18,9 @@
import android.content.Intent;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.Settings;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.UiObject2;
@@ -32,14 +35,6 @@
private static final int AUTOMATOR_WAIT_TIMEOUT = 5000;
private static final int INSTALL_WAIT_TIME = 5000;
- private static final BySelector POPUP_BUTTON_SELECTOR = By
- .clazz(android.widget.Button.class.getName())
- .res("android:id/button1")
- .pkg("com.android.settings");
- private static final BySelector POPUP_IMAGE_SELECTOR = By
- .clazz(android.widget.ImageView.class.getName())
- .res("com.android.settings:id/admin_support_icon")
- .pkg("com.android.settings");
private static final BySelector INSTALL_BUTTON_SELECTOR = By.text(Pattern.compile("Install",
Pattern.CASE_INSENSITIVE));
@@ -106,12 +101,35 @@
}
private void automateDismissInstallBlockedDialog() {
- mDevice.wait(Until.hasObject(POPUP_IMAGE_SELECTOR), AUTOMATOR_WAIT_TIMEOUT);
- UiObject2 icon = mDevice.findObject(POPUP_IMAGE_SELECTOR);
+ mDevice.wait(Until.hasObject(getPopUpImageSelector()), AUTOMATOR_WAIT_TIMEOUT);
+ UiObject2 icon = mDevice.findObject(getPopUpImageSelector());
assertNotNull("Policy transparency dialog icon not found", icon);
// "OK" button only present in the dialog if it is blocked by policy.
- UiObject2 button = mDevice.findObject(POPUP_BUTTON_SELECTOR);
+ UiObject2 button = mDevice.findObject(getPopUpButtonSelector());
assertNotNull("OK button not found", button);
button.click();
}
+
+ private String getSettingsPackageName() {
+ String settingsPackageName = "com.android.settings";
+ ResolveInfo resolveInfo = mPackageManager.resolveActivity(
+ new Intent(Settings.ACTION_SETTINGS), PackageManager.MATCH_SYSTEM_ONLY);
+ if (resolveInfo != null && resolveInfo.activityInfo != null) {
+ settingsPackageName = resolveInfo.activityInfo.packageName;
+ }
+ return settingsPackageName;
+ }
+
+ private BySelector getPopUpButtonSelector() {
+ return By.clazz(android.widget.Button.class.getName())
+ .res("android:id/button1")
+ .pkg(getSettingsPackageName());
+ }
+
+ private BySelector getPopUpImageSelector() {
+ final String settingsPackageName = getSettingsPackageName();
+ return By.clazz(android.widget.ImageView.class.getName())
+ .res(settingsPackageName + ":id/admin_support_icon")
+ .pkg(settingsPackageName);
+ }
}
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml
index 5e563d4..a25a1ee 100644
--- a/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml
@@ -73,6 +73,14 @@
</intent-filter>
</service>
+ <service android:name=".SimpleService6" android:exported="true"
+ android:isolatedProcess="true">
+ <intent-filter>
+ <action android:name="com.android.cts.launchertests.simpleapp.EXIT_ACTION" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </service>
+
<receiver android:name=".SimpleReceiverStartService" android:exported="true">
</receiver>
<receiver android:name=".SimpleReceiver" android:exported="true">
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleService4.java b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleService4.java
index 43fb201..7bcccc5 100644
--- a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleService4.java
+++ b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleService4.java
@@ -16,6 +16,7 @@
package com.android.cts.launcherapps.simpleapp;
+import android.app.ActivityManager;
import android.app.Service;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -32,6 +33,10 @@
import android.system.OsConstants;
import android.util.Log;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
/**
* A simple service which accepts various test command.
*/
@@ -43,6 +48,7 @@
private static final String EXTRA_ACTION = "action";
private static final String EXTRA_MESSENGER = "messenger";
private static final String EXTRA_PROCESS_NAME = "process";
+ private static final String EXTRA_COOKIE = "cookie";
private static final String STUB_PROVIDER_AUTHORITY =
"com.android.cts.launcherapps.simpleapp.provider";
@@ -73,6 +79,7 @@
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
sendPidBack(intent);
+ setCookieIfNeeded(intent);
// perform the action after return from here,
// make a delay, otherwise the system might try to restart the service
// if the process dies before the system realize it's asking for START_NOT_STICKY.
@@ -86,7 +93,11 @@
}
protected String getProcessName() {
- return getPackageName();
+ try (BufferedReader reader = new BufferedReader(new FileReader("/proc/self/cmdline"))) {
+ return reader.readLine().trim();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
private void sendPidBack(Intent intent) {
@@ -143,4 +154,12 @@
}
}
}
+
+ private void setCookieIfNeeded(final Intent intent) {
+ if (intent.hasExtra(EXTRA_COOKIE)) {
+ byte[] cookie = intent.getByteArrayExtra(EXTRA_COOKIE);
+ ActivityManager am = getSystemService(ActivityManager.class);
+ am.setProcessStateSummary(cookie);
+ }
+ }
}
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleService5.java b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleService5.java
index 03cd807..0945a6a 100644
--- a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleService5.java
+++ b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleService5.java
@@ -20,8 +20,4 @@
* A simple service which extends SimpleService4
*/
public class SimpleService5 extends SimpleService4 {
- @Override
- protected String getProcessName() {
- return getPackageName() + ":remote";
- }
}
diff --git a/apps/CtsVerifier/jni/audio_loopback/audio_utils/roundup.h b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleService6.java
similarity index 65%
rename from apps/CtsVerifier/jni/audio_loopback/audio_utils/roundup.h
rename to hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleService6.java
index ad34289..82df88b 100644
--- a/apps/CtsVerifier/jni/audio_loopback/audio_utils/roundup.h
+++ b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleService6.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -14,18 +14,10 @@
* limitations under the License.
*/
-#ifndef ANDROID_AUDIO_ROUNDUP_H
-#define ANDROID_AUDIO_ROUNDUP_H
+package com.android.cts.launcherapps.simpleapp;
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Round up to the next highest power of 2
-unsigned roundup(unsigned v);
-
-#ifdef __cplusplus
+/**
+ * A simple service which extends SimpleService4, but runs as isolated.
+ */
+public class SimpleService6 extends SimpleService4 {
}
-#endif
-
-#endif // ANDROID_AUDIO_ROUNDUP_H
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java
index d427645..345c91e 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java
@@ -127,6 +127,7 @@
}
verifyCrossProfileAppsApi(mProfileId, mPrimaryUserId, START_ACTIVITY_TEST_CLASS, "testCannotStartActivityWithImplicitIntent");
verifyCrossProfileAppsApi(mProfileId, mPrimaryUserId, START_ACTIVITY_TEST_CLASS, "testCanStartMainActivityByIntent");
+ verifyCrossProfileAppsApi(mProfileId, mPrimaryUserId, START_ACTIVITY_TEST_CLASS, "testCanStartMainActivityByIntent_withOptionsBundle");
verifyCrossProfileAppsApi(mProfileId, mPrimaryUserId, START_ACTIVITY_TEST_CLASS, "testCanStartNonMainActivityByIntent");
verifyCrossProfileAppsApi(mProfileId, mPrimaryUserId, START_ACTIVITY_TEST_CLASS, "testCanStartNotExportedActivityByIntent");
verifyCrossProfileAppsApi(mProfileId, mPrimaryUserId, START_ACTIVITY_TEST_CLASS, "testCannotStartActivityInOtherPackageByIntent");
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsPermissionHostSideTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsPermissionHostSideTest.java
index ff3b70b..c07b87c 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsPermissionHostSideTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsPermissionHostSideTest.java
@@ -263,14 +263,14 @@
}
@Test
- public void testCreateRequestInteractAcrossProfilesIntent_canNotRequestInteraction_returnsNull()
+ public void testCreateRequestInteractAcrossProfilesIntent_canNotRequestInteraction_throwsSecurityException()
throws Exception {
installAppAsUser(TEST_WITH_REQUESTED_PERMISSION_APK, mPrimaryUserId);
runDeviceTestsAsUser(
TEST_WITH_REQUESTED_PERMISSION_PACKAGE,
TEST_WITH_REQUESTED_PERMISSION_CLASS,
- "testCreateRequestInteractAcrossProfilesIntent_canNotRequestInteraction_returnsNull",
+ "testCreateRequestInteractAcrossProfilesIntent_canNotRequestInteraction_throwsSecurityException",
mProfileId,
Collections.EMPTY_MAP);
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index d393b98..a447f63 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -1569,7 +1569,7 @@
@Test
public void testPrintingPolicy() throws Exception {
- if (!mHasFeature) {
+ if (!mHasFeature || !hasDeviceFeature("android.software.print")) {
return;
}
installAppAsUser(PRINTING_APP_APK, mUserId);
@@ -1944,12 +1944,12 @@
}
@Test
- public void testSetAutoTime() throws Exception {
+ public void testSetAutoTimeEnabled() throws Exception {
if (!mHasFeature) {
return;
}
assertMetricsLogged(getDevice(), () -> {
- executeDeviceTestMethod(".DevicePolicyLoggingTest", "testSetAutoTime");
+ executeDeviceTestMethod(".DevicePolicyLoggingTest", "testSetAutoTimeEnabled");
}, new DevicePolicyEventWrapper.Builder(EventId.SET_AUTO_TIME_VALUE)
.setAdminPackageName(DEVICE_ADMIN_PKG)
.setBoolean(true)
@@ -1961,12 +1961,12 @@
}
@Test
- public void testSetAutoTimeZone() throws Exception {
+ public void testSetAutoTimeZoneEnabled() throws Exception {
if (!mHasFeature) {
return;
}
assertMetricsLogged(getDevice(), () -> {
- executeDeviceTestMethod(".TimeManagementTest", "testSetAutoTimeZone");
+ executeDeviceTestMethod(".TimeManagementTest", "testSetAutoTimeZoneEnabled");
}, new DevicePolicyEventWrapper.Builder(EventId.SET_AUTO_TIME_ZONE_VALUE)
.setAdminPackageName(DEVICE_ADMIN_PKG)
.setBoolean(true)
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index e45e647..303baec 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -967,28 +967,32 @@
}
@Test
- public void testSetProtectedPackages() throws Exception {
+ public void testSetUserControlDisabledPackages() throws Exception {
if (!mHasFeature) {
return;
}
try {
installAppAsUser(SIMPLE_APP_APK, mPrimaryUserId);
assertMetricsLogged(getDevice(),
- () -> executeDeviceTestMethod(".ProtectedPackagesTest",
- "testSetProtectedPackages"),
- new DevicePolicyEventWrapper.Builder(EventId.SET_PACKAGES_PROTECTED_VALUE)
+ () -> executeDeviceTestMethod(".UserControlDisabledPackagesTest",
+ "testSetUserControlDisabledPackages"),
+ new DevicePolicyEventWrapper.Builder(
+ EventId.SET_USER_CONTROL_DISABLED_PACKAGES_VALUE)
.setAdminPackageName(DEVICE_OWNER_PKG)
.setStrings(new String[] {SIMPLE_APP_PKG})
.build());
forceStopPackageForUser(SIMPLE_APP_PKG, mPrimaryUserId);
- executeDeviceTestMethod(".ProtectedPackagesTest", "testForceStopForProtectedPackages");
+ executeDeviceTestMethod(".UserControlDisabledPackagesTest",
+ "testForceStopWithUserControlDisabled");
// Reboot and verify protected packages are persisted
rebootAndWaitUntilReady();
- executeDeviceTestMethod(".ProtectedPackagesTest", "testForceStopForProtectedPackages");
- executeDeviceTestMethod(".ProtectedPackagesTest", "testClearProtectedPackages");
+ executeDeviceTestMethod(".UserControlDisabledPackagesTest",
+ "testForceStopWithUserControlDisabled");
+ executeDeviceTestMethod(".UserControlDisabledPackagesTest",
+ "testClearSetUserControlDisabledPackages");
forceStopPackageForUser(SIMPLE_APP_PKG, mPrimaryUserId);
- executeDeviceTestMethod(".ProtectedPackagesTest",
- "testForceStopForUnprotectedPackages");
+ executeDeviceTestMethod(".UserControlDisabledPackagesTest",
+ "testForceStopWithUserControlEnabled");
} finally {
getDevice().uninstallPackage(SIMPLE_APP_APK);
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java
index 6152f94..4fe211f 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java
@@ -491,6 +491,9 @@
}
installAllDummyApps();
getDevice().clearLogcat();
+ // Increase logcat size because the test is reading from it.
+ String command = "logcat -G 16M";
+ getDevice().executeShellCommand(command);
runWorkProfileDeviceTest(
".CrossProfileTest",
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
index 51a312b..7a61083 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
@@ -200,14 +200,14 @@
@Override
@Test
- public void testSetAutoTime() {
+ public void testSetAutoTimeEnabled() {
// Managed profile owner cannot set auto time unless it is called by the profile owner of
// an organization-owned managed profile.
}
@Override
@Test
- public void testSetAutoTimeZone() {
+ public void testSetAutoTimeZoneEnabled() {
// Managed profile owner cannot set auto time zone unless it is called by the profile
// owner of an organization-owned managed profile.
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java
index 2da4cba..66b2630 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java
@@ -101,7 +101,7 @@
@Override
@Test
- public void testSetAutoTimeZone() {
+ public void testSetAutoTimeZoneEnabled() {
// Profile owner cannot set auto time zone unless it is called by the profile
// owner of an organization-owned managed profile or a profile owner on user 0.
}
diff --git a/hostsidetests/gputools/apps/jni/android_gputools_cts_RootlessGpuDebug.cpp b/hostsidetests/gputools/apps/jni/android_gputools_cts_RootlessGpuDebug.cpp
index 8a27b9e..f62a583 100644
--- a/hostsidetests/gputools/apps/jni/android_gputools_cts_RootlessGpuDebug.cpp
+++ b/hostsidetests/gputools/apps/jni/android_gputools_cts_RootlessGpuDebug.cpp
@@ -17,13 +17,15 @@
#define LOG_TAG "RootlessGpuDebug"
+#include <string>
+#include <vector>
+
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <android/log.h>
#include <android/native_window.h>
#include <jni.h>
#include <vulkan/vulkan.h>
-#include <string>
#define ALOGI(msg, ...) \
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, (msg), __VA_ARGS__)
@@ -39,6 +41,22 @@
std::string initVulkan() {
std::string result = "";
+ {
+ uint32_t count = 0;
+ vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
+ if (count > 0) {
+ std::vector<VkExtensionProperties> properties(count);
+ vkEnumerateInstanceExtensionProperties(nullptr, &count,
+ properties.data());
+ for (uint32_t i = 0; i < count; ++i) {
+ if (!strcmp("VK_EXT_debug_utils", properties[i].extensionName)) {
+ ALOGI("VK_EXT_debug_utils: %u", properties[i].specVersion);
+ break;
+ }
+ }
+ }
+ }
+
const VkApplicationInfo app_info = {
VK_STRUCTURE_TYPE_APPLICATION_INFO,
nullptr, // pNext
diff --git a/hostsidetests/gputools/layers/Android.bp b/hostsidetests/gputools/layers/Android.bp
index 9d12a7b..f0ee2c9 100644
--- a/hostsidetests/gputools/layers/Android.bp
+++ b/hostsidetests/gputools/layers/Android.bp
@@ -25,8 +25,6 @@
shared_libs: [
"libandroid",
"libvulkan",
- "libEGL",
- "libGLESv3",
"liblog",
],
stl: "c++_shared",
@@ -46,8 +44,6 @@
shared_libs: [
"libandroid",
"libvulkan",
- "libEGL",
- "libGLESv3",
"liblog",
],
stl: "c++_shared",
@@ -67,8 +63,46 @@
shared_libs: [
"libandroid",
"libvulkan",
- "libEGL",
- "libGLESv3",
+ "liblog",
+ ],
+ stl: "c++_shared",
+ sdk_version: "current",
+}
+
+cc_test_library {
+ name: "libVkLayer_nullLayerD",
+ gtest: false,
+ srcs: ["jni/nullLayer.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-fvisibility=hidden",
+ "-DLAYERNAME=D",
+ "-DDEBUGUTILSPECVERSION=1",
+ ],
+ shared_libs: [
+ "libandroid",
+ "libvulkan",
+ "liblog",
+ ],
+ stl: "c++_shared",
+ sdk_version: "current",
+}
+
+cc_test_library {
+ name: "libVkLayer_nullLayerE",
+ gtest: false,
+ srcs: ["jni/nullLayer.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-fvisibility=hidden",
+ "-DLAYERNAME=E",
+ "-DDEBUGUTILSPECVERSION=2",
+ ],
+ shared_libs: [
+ "libandroid",
+ "libvulkan",
"liblog",
],
stl: "c++_shared",
@@ -149,6 +183,8 @@
"libVkLayer_nullLayerA",
"libVkLayer_nullLayerB",
"libVkLayer_nullLayerC",
+ "libVkLayer_nullLayerD",
+ "libVkLayer_nullLayerE",
],
use_embedded_native_libs: false,
stl: "c++_shared",
diff --git a/hostsidetests/gputools/layers/jni/nullLayer.cpp b/hostsidetests/gputools/layers/jni/nullLayer.cpp
index c5f84ca..f772b36 100644
--- a/hostsidetests/gputools/layers/jni/nullLayer.cpp
+++ b/hostsidetests/gputools/layers/jni/nullLayer.cpp
@@ -14,19 +14,28 @@
* limitations under the License.
*/
-#include <android/log.h>
#include <cstring>
-#include <vulkan/vulkan.h>
+#include <string>
+
#include "vk_layer_interface.h"
+#include <android/log.h>
+#include <vulkan/vulkan.h>
#define xstr(a) str(a)
#define str(a) #a
-#define LOG_TAG "nullLayer" xstr(LAYERNAME)
+#define LAYER_FULL_NAME "VK_LAYER_ANDROID_nullLayer" xstr(LAYERNAME)
+#define LOG_TAG LAYER_FULL_NAME
#define ALOGI(msg, ...) \
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, (msg), __VA_ARGS__)
+#ifdef DEBUGUTILSPECVERSION
+const VkExtensionProperties debug_utils_extension = {
+ "VK_EXT_debug_utils",
+ static_cast<uint32_t>(std::atoi(xstr(DEBUGUTILSPECVERSION))),
+};
+#endif
// Announce if anything loads this layer. LAYERNAME is defined in Android.mk
class StaticLogMessage {
@@ -35,8 +44,8 @@
ALOGI("%s", msg);
}
};
-StaticLogMessage g_initMessage("nullLayer" xstr(LAYERNAME) " loaded");
-
+StaticLogMessage
+ g_initMessage("VK_LAYER_ANDROID_nullLayer" xstr(LAYERNAME) " loaded");
namespace {
@@ -68,7 +77,10 @@
}
static const VkLayerProperties LAYER_PROPERTIES = {
- "VK_LAYER_ANDROID_nullLayer" xstr(LAYERNAME), VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION), 1, "Layer: nullLayer" xstr(LAYERNAME),
+ LAYER_FULL_NAME,
+ VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION),
+ 1,
+ "Layer: nullLayer" xstr(LAYERNAME),
};
VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
@@ -82,7 +94,12 @@
VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char* /* pLayerName */, uint32_t *pCount,
VkExtensionProperties *pProperties) {
- return getProperties<VkExtensionProperties>(0, NULL, pCount, pProperties);
+#ifdef DEBUGUTILSPECVERSION
+ return getProperties<VkExtensionProperties>(1, &debug_utils_extension, pCount,
+ pProperties);
+#else
+ return getProperties<VkExtensionProperties>(0, NULL, pCount, pProperties);
+#endif
}
VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice /* physicalDevice */, const char* /* pLayerName */,
@@ -94,16 +111,13 @@
const VkDeviceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDevice* pDevice) {
-
VkLayerDeviceCreateInfo *layerCreateInfo = (VkLayerDeviceCreateInfo*)pCreateInfo->pNext;
-
- const char* msg = "nullCreateDevice called in nullLayer" xstr(LAYERNAME);
+ const char *msg = "nullCreateDevice called in " LAYER_FULL_NAME;
ALOGI("%s", msg);
// Step through the pNext chain until we get to the link function
while(layerCreateInfo && (layerCreateInfo->sType != VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO ||
layerCreateInfo->function != VK_LAYER_FUNCTION_LINK)) {
-
layerCreateInfo = (VkLayerDeviceCreateInfo *)layerCreateInfo->pNext;
}
@@ -131,16 +145,13 @@
VKAPI_ATTR VkResult VKAPI_CALL nullCreateInstance(const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance) {
-
VkLayerInstanceCreateInfo *layerCreateInfo = (VkLayerInstanceCreateInfo *)pCreateInfo->pNext;
-
- const char* msg = "nullCreateInstance called in nullLayer" xstr(LAYERNAME);
+ const char *msg = "nullCreateInstance called in " LAYER_FULL_NAME;
ALOGI("%s", msg);
// Step through the pNext chain until we get to the link function
while(layerCreateInfo && (layerCreateInfo->sType != VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO ||
layerCreateInfo->function != VK_LAYER_FUNCTION_LINK)) {
-
layerCreateInfo = (VkLayerInstanceCreateInfo *)layerCreateInfo->pNext;
}
diff --git a/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java b/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
index fb14756..4ec4ef8 100644
--- a/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
+++ b/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
@@ -60,6 +60,9 @@
// - Ensure we can still use system properties if no layers loaded via Settings (testSystemPropertyEnableVulkan)
// - Ensure we can find layers in separate specified app and load them in a debuggable app (testDebugLayerLoadExternalVulkan)
// - Ensure we can find layers in separate specified app and load them in an injectLayers app (testInjectLayerLoadExternalVulkan)
+ // - Ensure we can enumerate the instance extension advertised by implicitly enabled layer (testInstanceExtensionPropertiesFromImplicitLayerVulkanBasic)
+ // - Ensure we can only enumerate first instance extension closest to application
+ // when multiple implicitly enabled layers advertise the same extension (testInstanceExtensionPropertiesFromImplicitLayerVulkanMultipleLayers)
// Negative Vulkan tests
// - Ensure we cannot push a layer to non-debuggable app (testReleaseLayerLoadVulkan)
// - Ensure non-debuggable app ignores the new Settings (testReleaseLayerLoadVulkan)
@@ -87,19 +90,20 @@
// Positive combined tests
// - Ensure we can load Vulkan and GLES layers at the same time, from multiple external apps (testMultipleExternalApps)
-
-
private static final String CLASS = "RootlessGpuDebugDeviceActivity";
private static final String ACTIVITY = "android.rootlessgpudebug.app.RootlessGpuDebugDeviceActivity";
- private static final String LAYER_A = "nullLayerA";
- private static final String LAYER_B = "nullLayerB";
- private static final String LAYER_C = "nullLayerC";
- private static final String LAYER_A_LIB = "libVkLayer_" + LAYER_A + ".so";
- private static final String LAYER_B_LIB = "libVkLayer_" + LAYER_B + ".so";
- private static final String LAYER_C_LIB = "libVkLayer_" + LAYER_C + ".so";
- private static final String LAYER_A_NAME = "VK_LAYER_ANDROID_" + LAYER_A;
- private static final String LAYER_B_NAME = "VK_LAYER_ANDROID_" + LAYER_B;
- private static final String LAYER_C_NAME = "VK_LAYER_ANDROID_" + LAYER_C;
+ private static final String VK_LAYER_LIB_PREFIX = "libVkLayer_nullLayer";
+ private static final String VK_LAYER_A_LIB = VK_LAYER_LIB_PREFIX + "A.so";
+ private static final String VK_LAYER_B_LIB = VK_LAYER_LIB_PREFIX + "B.so";
+ private static final String VK_LAYER_C_LIB = VK_LAYER_LIB_PREFIX + "C.so";
+ private static final String VK_LAYER_D_LIB = VK_LAYER_LIB_PREFIX + "D.so";
+ private static final String VK_LAYER_E_LIB = VK_LAYER_LIB_PREFIX + "E.so";
+ private static final String VK_LAYER_NAME_PREFIX = "VK_LAYER_ANDROID_nullLayer";
+ private static final String VK_LAYER_A = VK_LAYER_NAME_PREFIX + "A";
+ private static final String VK_LAYER_B = VK_LAYER_NAME_PREFIX + "B";
+ private static final String VK_LAYER_C = VK_LAYER_NAME_PREFIX + "C";
+ private static final String VK_LAYER_D = VK_LAYER_NAME_PREFIX + "D";
+ private static final String VK_LAYER_E = VK_LAYER_NAME_PREFIX + "E";
private static final String DEBUG_APP = "android.rootlessgpudebug.DEBUG.app";
private static final String RELEASE_APP = "android.rootlessgpudebug.RELEASE.app";
private static final String INJECT_APP = "android.rootlessgpudebug.INJECT.app";
@@ -117,14 +121,13 @@
private static final String GLES_LAYER_B_LIB = "libGLES_" + GLES_LAYER_B + ".so";
private static final String GLES_LAYER_C_LIB = "libGLES_" + GLES_LAYER_C + ".so";
- private static boolean initialized = false;
-
// This is how long we'll scan the log for a result before giving up. This limit will only
// be reached if something has gone wrong
private static final long LOG_SEARCH_TIMEOUT_MS = 5000;
-
private static final long SETTING_APPLY_TIMEOUT_MS = 5000;
+ private static boolean initialized = false;
+
private String removeWhitespace(String input) {
return input.replaceAll(System.getProperty("line.separator"), "").trim();
}
@@ -172,6 +175,41 @@
}
/**
+ * Check that the layer is loaded by only checking the log after startTime.
+ */
+ private void assertVkLayerLoading(String startTime, String layerName, boolean loaded) throws Exception {
+ String searchString = "nullCreateInstance called in " + layerName;
+ LogScanResult result = scanLog(TAG + "," + layerName, searchString, startTime);
+ if (loaded) {
+ Assert.assertTrue(layerName + " was not loaded", result.found);
+ } else {
+ Assert.assertFalse(layerName + " was loaded", result.found);
+ }
+ }
+
+ /**
+ * Check that the layer is enumerated by only checking the log after startTime.
+ */
+ private void assertVkLayerEnumeration(String startTime, String layerName, boolean enumerated) throws Exception {
+ String searchString = layerName + " loaded";
+ LogScanResult result = scanLog(TAG + "," + layerName, searchString, startTime);
+ if (enumerated) {
+ Assert.assertTrue(layerName + " was not enumerated", result.found);
+ } else {
+ Assert.assertFalse(layerName + " was enumerated", result.found);
+ }
+ }
+
+ /**
+ * Check whether an extension is properly advertised by only checking the log after startTime.
+ */
+ private void assertVkExtension(String startTime, String extensionName, int specVersion) throws Exception {
+ String searchString = extensionName + ": " + specVersion;
+ LogScanResult result = scanLog(TAG + ",RootlessGpuDebug", searchString, startTime);
+ Assert.assertTrue(extensionName + "with spec version: " + specVersion + " was not advertised", result.found);
+ }
+
+ /**
* Simple helper class for returning multiple results
*/
public class LogScanResult {
@@ -242,9 +280,9 @@
getDevice().executeAdbCommand("shell", "am", "force-stop", DEBUG_APP);
getDevice().executeAdbCommand("shell", "am", "force-stop", RELEASE_APP);
getDevice().executeAdbCommand("shell", "am", "force-stop", INJECT_APP);
- getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + LAYER_A_LIB);
- getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + LAYER_B_LIB);
- getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + LAYER_C_LIB);
+ getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + VK_LAYER_A_LIB);
+ getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + VK_LAYER_B_LIB);
+ getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + VK_LAYER_C_LIB);
getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_A_LIB);
getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_B_LIB);
getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_C_LIB);
@@ -282,20 +320,20 @@
// Set up layers to be loaded
applySetting("enable_gpu_debug_layers", "1");
applySetting("gpu_debug_app", DEBUG_APP);
- applySetting("gpu_debug_layers", LAYER_A_NAME + ":" + LAYER_B_NAME);
+ applySetting("gpu_debug_layers", VK_LAYER_A + ":" + VK_LAYER_B);
// Copy the layers from our LAYERS APK to tmp
- setupLayer(LAYER_A_LIB, LAYERS_APP);
- setupLayer(LAYER_B_LIB, LAYERS_APP);
+ setupLayer(VK_LAYER_A_LIB, LAYERS_APP);
+ setupLayer(VK_LAYER_B_LIB, LAYERS_APP);
// Copy them over to our DEBUG app
- getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_A_LIB, "|",
"run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
- "sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'");
- getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_B_LIB, "|",
+ "sh", "-c", "\'cat", ">", VK_LAYER_A_LIB, ";", "chmod", "700", VK_LAYER_A_LIB + "\'");
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_B_LIB, "|",
"run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
- "sh", "-c", "\'cat", ">", LAYER_B_LIB, ";", "chmod", "700", LAYER_B_LIB + "\'");
+ "sh", "-c", "\'cat", ">", VK_LAYER_B_LIB, ";", "chmod", "700", VK_LAYER_B_LIB + "\'");
// Kick off our DEBUG app
@@ -303,12 +341,12 @@
getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Check that both layers were loaded, in the correct order
- String searchStringA = "nullCreateInstance called in " + LAYER_A;
- LogScanResult resultA = scanLog(TAG + "," + LAYER_A + "," + LAYER_B, searchStringA, appStartTime);
+ String searchStringA = "nullCreateInstance called in " + VK_LAYER_A;
+ LogScanResult resultA = scanLog(TAG + "," + VK_LAYER_A + "," + VK_LAYER_B, searchStringA, appStartTime);
Assert.assertTrue("LayerA was not loaded", resultA.found);
- String searchStringB = "nullCreateInstance called in " + LAYER_B;
- LogScanResult resultB = scanLog(TAG + "," + LAYER_A + "," + LAYER_B, searchStringB, appStartTime);
+ String searchStringB = "nullCreateInstance called in " + VK_LAYER_B;
+ LogScanResult resultB = scanLog(TAG + "," + VK_LAYER_A + "," + VK_LAYER_B, searchStringB, appStartTime);
Assert.assertTrue("LayerB was not loaded", resultB.found);
Assert.assertTrue("LayerA should be loaded before LayerB", resultA.lineNumber < resultB.lineNumber);
@@ -318,24 +356,22 @@
// Set up a layers to be loaded for RELEASE or INJECT app
applySetting("enable_gpu_debug_layers", "1");
applySetting("gpu_debug_app", APP_NAME);
- applySetting("gpu_debug_layers", LAYER_A_NAME + ":" + LAYER_B_NAME);
+ applySetting("gpu_debug_layers", VK_LAYER_A + ":" + VK_LAYER_B);
// Copy a layer from our LAYERS APK to tmp
- setupLayer(LAYER_A_LIB, LAYERS_APP);
+ setupLayer(VK_LAYER_A_LIB, LAYERS_APP);
// Attempt to copy them over to our RELEASE or INJECT app (this should fail)
- getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_A_LIB, "|",
"run-as", APP_NAME, "--user", Integer.toString(getDevice().getCurrentUser()),
- "sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'", "||", "echo", "run-as", "failed");
+ "sh", "-c", "\'cat", ">", VK_LAYER_A_LIB, ";", "chmod", "700", VK_LAYER_A_LIB + "\'", "||", "echo", "run-as", "failed");
// Kick off our RELEASE app
String appStartTime = getTime();
getDevice().executeAdbCommand("shell", "am", "start", "-n", APP_NAME + "/" + ACTIVITY);
// Ensure we don't load the layer in base dir
- String searchStringA = LAYER_A_NAME + "loaded";
- LogScanResult resultA = scanLog(TAG + "," + LAYER_A, searchStringA, appStartTime);
- Assert.assertFalse("LayerA was enumerated", resultA.found);
+ assertVkLayerEnumeration(appStartTime, VK_LAYER_A, false);
}
/**
@@ -366,24 +402,22 @@
// Ensure the global layer enable settings is NOT enabled
applySetting("enable_gpu_debug_layers", "0");
applySetting("gpu_debug_app", DEBUG_APP);
- applySetting("gpu_debug_layers", LAYER_A_NAME);
+ applySetting("gpu_debug_layers", VK_LAYER_A);
// Copy a layer from our LAYERS APK to tmp
- setupLayer(LAYER_A_LIB, LAYERS_APP);
+ setupLayer(VK_LAYER_A_LIB, LAYERS_APP);
// Copy it over to our DEBUG app
- getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_A_LIB, "|",
"run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
- "sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'");
+ "sh", "-c", "\'cat", ">", VK_LAYER_A_LIB, ";", "chmod", "700", VK_LAYER_A_LIB + "\'");
// Kick off our DEBUG app
String appStartTime = getTime();
getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Ensure we don't load the layer in base dir
- String searchStringA = LAYER_A_NAME + "loaded";
- LogScanResult resultA = scanLog(TAG + "," + LAYER_A, searchStringA, appStartTime);
- Assert.assertFalse("LayerA was enumerated", resultA.found);
+ assertVkLayerEnumeration(appStartTime, VK_LAYER_A, false);
}
/**
@@ -396,24 +430,22 @@
// Ensure the gpu_debug_app does not match what we launch
applySetting("enable_gpu_debug_layers", "1");
applySetting("gpu_debug_app", RELEASE_APP);
- applySetting("gpu_debug_layers", LAYER_A_NAME);
+ applySetting("gpu_debug_layers", VK_LAYER_A);
// Copy a layer from our LAYERS APK to tmp
- setupLayer(LAYER_A_LIB, LAYERS_APP);
+ setupLayer(VK_LAYER_A_LIB, LAYERS_APP);
// Copy it over to our DEBUG app
- getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_A_LIB, "|",
"run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
- "sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'");
+ "sh", "-c", "\'cat", ">", VK_LAYER_A_LIB, ";", "chmod", "700", VK_LAYER_A_LIB + "\'");
// Kick off our DEBUG app
String appStartTime = getTime();
getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Ensure we don't load the layer in base dir
- String searchStringA = LAYER_A_NAME + "loaded";
- LogScanResult resultA = scanLog(TAG + "," + LAYER_A, searchStringA, appStartTime);
- Assert.assertFalse("LayerA was enumerated", resultA.found);
+ assertVkLayerEnumeration(appStartTime, VK_LAYER_A, false);
}
/**
@@ -429,21 +461,19 @@
applySetting("gpu_debug_layers", "foo");
// Copy a layer from our LAYERS APK to tmp
- setupLayer(LAYER_A_LIB, LAYERS_APP);
+ setupLayer(VK_LAYER_A_LIB, LAYERS_APP);
// Copy it over to our DEBUG app
- getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_A_LIB, "|",
"run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
- "sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'");
+ "sh", "-c", "\'cat", ">", VK_LAYER_A_LIB, ";", "chmod", "700", VK_LAYER_A_LIB + "\'");
// Kick off our DEBUG app
String appStartTime = getTime();
getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Ensure layerA is not loaded
- String searchStringA = "nullCreateInstance called in " + LAYER_A;
- LogScanResult resultA = scanLog(TAG + "," + LAYER_A, searchStringA, appStartTime);
- Assert.assertFalse("LayerA was loaded", resultA.found);
+ assertVkLayerLoading(appStartTime, VK_LAYER_A, false);
}
/**
@@ -458,20 +488,15 @@
deleteSetting("gpu_debug_layers");
// Enable layerC (which is packaged with the RELEASE app) with system properties
- getDevice().executeAdbCommand("shell", "setprop", "debug.vulkan.layers " + LAYER_C_NAME);
+ getDevice().executeAdbCommand("shell", "setprop", "debug.vulkan.layers " + VK_LAYER_C);
// Kick off our RELEASE app
String appStartTime = getTime();
getDevice().executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
// Check that only layerC was loaded
- String searchStringA = LAYER_A_NAME + "loaded";
- LogScanResult resultA = scanLog(TAG + "," + LAYER_A, searchStringA, appStartTime);
- Assert.assertFalse("LayerA was enumerated", resultA.found);
-
- String searchStringC = "nullCreateInstance called in " + LAYER_C;
- LogScanResult resultC = scanLog(TAG + "," + LAYER_C, searchStringC, appStartTime);
- Assert.assertTrue("LayerC was not loaded", resultC.found);
+ assertVkLayerEnumeration(appStartTime, VK_LAYER_A, false);
+ assertVkLayerLoading(appStartTime, VK_LAYER_C, true);
}
/**
@@ -483,44 +508,42 @@
// Set up layerA to be loaded, but not layerB
applySetting("enable_gpu_debug_layers", "1");
applySetting("gpu_debug_app", DEBUG_APP);
- applySetting("gpu_debug_layers", LAYER_A_NAME);
+ applySetting("gpu_debug_layers", VK_LAYER_A);
// Copy the layers from our LAYERS APK
- setupLayer(LAYER_A_LIB, LAYERS_APP);
- setupLayer(LAYER_B_LIB, LAYERS_APP);
+ setupLayer(VK_LAYER_A_LIB, LAYERS_APP);
+ setupLayer(VK_LAYER_B_LIB, LAYERS_APP);
// Copy them over to our DEBUG app
- getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_A_LIB, "|",
"run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
- "sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'");
- getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_B_LIB, "|",
+ "sh", "-c", "\'cat", ">", VK_LAYER_A_LIB, ";", "chmod", "700", VK_LAYER_A_LIB + "\'");
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + VK_LAYER_B_LIB, "|",
"run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
- "sh", "-c", "\'cat", ">", LAYER_B_LIB, ";", "chmod", "700", LAYER_B_LIB + "\'");
+ "sh", "-c", "\'cat", ">", VK_LAYER_B_LIB, ";", "chmod", "700", VK_LAYER_B_LIB + "\'");
// Enable layerB with system properties
- getDevice().executeAdbCommand("shell", "setprop", "debug.vulkan.layers " + LAYER_B_NAME);
+ getDevice().executeAdbCommand("shell", "setprop", "debug.vulkan.layers " + VK_LAYER_B);
// Kick off our DEBUG app
String appStartTime = getTime();
getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Ensure only layerA is loaded
- String searchStringA = "nullCreateInstance called in " + LAYER_A;
- LogScanResult resultA = scanLog(TAG + "," + LAYER_A, searchStringA, appStartTime);
- Assert.assertTrue("LayerA was not loaded", resultA.found);
-
- String searchStringB = "nullCreateInstance called in " + LAYER_B;
- LogScanResult resultB = scanLog(TAG + "," + LAYER_B, searchStringB, appStartTime);
- Assert.assertFalse("LayerB was loaded", resultB.found);
+ assertVkLayerLoading(appStartTime, VK_LAYER_A, true);
+ assertVkLayerLoading(appStartTime, VK_LAYER_B, false);
}
-
- public void testLayerLoadExternalVulkan(final String APP_NAME) throws Exception {
+ /**
+ * The common functionality to load layers from an external package.
+ * Returns the app start time.
+ */
+ public String testLayerLoadExternalVulkan(final String APP_NAME, String layers) throws Exception {
// Set up layers to be loaded
applySetting("enable_gpu_debug_layers", "1");
applySetting("gpu_debug_app", APP_NAME);
- applySetting("gpu_debug_layers", LAYER_C_NAME);
+ applySetting("gpu_debug_layers", layers);
// Specify the external app that hosts layers
applySetting("gpu_debug_layer_app", LAYERS_APP);
@@ -529,10 +552,11 @@
String appStartTime = getTime();
getDevice().executeAdbCommand("shell", "am", "start", "-n", APP_NAME + "/" + ACTIVITY);
- // Check that our external layer was loaded
- String searchStringC = "nullCreateInstance called in " + LAYER_C;
- LogScanResult resultC = scanLog(TAG + "," + LAYER_C, searchStringC, appStartTime);
- Assert.assertTrue("LayerC was not loaded", resultC.found);
+ String[] layerNames = layers.split(":");
+ for (String layerName : layerNames) {
+ assertVkLayerLoading(appStartTime, layerName, true);
+ }
+ return appStartTime;
}
/**
@@ -540,7 +564,7 @@
*/
@Test
public void testDebugLayerLoadExternalVulkan() throws Exception {
- testLayerLoadExternalVulkan(DEBUG_APP);
+ testLayerLoadExternalVulkan(DEBUG_APP, VK_LAYER_C);
}
/**
@@ -548,7 +572,27 @@
*/
@Test
public void testInjectLayerLoadExternalVulkan() throws Exception {
- testLayerLoadExternalVulkan(INJECT_APP);
+ testLayerLoadExternalVulkan(INJECT_APP, VK_LAYER_C);
+ }
+
+ /**
+ * Test that the instance extension is advertised properly from the implicitly enabled layer.
+ */
+ @Test
+ public void testInstanceExtensionPropertiesFromImplicitLayerVulkanBasic() throws Exception {
+ String appStartTime = testLayerLoadExternalVulkan(DEBUG_APP, VK_LAYER_D);
+ assertVkExtension(appStartTime, "VK_EXT_debug_utils", 1);
+ }
+
+ /**
+ * Test that when there are multiple implicit layers are enabled, if there are several instance
+ * extensions with the same extension names advertised by multiple layers, only the extension
+ * that is closer to the application is advertised by the loader.
+ */
+ @Test
+ public void testInstanceExtensionPropertiesFromImplicitLayerVulkanMultipleLayers() throws Exception {
+ String appStartTime = testLayerLoadExternalVulkan(DEBUG_APP, VK_LAYER_E + ":" + VK_LAYER_D);
+ assertVkExtension(appStartTime, "VK_EXT_debug_utils", 2);
}
/**
@@ -820,7 +864,7 @@
// Set up layers to be loaded
applySetting("enable_gpu_debug_layers", "1");
applySetting("gpu_debug_app", DEBUG_APP);
- applySetting("gpu_debug_layers", LAYER_C_NAME);
+ applySetting("gpu_debug_layers", VK_LAYER_C);
applySetting("gpu_debug_layers_gles", GLES_LAYER_C_LIB);
// Specify multple external apps that host layers
@@ -831,9 +875,7 @@
getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Check that external layers were loaded from both apps
- String vulkanString = "nullCreateInstance called in " + LAYER_C;
- LogScanResult vulkanResult = scanLog(TAG + "," + LAYER_C, vulkanString, appStartTime);
- Assert.assertTrue(LAYER_C + " was not loaded", vulkanResult.found);
+ assertVkLayerLoading(appStartTime, VK_LAYER_C, true);
String glesString = "glesLayer_eglChooseConfig called in " + GLES_LAYER_C;
LogScanResult glesResult = scanLog(TAG + "," + GLES_LAYER_C, glesString, appStartTime);
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 ed4e672..644ba72 100644
--- a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java
+++ b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/InputMethodServiceLifecycleTest.java
@@ -37,6 +37,7 @@
import android.platform.test.annotations.AppModeInstant;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import org.junit.After;
import org.junit.Before;
@@ -50,7 +51,7 @@
* Test general lifecycle events around InputMethodService.
*/
@RunWith(DeviceJUnit4ClassRunner.class)
-public class InputMethodServiceLifecycleTest extends RebootFreeHostTestBase {
+public class InputMethodServiceLifecycleTest extends BaseHostJUnit4Test {
private static final long WAIT_TIMEOUT = TimeUnit.SECONDS.toMillis(1);
private static final long PACKAGE_OP_TIMEOUT = TimeUnit.SECONDS.toMillis(7);
diff --git a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java
index 8fece56..f1e73a2 100644
--- a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java
+++ b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java
@@ -30,6 +30,7 @@
import android.platform.test.annotations.AppModeInstant;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
import com.android.tradefed.util.CommandResult;
import com.android.tradefed.util.CommandStatus;
@@ -48,7 +49,7 @@
* Test IME APIs for multi-user environment.
*/
@RunWith(DeviceJUnit4ClassRunner.class)
-public class MultiUserTest extends RebootFreeHostTestBase {
+public class MultiUserTest extends BaseHostJUnit4Test {
private static final long USER_SWITCH_TIMEOUT = TimeUnit.SECONDS.toMillis(60);
private static final long USER_SWITCH_POLLING_INTERVAL = TimeUnit.MILLISECONDS.toMillis(100);
private static final long IME_COMMAND_TIMEOUT = TimeUnit.SECONDS.toMillis(7);
diff --git a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/RebootFreeHostTestBase.java b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/RebootFreeHostTestBase.java
deleted file mode 100644
index e90f1f6..0000000
--- a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/RebootFreeHostTestBase.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2020 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.hostside;
-
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.rules.TestName;
-
-import java.util.Objects;
-import java.util.WeakHashMap;
-
-/**
- * A utility class that enforces the device under test must never reboot during the test runs.
- *
- * <p>For instance, suppose the following test class.</p>
- * <pre>{@code
- * @RunWith(DeviceJUnit4ClassRunner.class)
- * public class MyTestClass extends RebootFreeHostTestBase {
- * @Test
- * public void test1() throws Exception {
- * // do something;
- * }
- *
- * @Test
- * public void test2() throws Exception {
- * // do something;
- * }
- *
- * @Test
- * public void test3() throws Exception {
- * // do something;
- * }
- * }
- * }</pre>
- *
- * <p>If the device (soft-)rebooted between {@code test1()} and {@code test2()}, then this base
- * class would let {@code test2()} and {@code test3()} immediately fail by throwing
- * {@link IllegalStateException} with saying that the device reboot is detected and the last
- * test method before reboot is {@code test1()}</p>
- *
- * <p>Note that reboot-free is enforced only within each subclass of {@link RebootFreeHostTestBase}.
- * Another sub-class such as {@code class MyTestClass2 extends RebootFreeHostTestBase} will not
- * immediately fail because of device restart detected while running {@code class MyTestClass}.</p>
- */
-public class RebootFreeHostTestBase extends BaseHostJUnit4Test {
- private static final String PROP_SYSTEM_SERVER_START_COUNT = "sys.system_server.start_count";
-
- private static final WeakHashMap<Class<?>, String> sExpectedSystemStartCount =
- new WeakHashMap<>();
- private static final WeakHashMap<Class<?>, String> sLastRunningTestName = new WeakHashMap<>();
-
- /**
- * A {@link TestName} object to receive the currently running test name.
- *
- * <p>Note this field needs to be {@code public} due to a restriction of JUnit4.</p>
- */
- @Rule
- public TestName mTestName = new TestName();
-
- /**
- * @return device start count as {@link String}.
- * @throws DeviceNotAvailableException
- */
- private String getSystemStartCountAsString() throws DeviceNotAvailableException {
- final String countString = getDevice().getProperty(PROP_SYSTEM_SERVER_START_COUNT);
- if (countString == null) {
- throw new IllegalStateException(
- String.format("Property %s must not be null", PROP_SYSTEM_SERVER_START_COUNT));
- }
- return countString;
- }
-
- /**
- * Ensures there was no unexpected device reboot.
- *
- * @throws IllegalStateException when an unexpected device reboot is detected.
- */
- @Before
- public void ensureNoSystemRestart() throws Exception {
- final Class<?> myClass = getClass();
- final String currentCount = getSystemStartCountAsString();
- final String expectedCount = sExpectedSystemStartCount.get(myClass);
- if (expectedCount == null) {
- // This is the first time for the given test class to run.
- // Just remember the current system start count.
- sExpectedSystemStartCount.put(myClass, currentCount);
- } else if (!Objects.equals(expectedCount, currentCount)) {
- final String lastTest = sLastRunningTestName.getOrDefault(myClass, "<unknown>");
- throw new IllegalStateException(String.format(
- "Unexpected device restart detected [%s: %s -> %s]. "
- + "lastTestBeforeRestart=%s. Check the device log!",
- PROP_SYSTEM_SERVER_START_COUNT, expectedCount, currentCount, lastTest));
- }
- sLastRunningTestName.put(myClass, mTestName.getMethodName());
- }
-}
diff --git a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/ShellCommandFromAppTest.java b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/ShellCommandFromAppTest.java
index 0ab53cd..6c66949 100644
--- a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/ShellCommandFromAppTest.java
+++ b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/ShellCommandFromAppTest.java
@@ -25,6 +25,7 @@
import android.platform.test.annotations.AppModeInstant;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
import org.junit.After;
@@ -36,7 +37,7 @@
* Test IInputMethodManager#shellComman verifies callers.
*/
@RunWith(DeviceJUnit4ClassRunner.class)
-public class ShellCommandFromAppTest extends RebootFreeHostTestBase {
+public class ShellCommandFromAppTest extends BaseHostJUnit4Test {
/**
* {@code true} if {@link #tearDown()} needs to be fully executed.
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/poc.cpp
index 0c64210..d9acb35 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/poc.cpp
@@ -79,8 +79,8 @@
for (i=0; i<100; i++) {
gEffect = audioFlinger->createEffect(&descriptor, effectClient, priority,
- io, sessionId, device, opPackageName, getpid(),
- &err, &id, &enabled);
+ io, sessionId, device, opPackageName,
+ getpid(), false, &err, &id, &enabled);
if (gEffect == NULL || err != NO_ERROR) {
return -1;
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index b1eeb5e..ac8908b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -393,9 +393,22 @@
*/
public static void runPocAssertNoCrashes(String pocName, ITestDevice device,
String... processPatternStrings) throws Exception {
+ runPocAssertNoCrashes(pocName, device,
+ new CrashUtils.Config().setProcessPatterns(processPatternStrings));
+ }
+
+ /**
+ * Runs the poc binary and asserts that there are no security crashes that match the expected
+ * process pattern.
+ * @param pocName a string path to poc from the /res folder
+ * @param device device to be ran on
+ * @param config a crash parser configuration
+ */
+ public static void runPocAssertNoCrashes(String pocName, ITestDevice device,
+ CrashUtils.Config config) throws Exception {
AdbUtils.runCommandLine("logcat -c", device);
AdbUtils.runPocNoOutput(pocName, device, SecurityTestCase.TIMEOUT_NONDETERMINISTIC);
- assertNoCrashes(device, processPatternStrings);
+ assertNoCrashes(device, config);
}
/**
@@ -500,27 +513,21 @@
*/
public static void assertNoCrashes(ITestDevice device, String... processPatternStrings)
throws Exception {
- assertNoCrashes(device, true, processPatternStrings);
+ assertNoCrashes(device, new CrashUtils.Config().setProcessPatterns(processPatternStrings));
}
/**
* Dumps logcat and asserts that there are no security crashes that match the expected process
* pattern. Ensure that adb logcat -c is called beforehand.
* @param device device to be ran on
- * @param checkMinAddress if the minimum fault address should be respected
- * @param processPatternStrings a Pattern string to match the crash tombstone process
+ * @param config a crash parser configuration
*/
- public static void assertNoCrashes(ITestDevice device, boolean checkMinAddress,
- String... processPatternStrings) throws Exception {
+ public static void assertNoCrashes(ITestDevice device,
+ CrashUtils.Config config) throws Exception {
String logcat = AdbUtils.runCommandLine("logcat -d *:S DEBUG:V", device);
- Pattern[] processPatterns = new Pattern[processPatternStrings.length];
- for (int i = 0; i < processPatternStrings.length; i++) {
- processPatterns[i] = Pattern.compile(processPatternStrings[i]);
- }
JSONArray crashes = CrashUtils.addAllCrashes(logcat, new JSONArray());
- JSONArray securityCrashes =
- CrashUtils.matchSecurityCrashes(crashes, checkMinAddress, processPatterns);
+ JSONArray securityCrashes = CrashUtils.matchSecurityCrashes(crashes, config);
if (securityCrashes.length() == 0) {
return; // no security crashes detected
@@ -529,8 +536,8 @@
StringBuilder error = new StringBuilder();
error.append("Security crash detected:\n");
error.append("Process patterns:");
- for (String pattern : processPatternStrings) {
- error.append(String.format(" '%s'", pattern));
+ for (Pattern pattern : config.getProcessPatterns()) {
+ error.append(String.format(" '%s'", pattern.toString()));
}
error.append("\nCrashes:\n");
for (int i = 0; i < crashes.length(); i++) {
diff --git a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
index 7458be5..fa74b7f 100644
--- a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
+++ b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
@@ -60,6 +60,7 @@
import android.os.SystemClock;
import android.os.VibrationEffect;
import android.os.Vibrator;
+import android.util.ArrayMap;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -70,6 +71,7 @@
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -78,6 +80,108 @@
private static final String MY_PACKAGE_NAME = "com.android.server.cts.device.statsd";
+ private static final Map<String, Integer> APP_OPS_ENUM_MAP = new ArrayMap<>();
+ static {
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_COARSE_LOCATION, 0);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_FINE_LOCATION, 1);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_GPS, 2);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_VIBRATE, 3);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_CONTACTS, 4);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_CONTACTS, 5);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_CALL_LOG, 6);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_CALL_LOG, 7);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_CALENDAR, 8);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_CALENDAR, 9);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WIFI_SCAN, 10);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_POST_NOTIFICATION, 11);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_NEIGHBORING_CELLS, 12);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_CALL_PHONE, 13);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_SMS, 14);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_SMS, 15);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RECEIVE_SMS, 16);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RECEIVE_EMERGENCY_BROADCAST, 17);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RECEIVE_MMS, 18);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RECEIVE_WAP_PUSH, 19);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_SEND_SMS, 20);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_ICC_SMS, 21);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_ICC_SMS, 22);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_SETTINGS, 23);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW, 24);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACCESS_NOTIFICATIONS, 25);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_CAMERA, 26);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RECORD_AUDIO, 27);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_PLAY_AUDIO, 28);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_CLIPBOARD, 29);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_CLIPBOARD, 30);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_TAKE_MEDIA_BUTTONS, 31);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_TAKE_AUDIO_FOCUS, 32);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_MASTER_VOLUME, 33);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_VOICE_VOLUME, 34);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_RING_VOLUME, 35);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_MEDIA_VOLUME, 36);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_ALARM_VOLUME, 37);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_NOTIFICATION_VOLUME, 38);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_BLUETOOTH_VOLUME, 39);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WAKE_LOCK, 40);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MONITOR_LOCATION, 41);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MONITOR_HIGH_POWER_LOCATION, 42);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_GET_USAGE_STATS, 43);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MUTE_MICROPHONE, 44);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_TOAST_WINDOW, 45);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_PROJECT_MEDIA, 46);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACTIVATE_VPN, 47);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_WALLPAPER, 48);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ASSIST_STRUCTURE, 49);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ASSIST_SCREENSHOT, 50);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_PHONE_STATE, 51);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ADD_VOICEMAIL, 52);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_USE_SIP, 53);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_PROCESS_OUTGOING_CALLS, 54);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_USE_FINGERPRINT, 55);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_BODY_SENSORS, 56);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_CELL_BROADCASTS, 57);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MOCK_LOCATION, 58);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE, 59);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_EXTERNAL_STORAGE, 60);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_TURN_SCREEN_ON, 61);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_GET_ACCOUNTS, 62);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RUN_IN_BACKGROUND, 63);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_ACCESSIBILITY_VOLUME, 64);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_PHONE_NUMBERS, 65);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES, 66);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_PICTURE_IN_PICTURE, 67);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_INSTANT_APP_START_FOREGROUND, 68);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ANSWER_PHONE_CALLS, 69);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RUN_ANY_IN_BACKGROUND, 70);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, 71);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_REQUEST_DELETE_PACKAGES, 72);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE, 73);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACCEPT_HANDOVER, 74);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS, 75);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_START_FOREGROUND, 76);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_BLUETOOTH_SCAN, 77);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_USE_BIOMETRIC, 78);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACTIVITY_RECOGNITION, 79);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_SMS_FINANCIAL_TRANSACTIONS, 80);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_MEDIA_AUDIO, 81);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_MEDIA_AUDIO, 82);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_MEDIA_VIDEO, 83);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_MEDIA_VIDEO, 84);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_MEDIA_IMAGES, 85);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_MEDIA_IMAGES, 86);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_LEGACY_STORAGE, 87);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACCESS_ACCESSIBILITY, 88);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS, 89);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACCESS_MEDIA_LOCATION, 90);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_QUERY_ALL_PACKAGES, 91);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE, 92);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_INTERACT_ACROSS_PROFILES, 93);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN, 94);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_LOADER_USAGE_STATS, 95);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACCESS_CALL_AUDIO, 96);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, 97);
+ }
+
@Test
public void testAudioState() {
// TODO: This should surely be getTargetContext(), here and everywhere, but test first.
@@ -244,6 +348,7 @@
// No foreground service session
noteAppOp(appOpsManager, AppOpsManager.OPSTR_COARSE_LOCATION, true);
+ sleep(500);
// Foreground service session 1
context.startService(fgsIntent);
@@ -255,14 +360,34 @@
noteAppOp(appOpsManager, AppOpsManager.OPSTR_CAMERA, true);
noteAppOp(appOpsManager, AppOpsManager.OPSTR_RECORD_AUDIO, false);
noteAppOp(appOpsManager, AppOpsManager.OPSTR_RECORD_AUDIO, true);
+ sleep(500);
context.stopService(fgsIntent);
// No foreground service session
noteAppOp(appOpsManager, AppOpsManager.OPSTR_COARSE_LOCATION, true);
+ sleep(500);
// TODO(b/149098800): Start fgs a second time and log OPSTR_CAMERA again
}
+ @Test
+ public void testAppOps() throws Exception {
+ Context context = InstrumentationRegistry.getContext();
+ AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
+
+ String[] opsList = appOpsManager.getOpStrs();
+
+ for (int i = 0; i < opsList.length; i++) {
+ String op = opsList[i];
+ int noteCount = APP_OPS_ENUM_MAP.getOrDefault(op, opsList.length) + 1;
+ for (int j = 0; j < noteCount; j++) {
+ try {
+ noteAppOp(appOpsManager, opsList[i], true);
+ } catch (SecurityException e) {}
+ }
+ }
+ }
+
/** @param doNote true if should use noteOp; false if should use startOp. */
private void noteAppOp(AppOpsManager appOpsManager, String opStr, boolean doNote) {
if (doNote) {
@@ -274,7 +399,6 @@
(aom) -> aom.startOp(opStr, android.os.Process.myUid(),
MY_PACKAGE_NAME, null, "statsdTest"));
}
- sleep(500);
}
/** Check if service is running. */
diff --git a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/DirectoryTests.java b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/DirectoryTests.java
new file mode 100644
index 0000000..fd849c9
--- /dev/null
+++ b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/DirectoryTests.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.cts.device.statsd;
+
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class DirectoryTests {
+
+ @Test
+ public void testStatsActiveMetricDirectoryExists() {
+ final File f = new File("/data/misc/stats-active-metric/");
+ assertTrue(f.exists());
+ assertFalse(f.isFile());
+ }
+
+ @Test
+ public void testStatsDataDirectoryExists() {
+ final File f = new File("/data/misc/stats-data/");
+ assertTrue(f.exists());
+ assertFalse(f.isFile());
+ }
+
+ @Test
+ public void testStatsMetadataDirectoryExists() {
+ final File f = new File("/data/misc/stats-metadata/");
+ assertTrue(f.exists());
+ assertFalse(f.isFile());
+ }
+
+ @Test
+ public void testStatsServiceDirectoryExists() {
+ final File f = new File("/data/misc/stats-service/");
+ assertTrue(f.exists());
+ assertFalse(f.isFile());
+ }
+
+ @Test
+ public void testTrainInfoDirectoryExists() {
+ final File f = new File("/data/misc/train-info/");
+ assertTrue(f.exists());
+ assertFalse(f.isFile());
+ }
+}
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index 82fdaf9..15d5bb6 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import android.app.AppOpEnum;
import android.net.wifi.WifiModeEnum;
import android.os.WakeLockLevelEnum;
import android.server.ErrorSource;
@@ -31,6 +32,7 @@
import com.android.os.AtomsProto.AppStartOccurred;
import com.android.os.AtomsProto.Atom;
import com.android.os.AtomsProto.AttributionNode;
+import com.android.os.AtomsProto.AttributedAppOps;
import com.android.os.AtomsProto.AudioStateChanged;
import com.android.os.AtomsProto.BinderCalls;
import com.android.os.AtomsProto.BleScanResultReceived;
@@ -85,8 +87,13 @@
private static final String TAG = "Statsd.UidAtomTests";
+ private static final String TEST_PACKAGE_NAME = "com.android.server.cts.device.statsd";
+
private static final boolean DAVEY_ENABLED = false;
+ private static final int NUM_APP_OPS = AttributedAppOps.getDefaultInstance().getOp().
+ getDescriptorForType().getValues().size() - 1;
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -171,7 +178,7 @@
.isEqualTo(AppCrashOccurred.InstantApp.FALSE_VALUE);
assertThat(atom.getForegroundState().getNumber())
.isEqualTo(AppCrashOccurred.ForegroundState.FOREGROUND_VALUE);
- assertThat(atom.getPackageName()).isEqualTo("com.android.server.cts.device.statsd");
+ assertThat(atom.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
}
public void testAppStartOccurred() throws Exception {
@@ -189,7 +196,7 @@
List<EventMetricData> data = getEventMetricDataList();
AppStartOccurred atom = data.get(0).getAtom().getAppStartOccurred();
- assertThat(atom.getPkgName()).isEqualTo("com.android.server.cts.device.statsd");
+ assertThat(atom.getPkgName()).isEqualTo(TEST_PACKAGE_NAME);
assertThat(atom.getActivityName())
.isEqualTo("com.android.server.cts.device.statsd.StatsdCtsForegroundActivity");
assertThat(atom.getIsInstantApp()).isFalse();
@@ -570,22 +577,21 @@
final int count = acceptances + rejections;
int expectedCount = 0;
switch (opName) {
- case ForegroundServiceAppOpSessionEnded.AppOpName.OP_CAMERA_VALUE:
+ case AppOpEnum.APP_OP_CAMERA_VALUE:
expectedCount = 2;
break;
- case ForegroundServiceAppOpSessionEnded.AppOpName.OP_FINE_LOCATION_VALUE:
+ case AppOpEnum.APP_OP_FINE_LOCATION_VALUE:
expectedCount = 1;
break;
- case ForegroundServiceAppOpSessionEnded.AppOpName.OP_RECORD_AUDIO_VALUE:
+ case AppOpEnum.APP_OP_RECORD_AUDIO_VALUE:
expectedCount = 2;
break;
- case ForegroundServiceAppOpSessionEnded.AppOpName.OP_COARSE_LOCATION_VALUE:
+ case AppOpEnum.APP_OP_COARSE_LOCATION_VALUE:
// fall-through
default:
fail("Unexpected opName " + opName);
}
assertWithMessage("Wrong count for " + opName).that(count).isEqualTo(expectedCount);
-
}
}
@@ -1560,20 +1566,38 @@
StatsdConfig.Builder config = getPulledConfig();
addGaugeAtomWithDimensions(config, Atom.APP_OPS_FIELD_NUMBER, null);
uploadConfig(config);
+
+ runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testAppOps");
Thread.sleep(WAIT_TIME_SHORT);
// Pull a report
setAppBreadcrumbPredicate();
Thread.sleep(WAIT_TIME_SHORT);
- long accessInstancesRecorded = 0;
-
- for (Atom atom : getGaugeMetricDataList()) {
- AppOps appOps = atom.getAppOps();
- accessInstancesRecorded += appOps.getTrustedForegroundGrantedCount();
+ ArrayList<Integer> expectedOps = new ArrayList<>();
+ for (int i = 0; i < NUM_APP_OPS; i++) {
+ expectedOps.add(i);
}
- assertThat(accessInstancesRecorded).isAtLeast(1l);
+ for (Atom atom : getGaugeMetricDataList()) {
+
+ AppOps appOps = atom.getAppOps();
+ if (appOps.getPackageName().equals(TEST_PACKAGE_NAME)) {
+ if (appOps.getOpId().getNumber() == -1) {
+ continue;
+ }
+ long totalNoted = appOps.getTrustedForegroundGrantedCount()
+ + appOps.getTrustedBackgroundGrantedCount()
+ + appOps.getTrustedForegroundRejectedCount()
+ + appOps.getTrustedBackgroundRejectedCount();
+ assertWithMessage("Operation in APP_OPS_ENUM_MAP: " + appOps.getOpId().getNumber())
+ .that(totalNoted - 1).isEqualTo(appOps.getOpId().getNumber());
+ assertWithMessage("Unexpected Op reported").that(expectedOps).contains(
+ appOps.getOpId().getNumber());
+ expectedOps.remove(expectedOps.indexOf(appOps.getOpId().getNumber()));
+ }
+ }
+ assertWithMessage("Logging app op ids are missing in report.").that(expectedOps).isEmpty();
}
public void testANROccurred() throws Exception {
diff --git a/hostsidetests/statsd/src/android/cts/statsd/validation/DirectoryValidationTest.java b/hostsidetests/statsd/src/android/cts/statsd/validation/DirectoryValidationTest.java
new file mode 100644
index 0000000..37ded0b
--- /dev/null
+++ b/hostsidetests/statsd/src/android/cts/statsd/validation/DirectoryValidationTest.java
@@ -0,0 +1,34 @@
+package android.cts.statsd.validation;
+
+import android.cts.statsd.atom.DeviceAtomTestCase;
+
+/**
+ * Tests Suite for directories used by Statsd.
+ */
+public class DirectoryValidationTest extends DeviceAtomTestCase {
+
+ public void testStatsActiveMetricDirectoryExists() throws Exception {
+ runDeviceTests(DEVICE_SIDE_TEST_PACKAGE,
+ ".DirectoryTests", "testStatsActiveMetricDirectoryExists");
+ }
+
+ public void testStatsDataDirectoryExists() throws Exception {
+ runDeviceTests(DEVICE_SIDE_TEST_PACKAGE,
+ ".DirectoryTests", "testStatsDataDirectoryExists");
+ }
+
+ public void testStatsMetadataDirectoryExists() throws Exception {
+ runDeviceTests(DEVICE_SIDE_TEST_PACKAGE,
+ ".DirectoryTests", "testStatsMetadataDirectoryExists");
+ }
+
+ public void testStatsServiceDirectoryExists() throws Exception {
+ runDeviceTests(DEVICE_SIDE_TEST_PACKAGE,
+ ".DirectoryTests", "testStatsServiceDirectoryExists");
+ }
+
+ public void testTrainInfoDirectoryExists() throws Exception {
+ runDeviceTests(DEVICE_SIDE_TEST_PACKAGE,
+ ".DirectoryTests", "testTrainInfoDirectoryExists");
+ }
+}
diff --git a/hostsidetests/telephonyprovider/devicetest/AndroidManifest.xml b/hostsidetests/telephonyprovider/devicetest/AndroidManifest.xml
index 0e78e46..99980a1 100644
--- a/hostsidetests/telephonyprovider/devicetest/AndroidManifest.xml
+++ b/hostsidetests/telephonyprovider/devicetest/AndroidManifest.xml
@@ -15,8 +15,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.telephonyprovider.host.cts">
- <uses-sdk android:targetSdkVersion="30"/>
+ package="android.telephonyprovider.device.cts">
+ <uses-sdk android:targetSdkVersion="28"/>
<application
android:debuggable="true">
<uses-library android:name="android.test.runner" />
@@ -24,6 +24,6 @@
<instrumentation
android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.telephonyprovider.host.cts" />
+ android:targetPackage="android.telephonyprovider.device.cts" />
</manifest>
diff --git a/hostsidetests/telephonyprovider/devicetest/src/android/telephonyprovider/cts/TelephonyProviderTest.java b/hostsidetests/telephonyprovider/devicetest/src/android/telephonyprovider/device/cts/TelephonyProviderTest.java
similarity index 98%
rename from hostsidetests/telephonyprovider/devicetest/src/android/telephonyprovider/cts/TelephonyProviderTest.java
rename to hostsidetests/telephonyprovider/devicetest/src/android/telephonyprovider/device/cts/TelephonyProviderTest.java
index 8230213..2549483 100644
--- a/hostsidetests/telephonyprovider/devicetest/src/android/telephonyprovider/cts/TelephonyProviderTest.java
+++ b/hostsidetests/telephonyprovider/devicetest/src/android/telephonyprovider/device/cts/TelephonyProviderTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.telephonyprovider.host.cts;
+package android.telephonyprovider.device.cts;
import android.content.ContentResolver;
import android.database.Cursor;
diff --git a/hostsidetests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderHostTest.java b/hostsidetests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderHostTest.java
index b3b91c8..6e226d1 100644
--- a/hostsidetests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderHostTest.java
+++ b/hostsidetests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderHostTest.java
@@ -27,7 +27,7 @@
public class TelephonyProviderHostTest extends CompatChangeGatingTestCase {
protected static final String TEST_APK = "TelephonyProviderDeviceTest.apk";
- protected static final String TEST_PKG = "android.telephonyprovider.cts";
+ protected static final String TEST_PKG = "android.telephonyprovider.device.cts";
private static final long APN_READING_PERMISSION_CHANGE_ID = 124107808L;
diff --git a/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java b/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java
index 1d450cd..552b819 100644
--- a/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java
+++ b/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java
@@ -212,8 +212,10 @@
// new ViewPressedModifier()),
//new LayoutInfo(R.layout.ratingbar_5, "ratingbar_5_pressed",
// new ViewPressedModifier()),
- new LayoutInfo(R.layout.searchview, "searchview_query",
- new SearchViewModifier(SearchViewModifier.QUERY)),
+ // Temporarily remove tests for the SearchView widget with no hint. The "X" icon has
+ // indeterminate rendering behavior on 480dpi devices, but we don't know why yet.
+ //new LayoutInfo(R.layout.searchview, "searchview_query",
+ // new SearchViewModifier(SearchViewModifier.QUERY)),
new LayoutInfo(R.layout.searchview, "searchview_query_hint",
new SearchViewModifier(SearchViewModifier.QUERY_HINT)),
new LayoutInfo(R.layout.seekbar_0, "seekbar_0"),
diff --git a/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java b/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java
index b5fbff1..47b42fc 100644
--- a/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java
+++ b/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java
@@ -34,6 +34,9 @@
import java.time.Duration;
+/**
+ * Host side CTS tests verifying userspace reboot functionality.
+ */
@RunWith(DeviceJUnit4ClassRunner.class)
public class UserspaceRebootHostTest extends BaseHostJUnit4Test {
@@ -64,18 +67,34 @@
getDevice().uninstallPackage(BOOT_COMPLETED_TEST_APP_PACKAGE_NAME);
}
+ /**
+ * Asserts that only file-based encrypted devices can support userspace reboot.
+ */
@Test
public void testOnlyFbeDevicesSupportUserspaceReboot() throws Exception {
assumeTrue("Userspace reboot not supported on the device",
getDevice().getBooleanProperty(USERSPACE_REBOOT_SUPPORTED_PROP, false));
- installApk(BASIC_TEST_APP_APK);
assertThat(getDevice().getProperty("ro.crypto.state")).isEqualTo("encrypted");
assertThat(getDevice().getProperty("ro.crypto.type")).isEqualTo("file");
- // Also verify that PowerManager.isRebootingUserspaceSupported will return true
+ }
+
+ /**
+ * Tests that on devices supporting userspace reboot {@code
+ * PowerManager.isRebootingUserspaceSupported()} returns {@code true}.
+ */
+ @Test
+ public void testDeviceSupportsUserspaceReboot() throws Exception {
+ assumeTrue("Userspace reboot not supported on the device",
+ getDevice().getBooleanProperty(USERSPACE_REBOOT_SUPPORTED_PROP, false));
+ installApk(BASIC_TEST_APP_APK);
runDeviceTest(BASIC_TEST_APP_PACKAGE_NAME, "BasicUserspaceRebootTest",
"testUserspaceRebootIsSupported");
}
+ /**
+ * Tests that on devices not supporting userspace reboot {@code
+ * PowerManager.isRebootingUserspaceSupported()} returns {@code false}.
+ */
@Test
public void testDeviceDoesNotSupportUserspaceReboot() throws Exception {
assumeFalse("Userspace reboot supported on the device",
@@ -86,6 +105,9 @@
"testUserspaceRebootIsNotSupported");
}
+ /**
+ * Tests that userspace reboot succeeds and doesn't fall back to full reboot.
+ */
@Test
public void testUserspaceReboot() throws Exception {
assumeTrue("Userspace reboot not supported on the device",
@@ -94,6 +116,10 @@
assertUserspaceRebootSucceed();
}
+ /**
+ * Tests that userspace reboot with fs-checkpointing succeeds and doesn't fall back to full
+ * reboot.
+ */
@Test
public void testUserspaceRebootWithCheckpoint() throws Exception {
assumeTrue("Userspace reboot not supported on the device",
@@ -107,7 +133,9 @@
assertUserspaceRebootSucceed();
}
- // TODO(ioffe): this should also cover other lock scenarios.
+ /**
+ * Tests that CE storage is unlocked after userspace reboot.
+ */
@Test
public void testUserspaceReboot_verifyCeStorageIsUnlocked() throws Exception {
assumeTrue("Userspace reboot not supported on the device",
@@ -131,22 +159,43 @@
}
}
+ /**
+ * Tests that CE storage is unlocked after userspace reboot with fs-checkpointing.
+ */
@Test
- public void testBootReasonProperty_shutdown_aborted() throws Exception {
- getDevice().reboot("userspace_failed,shutdown_aborted");
- assertThat(getDevice().getProperty("sys.boot.reason")).isEqualTo(
- "reboot,userspace_failed,shutdown_aborted");
- }
-
- @Test
- public void testBootReasonProperty_mount_userdata_failed() throws Exception {
- getDevice().reboot("mount_userdata_failed");
- assertThat(getDevice().getProperty("sys.boot.reason")).isEqualTo(
- "reboot,mount_userdata_failed");
+ public void testUserspaceRebootWithCheckpoint_verifyCeStorageIsUnlocked() throws Exception {
+ assumeTrue("Userspace reboot not supported on the device",
+ getDevice().getBooleanProperty(USERSPACE_REBOOT_SUPPORTED_PROP, false));
+ assumeTrue("Device doesn't support fs checkpointing", isFsCheckpointingSupported());
+ try {
+ CommandResult result = getDevice().executeShellV2Command("sm start-checkpoint 1");
+ Thread.sleep(500);
+ assertWithMessage("Failed to start checkpoint : %s", result.getStderr()).that(
+ result.getStatus()).isEqualTo(CommandStatus.SUCCESS);
+ rebootUserspaceAndWaitForBootComplete();
+ getDevice().executeShellV2Command("cmd lock_settings set-pin 1543");
+ installApk(BOOT_COMPLETED_TEST_APP_APK);
+ runDeviceTest(BOOT_COMPLETED_TEST_APP_PACKAGE_NAME, "BootCompletedUserspaceRebootTest",
+ "prepareFile");
+ rebootUserspaceAndWaitForBootComplete();
+ assertUserspaceRebootSucceed();
+ // Sleep for 30s to make sure that system_server has sent out BOOT_COMPLETED broadcast.
+ Thread.sleep(Duration.ofSeconds(30).toMillis());
+ getDevice().executeShellV2Command("am wait-for-broadcast-idle");
+ runDeviceTest(BOOT_COMPLETED_TEST_APP_PACKAGE_NAME, "BootCompletedUserspaceRebootTest",
+ "testVerifyCeStorageUnlocked");
+ runDeviceTest(BOOT_COMPLETED_TEST_APP_PACKAGE_NAME, "BootCompletedUserspaceRebootTest",
+ "testVerifyReceivedBootCompletedBroadcast");
+ } finally {
+ getDevice().executeShellV2Command("cmd lock_settings clear --old 1543");
+ }
}
// TODO(b/135984674): add test case that forces unmount of f2fs userdata.
+ /**
+ * Returns {@code true} if device supports fs-checkpointing.
+ */
private boolean isFsCheckpointingSupported() throws Exception {
CommandResult result = getDevice().executeShellV2Command("sm supports-checkpoint");
assertWithMessage("Failed to check if fs checkpointing is supported : %s",
@@ -154,13 +203,24 @@
return "true".equals(result.getStdout().trim());
}
+ /**
+ * Reboots a device and waits for the boot to complete.
+ *
+ * <p>Before rebooting, sets a value of sysprop {@code test.userspace_reboot.requested} to 1.
+ * Querying this property is then used in {@link #assertUserspaceRebootSucceed()} to assert that
+ * userspace reboot succeeded.
+ */
private void rebootUserspaceAndWaitForBootComplete() throws Exception {
- assertThat(getDevice().setProperty("test.userspace_reboot.requested", "1")).isTrue();
+ setProperty("test.userspace_reboot.requested", "1");
getDevice().rebootUserspaceUntilOnline();
assertWithMessage("Device did not boot withing 2 minutes").that(
getDevice().waitForBootComplete(Duration.ofMinutes(2).toMillis())).isTrue();
}
+ /**
+ * Asserts that userspace reboot succeeded by querying the value of {@code
+ * test.userspace_reboot.requested} property.
+ */
private void assertUserspaceRebootSucceed() throws Exception {
// If userspace reboot fails and fallback to hard reboot is triggered then
// test.userspace_reboot.requested won't be set.
@@ -171,4 +231,17 @@
"Userspace reboot failed and fallback to full reboot was triggered. Boot reason: "
+ "%s", bootReason).that(result).isTrue();
}
+
+ /**
+ * A wrapper over {@code adb shell setprop name value}.
+ *
+ * This is a temporary workaround until issues with {@code getDevice().setProperty()} API are
+ * resolved.
+ */
+ private void setProperty(String name, String value) throws Exception {
+ final String cmd = String.format("\"setprop %s %s\"", name, value);
+ final CommandResult result = getDevice().executeShellV2Command(cmd);
+ assertWithMessage("Failed to call adb shell %s: %s", cmd, result.getStderr())
+ .that(result.getStatus()).isEqualTo(CommandStatus.SUCCESS);
+ }
}
diff --git a/hostsidetests/userspacereboot/testapps/BasicTestApp/src/com/android/cts/userspacereboot/basic/BasicUserspaceRebootTest.java b/hostsidetests/userspacereboot/testapps/BasicTestApp/src/com/android/cts/userspacereboot/basic/BasicUserspaceRebootTest.java
index f4616c2..7867c46 100644
--- a/hostsidetests/userspacereboot/testapps/BasicTestApp/src/com/android/cts/userspacereboot/basic/BasicUserspaceRebootTest.java
+++ b/hostsidetests/userspacereboot/testapps/BasicTestApp/src/com/android/cts/userspacereboot/basic/BasicUserspaceRebootTest.java
@@ -29,17 +29,27 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+/**
+ * A test app called from {@link com.android.cts.userspacereboot.host.UserspaceRebootHostTest} to
+ * verify basic properties around userspace reboot.
+ */
@RunWith(JUnit4.class)
public class BasicUserspaceRebootTest {
private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ /**
+ * Tests that {@link PowerManager#isRebootingUserspaceSupported()} returns {@code true}.
+ */
@Test
public void testUserspaceRebootIsSupported() {
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
assertThat(powerManager.isRebootingUserspaceSupported()).isTrue();
}
+ /**
+ * Tests that {@link PowerManager#isRebootingUserspaceSupported()} returns {@code false}.
+ */
@Test
public void testUserspaceRebootIsNotSupported() {
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
diff --git a/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/src/com/android/cts/userspacereboot/bootcompleted/BootCompletedUserspaceRebootTest.java b/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/src/com/android/cts/userspacereboot/bootcompleted/BootCompletedUserspaceRebootTest.java
index 8bb86ce..bfd8773 100644
--- a/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/src/com/android/cts/userspacereboot/bootcompleted/BootCompletedUserspaceRebootTest.java
+++ b/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/src/com/android/cts/userspacereboot/bootcompleted/BootCompletedUserspaceRebootTest.java
@@ -35,6 +35,10 @@
import java.io.PrintWriter;
import java.util.Scanner;
+/**
+ * A test app called from {@link com.android.cts.userspacereboot.host.UserspaceRebootHostTest} to
+ * verify CE storage related properties of userspace reboot.
+ */
@RunWith(JUnit4.class)
public class BootCompletedUserspaceRebootTest {
@@ -50,6 +54,12 @@
private final Context mDeContext =
getInstrumentation().getContext().createDeviceProtectedStorageContext();
+ /**
+ * Writes to a file in CE storage of {@link BootCompletedUserspaceRebootTest}.
+ *
+ * <p>Reading content of this file is used by other test cases in this class to verify that CE
+ * storage is unlocked after userspace reboot.
+ */
@Test
public void prepareFile() throws Exception {
try (OutputStreamWriter writer = new OutputStreamWriter(
@@ -58,6 +68,9 @@
}
}
+ /**
+ * Tests that CE storage is unlocked by reading content of a file in CE storage.
+ */
@Test
public void testVerifyCeStorageUnlocked() throws Exception {
UserManager um = getInstrumentation().getContext().getSystemService(UserManager.class);
@@ -68,6 +81,10 @@
}
}
+ /**
+ * Tests that {@link BootCompletedUserspaceRebootTest} received a {@link
+ * Intent.ACTION_BOOT_COMPLETED} broadcast.
+ */
@Test
public void testVerifyReceivedBootCompletedBroadcast() throws Exception {
try (Scanner scanner = new Scanner(mDeContext.openFileInput(RECEIVED_BROADCASTS_FILE))) {
@@ -76,6 +93,9 @@
}
}
+ /**
+ * Receiver of {@link Intent.ACTION_BOOT_COMPLETED} broadcast.
+ */
public static class BootReceiver extends BroadcastReceiver {
@Override
diff --git a/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/src/com/android/cts/userspacereboot/bootcompleted/LauncherActivity.java b/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/src/com/android/cts/userspacereboot/bootcompleted/LauncherActivity.java
index abaca60..4d5d3b0 100644
--- a/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/src/com/android/cts/userspacereboot/bootcompleted/LauncherActivity.java
+++ b/hostsidetests/userspacereboot/testapps/BootCompletedTestApp/src/com/android/cts/userspacereboot/bootcompleted/LauncherActivity.java
@@ -18,5 +18,8 @@
import android.app.Activity;
+/**
+ * An empty launcher activity.
+ */
public class LauncherActivity extends Activity {
}
diff --git a/tests/BlobStore/Android.bp b/tests/BlobStore/Android.bp
index 61d34e4..5bd782a 100644
--- a/tests/BlobStore/Android.bp
+++ b/tests/BlobStore/Android.bp
@@ -40,6 +40,7 @@
name: "CtsBlobStoreTestHelper",
defaults: ["cts_defaults"],
static_libs: [
+ "androidx.test.ext.junit",
"truth-prebuilt",
"BlobStoreTestUtils",
],
@@ -60,6 +61,7 @@
name: "CtsBlobStoreTestHelperDiffSig",
defaults: ["cts_defaults"],
static_libs: [
+ "androidx.test.ext.junit",
"truth-prebuilt",
"BlobStoreTestUtils",
],
@@ -84,6 +86,7 @@
name: "CtsBlobStoreTestHelperDiffSig2",
defaults: ["cts_defaults"],
static_libs: [
+ "androidx.test.ext.junit",
"truth-prebuilt",
"BlobStoreTestUtils",
],
diff --git a/tests/BlobStore/helper-app/src/com/android/cts/blob/helper/BlobStoreTestService.java b/tests/BlobStore/helper-app/src/com/android/cts/blob/helper/BlobStoreTestService.java
index ce8cd6c..5f3547d 100644
--- a/tests/BlobStore/helper-app/src/com/android/cts/blob/helper/BlobStoreTestService.java
+++ b/tests/BlobStore/helper-app/src/com/android/cts/blob/helper/BlobStoreTestService.java
@@ -29,8 +29,10 @@
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.IBinder;
+import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.RemoteException;
import com.android.cts.blob.ICommandReceiver;
import com.android.utils.blob.Utils;
@@ -66,7 +68,7 @@
return callback.get(timeoutSec, TimeUnit.SECONDS);
}
} catch (IOException | InterruptedException | TimeoutException | ExecutionException e) {
- throw new RuntimeException(e);
+ throw new IllegalStateException(e);
}
}
@@ -77,7 +79,7 @@
try {
return blobStoreManager.openBlob(blobHandle);
} catch (IOException e) {
- throw new RuntimeException(e);
+ throw new IllegalStateException(e);
}
}
@@ -90,7 +92,7 @@
assertThat(session).isNotNull();
}
} catch (IOException e) {
- throw new RuntimeException(e);
+ throw new IllegalStateException(e);
}
}
@@ -99,9 +101,10 @@
final BlobStoreManager blobStoreManager = getSystemService(
BlobStoreManager.class);
try {
- blobStoreManager.acquireLease(blobHandle, "Test description");
+ Utils.acquireLease(BlobStoreTestService.this, blobHandle, "Test description");
+ assertThat(blobStoreManager.getLeasedBlobs()).contains(blobHandle);
} catch (IOException e) {
- throw new RuntimeException(e);
+ throw new IllegalStateException(e);
}
}
@@ -110,9 +113,10 @@
final BlobStoreManager blobStoreManager = getSystemService(
BlobStoreManager.class);
try {
- blobStoreManager.releaseLease(blobHandle);
+ Utils.releaseLease(BlobStoreTestService.this, blobHandle);
+ assertThat(blobStoreManager.getLeasedBlobs()).doesNotContain(blobHandle);
} catch (IOException e) {
- throw new RuntimeException(e);
+ throw new IllegalStateException(e);
}
}
@@ -124,7 +128,7 @@
return storageStatsManager
.queryStatsForPackage(UUID_DEFAULT, getPackageName(), getUser());
} catch (IOException | NameNotFoundException e) {
- throw new RuntimeException(e);
+ throw new IllegalStateException(e);
}
}
@@ -136,7 +140,17 @@
return storageStatsManager
.queryStatsForUid(UUID_DEFAULT, Process.myUid());
} catch (IOException e) {
- throw new RuntimeException(e);
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ try {
+ return super.onTransact(code, data, reply, flags);
+ } catch (AssertionError e) {
+ throw new IllegalStateException(e);
}
}
}
diff --git a/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java b/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java
index 7c39970..2c81ca7 100644
--- a/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java
+++ b/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java
@@ -17,12 +17,14 @@
import static android.os.storage.StorageManager.UUID_DEFAULT;
-import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.utils.blob.Utils.acquireLease;
+import static com.android.utils.blob.Utils.assertLeasedBlobs;
+import static com.android.utils.blob.Utils.assertNoLeasedBlobs;
+import static com.android.utils.blob.Utils.releaseLease;
import static com.google.common.truth.Truth.assertThat;
import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
import android.app.blob.BlobHandle;
import android.app.blob.BlobStoreManager;
@@ -35,23 +37,27 @@
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.SystemClock;
+import android.provider.DeviceConfig;
import android.util.Log;
+import com.android.compatibility.common.util.SystemUtil;
+import com.android.compatibility.common.util.ThrowingRunnable;
import com.android.cts.blob.R;
import com.android.cts.blob.ICommandReceiver;
import com.android.utils.blob.DummyBlobData;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.IOException;
-import java.util.ArrayList;
+import java.util.Objects;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -66,6 +72,12 @@
private static final long TIMEOUT_BIND_SERVICE_SEC = 2;
+ // TODO: Make it a @TestApi or move the test using this to a different location.
+ // Copy of DeviceConfig.NAMESPACE_BLOBSTORE constant
+ public static final String NAMESPACE_BLOBSTORE = "blobstore";
+ public static final String KEY_LEASE_ACQUISITION_WAIT_DURATION_MS =
+ "lease_acquisition_wait_time_ms";
+
private static final String HELPER_PKG = "com.android.cts.blob.helper";
private static final String HELPER_PKG2 = "com.android.cts.blob.helper2";
private static final String HELPER_PKG3 = "com.android.cts.blob.helper3";
@@ -91,7 +103,7 @@
@Test
public void testGetCreateSession() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
@@ -104,7 +116,7 @@
@Test
public void testCreateBlobHandle_invalidArguments() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
final BlobHandle handle = blobData.getBlobHandle();
try {
@@ -140,7 +152,7 @@
@Test
public void testAbandonSession() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
@@ -158,7 +170,7 @@
@Test
public void testOpenReadWriteSession() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
@@ -180,7 +192,7 @@
@Test
public void testOpenSession_fromAnotherPkg() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
@@ -206,7 +218,7 @@
@Test
public void testOpenSessionAndAbandon() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
@@ -231,7 +243,7 @@
@Test
public void testCloseSession() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
@@ -267,21 +279,16 @@
@Test
public void testAllowPublicAccess() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
assertThat(sessionId).isGreaterThan(0L);
- try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
- blobData.writeToSession(session);
+ commitBlob(blobData, session -> {
session.allowPublicAccess();
-
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(0);
- }
+ assertThat(session.isPublicAccessAllowed()).isTrue();
+ });
assertPkgCanAccess(blobData, HELPER_PKG);
assertPkgCanAccess(blobData, HELPER_PKG2);
@@ -293,7 +300,7 @@
@Test
public void testAllowPublicAccess_abandonedSession() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
@@ -316,21 +323,16 @@
@Test
public void testAllowSameSignatureAccess() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
assertThat(sessionId).isGreaterThan(0L);
- try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
- blobData.writeToSession(session);
+ commitBlob(blobData, session -> {
session.allowSameSignatureAccess();
-
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(0);
- }
+ assertThat(session.isSameSignatureAccessAllowed()).isTrue();
+ });
assertPkgCanAccess(blobData, HELPER_PKG);
assertPkgCannotAccess(blobData, HELPER_PKG2);
@@ -342,7 +344,7 @@
@Test
public void testAllowSameSignatureAccess_abandonedSession() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
@@ -365,21 +367,17 @@
@Test
public void testAllowPackageAccess() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
assertThat(sessionId).isGreaterThan(0L);
- try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
- blobData.writeToSession(session);
+ commitBlob(blobData, session -> {
session.allowPackageAccess(HELPER_PKG2, HELPER_PKG2_CERT_SHA256);
-
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(0);
- }
+ assertThat(session.isPackageAccessAllowed(HELPER_PKG2, HELPER_PKG2_CERT_SHA256))
+ .isTrue();
+ });
assertPkgCannotAccess(blobData, HELPER_PKG);
assertPkgCanAccess(blobData, HELPER_PKG2);
@@ -391,22 +389,20 @@
@Test
public void testAllowPackageAccess_allowMultiple() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
assertThat(sessionId).isGreaterThan(0L);
- try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
- blobData.writeToSession(session);
+ commitBlob(blobData, session -> {
session.allowPackageAccess(HELPER_PKG2, HELPER_PKG2_CERT_SHA256);
session.allowPackageAccess(HELPER_PKG3, HELPER_PKG3_CERT_SHA256);
-
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(0);
- }
+ assertThat(session.isPackageAccessAllowed(HELPER_PKG2, HELPER_PKG2_CERT_SHA256))
+ .isTrue();
+ assertThat(session.isPackageAccessAllowed(HELPER_PKG3, HELPER_PKG3_CERT_SHA256))
+ .isTrue();
+ });
assertPkgCannotAccess(blobData, HELPER_PKG);
assertPkgCanAccess(blobData, HELPER_PKG2);
@@ -418,7 +414,7 @@
@Test
public void testAllowPackageAccess_abandonedSession() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
@@ -444,7 +440,7 @@
@Test
public void testPrivateAccess() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
final TestServiceConnection connection1 = bindToHelperService(HELPER_PKG);
final TestServiceConnection connection2 = bindToHelperService(HELPER_PKG2);
@@ -453,14 +449,7 @@
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
assertThat(sessionId).isGreaterThan(0L);
- try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
- blobData.writeToSession(session);
-
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(0);
- }
+ commitBlob(blobData);
assertPkgCannotAccess(blobData, connection1);
assertPkgCannotAccess(blobData, connection2);
@@ -485,28 +474,20 @@
@Test
public void testMixedAccessType() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
assertThat(sessionId).isGreaterThan(0L);
- try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
- blobData.writeToSession(session);
-
+ commitBlob(blobData, session -> {
session.allowSameSignatureAccess();
session.allowPackageAccess(HELPER_PKG3, HELPER_PKG3_CERT_SHA256);
-
assertThat(session.isSameSignatureAccessAllowed()).isTrue();
assertThat(session.isPackageAccessAllowed(HELPER_PKG3, HELPER_PKG3_CERT_SHA256))
.isTrue();
assertThat(session.isPublicAccessAllowed()).isFalse();
-
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(0);
- }
+ });
assertPkgCanAccess(blobData, HELPER_PKG);
assertPkgCannotAccess(blobData, HELPER_PKG2);
@@ -518,7 +499,7 @@
@Test
public void testMixedAccessType_fromMultiplePackages() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
final TestServiceConnection connection1 = bindToHelperService(HELPER_PKG);
final TestServiceConnection connection2 = bindToHelperService(HELPER_PKG2);
@@ -527,22 +508,14 @@
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
assertThat(sessionId).isGreaterThan(0L);
- try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
- blobData.writeToSession(session);
-
+ commitBlob(blobData, session -> {
session.allowSameSignatureAccess();
session.allowPackageAccess(HELPER_PKG2, HELPER_PKG2_CERT_SHA256);
-
assertThat(session.isSameSignatureAccessAllowed()).isTrue();
assertThat(session.isPackageAccessAllowed(HELPER_PKG2, HELPER_PKG2_CERT_SHA256))
.isTrue();
assertThat(session.isPublicAccessAllowed()).isFalse();
-
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(0);
- }
+ });
assertPkgCanAccess(blobData, connection1);
assertPkgCanAccess(blobData, connection2);
@@ -563,7 +536,7 @@
@Test
public void testSessionCommit() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
@@ -594,7 +567,7 @@
@Test
public void testOpenBlob() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
@@ -631,43 +604,104 @@
@Test
public void testAcquireReleaseLease() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
assertThat(sessionId).isGreaterThan(0L);
- try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
- blobData.writeToSession(session);
-
- final CompletableFuture<Integer> callback = new CompletableFuture<>();
- session.commit(mContext.getMainExecutor(), callback::complete);
- assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
- .isEqualTo(0);
- }
+ commitBlob(blobData);
assertThrows(IllegalArgumentException.class, () ->
- mBlobStoreManager.acquireLease(blobData.getBlobHandle(),
+ acquireLease(mContext, blobData.getBlobHandle(),
R.string.test_desc, blobData.getExpiryTimeMillis() + 1000));
+ assertNoLeasedBlobs(mBlobStoreManager);
- mBlobStoreManager.acquireLease(blobData.getBlobHandle(), R.string.test_desc,
+ acquireLease(mContext, blobData.getBlobHandle(), R.string.test_desc,
blobData.getExpiryTimeMillis() - 1000);
- mBlobStoreManager.acquireLease(blobData.getBlobHandle(), R.string.test_desc);
- // TODO: verify acquiring lease took effect.
- mBlobStoreManager.releaseLease(blobData.getBlobHandle());
+ assertLeasedBlobs(mBlobStoreManager, blobData.getBlobHandle());
+ acquireLease(mContext, blobData.getBlobHandle(), R.string.test_desc);
+ assertLeasedBlobs(mBlobStoreManager, blobData.getBlobHandle());
+ releaseLease(mContext, blobData.getBlobHandle());
+ assertNoLeasedBlobs(mBlobStoreManager);
- mBlobStoreManager.acquireLease(blobData.getBlobHandle(), "Test description",
+ acquireLease(mContext, blobData.getBlobHandle(), "Test description",
blobData.getExpiryTimeMillis() - 20000);
- mBlobStoreManager.acquireLease(blobData.getBlobHandle(), "Test description two");
- mBlobStoreManager.releaseLease(blobData.getBlobHandle());
+ assertLeasedBlobs(mBlobStoreManager, blobData.getBlobHandle());
+ acquireLease(mContext, blobData.getBlobHandle(), "Test description two");
+ assertLeasedBlobs(mBlobStoreManager, blobData.getBlobHandle());
+ releaseLease(mContext, blobData.getBlobHandle());
+ assertNoLeasedBlobs(mBlobStoreManager);
} finally {
blobData.delete();
}
}
@Test
+ public void testAcquireLease_multipleLeases() throws Exception {
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
+ final DummyBlobData blobData2 = new DummyBlobData.Builder(mContext)
+ .setRandomSeed(42)
+ .build();
+ blobData.prepare();
+ blobData2.prepare();
+ try {
+ commitBlob(blobData);
+
+ acquireLease(mContext, blobData.getBlobHandle(), R.string.test_desc,
+ blobData.getExpiryTimeMillis() - 1000);
+ assertLeasedBlobs(mBlobStoreManager, blobData.getBlobHandle());
+
+ commitBlob(blobData2);
+
+ acquireLease(mContext, blobData2.getBlobHandle(), "Test desc2",
+ blobData.getExpiryTimeMillis() - 2000);
+ assertLeasedBlobs(mBlobStoreManager, blobData.getBlobHandle(),
+ blobData2.getBlobHandle());
+
+ releaseLease(mContext, blobData.getBlobHandle());
+ assertLeasedBlobs(mBlobStoreManager, blobData2.getBlobHandle());
+
+ releaseLease(mContext, blobData2.getBlobHandle());
+ assertNoLeasedBlobs(mBlobStoreManager);
+ } finally {
+ blobData.delete();
+ blobData2.delete();
+ }
+ }
+
+ @Test
+ public void testAcquireRelease_deleteImmediately() throws Exception {
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
+ blobData.prepare();
+ final long waitDurationMs = TimeUnit.SECONDS.toMillis(1);
+ runWithKeyValue(KEY_LEASE_ACQUISITION_WAIT_DURATION_MS, String.valueOf(waitDurationMs),
+ () -> {
+ try {
+ commitBlob(blobData);
+
+ acquireLease(mContext, blobData.getBlobHandle(), R.string.test_desc,
+ blobData.getExpiryTimeMillis());
+ assertLeasedBlobs(mBlobStoreManager, blobData.getBlobHandle());
+
+ SystemClock.sleep(waitDurationMs);
+
+ releaseLease(mContext, blobData.getBlobHandle());
+ assertNoLeasedBlobs(mBlobStoreManager);
+
+ assertThrows(SecurityException.class, () -> mBlobStoreManager.acquireLease(
+ blobData.getBlobHandle(), R.string.test_desc,
+ blobData.getExpiryTimeMillis()));
+ assertNoLeasedBlobs(mBlobStoreManager);
+ } finally {
+ blobData.delete();
+ }
+ });
+ }
+
+ @Test
public void testAcquireReleaseLease_invalidArguments() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
try {
assertThrows(NullPointerException.class, () -> mBlobStoreManager.acquireLease(
@@ -689,7 +723,7 @@
@Test
public void testStorageAttributedToSelf() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
final long partialFileSize = 3373L;
@@ -744,7 +778,8 @@
.isEqualTo(0);
}
- mBlobStoreManager.acquireLease(blobData.getBlobHandle(), R.string.test_desc);
+ acquireLease(mContext, blobData.getBlobHandle(), R.string.test_desc);
+ assertLeasedBlobs(mBlobStoreManager, blobData.getBlobHandle());
afterStatsForPkg = storageStatsManager
.queryStatsForPackage(UUID_DEFAULT, mContext.getPackageName(), mContext.getUser());
@@ -758,7 +793,8 @@
assertThat(afterStatsForUid.getDataBytes() - beforeStatsForUid.getDataBytes())
.isEqualTo(totalFileSize);
- mBlobStoreManager.releaseLease(blobData.getBlobHandle());
+ releaseLease(mContext, blobData.getBlobHandle());
+ assertNoLeasedBlobs(mBlobStoreManager);
afterStatsForPkg = storageStatsManager
.queryStatsForPackage(UUID_DEFAULT, mContext.getPackageName(), mContext.getUser());
@@ -774,7 +810,7 @@
@Test
public void testStorageAttribution_acquireLease() throws Exception {
- final DummyBlobData blobData = new DummyBlobData(mContext);
+ final DummyBlobData blobData = new DummyBlobData.Builder(mContext).build();
blobData.prepare();
final StorageStatsManager storageStatsManager = mContext.getSystemService(
@@ -853,6 +889,56 @@
}
}
+ private static void runWithKeyValue(String key, String value, ThrowingRunnable runnable)
+ throws Exception {
+ final AtomicReference<String> previousValue = new AtomicReference<>();
+ SystemUtil.runWithShellPermissionIdentity(() -> {
+ previousValue.set(DeviceConfig.getProperty(NAMESPACE_BLOBSTORE, key));
+ Log.i(TAG, key + " previous value: " + previousValue.get());
+ assertThat(DeviceConfig.setProperty(NAMESPACE_BLOBSTORE, key, value,
+ false /* makeDefault */)).isTrue();
+ Log.i(TAG, key + " value set: " + value);
+ });
+ try {
+ runnable.run();
+ } finally {
+ SystemUtil.runWithShellPermissionIdentity(() -> {
+ final String currentValue = DeviceConfig.getProperty(
+ NAMESPACE_BLOBSTORE, key);
+ if (!Objects.equals(previousValue.get(), currentValue)) {
+ assertThat(DeviceConfig.setProperty(NAMESPACE_BLOBSTORE,
+ key, previousValue.get(), false /* makeDefault */)).isTrue();
+ Log.i(TAG, key + " value restored: " + previousValue.get());
+ }
+ });
+ }
+ }
+
+ private void commitBlob(DummyBlobData blobData) throws Exception {
+ commitBlob(blobData, null);
+ }
+
+ private void commitBlob(DummyBlobData blobData,
+ AccessModifier accessModifier) throws Exception {
+ final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
+ assertThat(sessionId).isGreaterThan(0L);
+ try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
+ blobData.writeToSession(session);
+
+ if (accessModifier != null) {
+ accessModifier.modify(session);
+ }
+ final CompletableFuture<Integer> callback = new CompletableFuture<>();
+ session.commit(mContext.getMainExecutor(), callback::complete);
+ assertThat(callback.get(TIMEOUT_COMMIT_CALLBACK_SEC, TimeUnit.SECONDS))
+ .isEqualTo(0);
+ }
+ }
+
+ private interface AccessModifier {
+ void modify(BlobStoreManager.Session session) throws Exception;
+ }
+
private void commitBlobFromPkg(DummyBlobData blobData, TestServiceConnection serviceConnection)
throws Exception {
commitBlobFromPkg(blobData, ICommandReceiver.FLAG_ACCESS_TYPE_PRIVATE, serviceConnection);
diff --git a/tests/JobScheduler/Android.bp b/tests/JobScheduler/Android.bp
index 9869c74..e9be178 100644
--- a/tests/JobScheduler/Android.bp
+++ b/tests/JobScheduler/Android.bp
@@ -19,6 +19,7 @@
"compatibility-device-util-axt",
"ub-uiautomator",
"androidx.test.rules",
+ "cts-wm-util",
],
libs: ["android.test.base.stubs"],
srcs: [
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
index effabb7..895c563 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
@@ -232,7 +232,7 @@
sendScheduleJobBroadcast(false);
assertFalse("Job started for restricted app",
mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT));
- mTestAppInterface.startAndKeepTestActivity();
+ mTestAppInterface.startAndKeepTestActivity(true);
assertTrue("Job did not start when app had an activity",
mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT));
}
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/TestAppInterface.java b/tests/JobScheduler/src/android/jobscheduler/cts/TestAppInterface.java
index 36d1825..d871a2b 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/TestAppInterface.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/TestAppInterface.java
@@ -18,6 +18,7 @@
import static android.jobscheduler.cts.jobtestapp.TestJobService.ACTION_JOB_STARTED;
import static android.jobscheduler.cts.jobtestapp.TestJobService.ACTION_JOB_STOPPED;
import static android.jobscheduler.cts.jobtestapp.TestJobService.JOB_PARAMS_EXTRA_KEY;
+import static android.server.wm.WindowManagerState.STATE_RESUMED;
import android.app.job.JobParameters;
import android.content.BroadcastReceiver;
@@ -28,6 +29,7 @@
import android.jobscheduler.cts.jobtestapp.TestActivity;
import android.jobscheduler.cts.jobtestapp.TestJobSchedulerReceiver;
import android.os.SystemClock;
+import android.server.wm.WindowManagerStateHelper;
import android.util.Log;
/**
@@ -77,10 +79,18 @@
}
void startAndKeepTestActivity() {
+ startAndKeepTestActivity(false);
+ }
+
+ void startAndKeepTestActivity(boolean waitForResume) {
final Intent testActivity = new Intent();
testActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- testActivity.setComponent(new ComponentName(TEST_APP_PACKAGE, TEST_APP_ACTIVITY));
+ ComponentName testComponentName = new ComponentName(TEST_APP_PACKAGE, TEST_APP_ACTIVITY);
+ testActivity.setComponent(testComponentName);
mContext.startActivity(testActivity);
+ if (waitForResume) {
+ new WindowManagerStateHelper().waitForActivityState(testComponentName, STATE_RESUMED);
+ }
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java
index 8f79102..4d84a73 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java
@@ -17,6 +17,7 @@
package android.accessibilityservice.cts;
import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen;
+import static android.accessibilityservice.cts.utils.AsyncUtils.DEFAULT_TIMEOUT_MS;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -27,13 +28,18 @@
import android.accessibilityservice.cts.activities.AccessibilityTestActivity;
import android.app.Instrumentation;
import android.app.UiAutomation;
+import android.graphics.Point;
import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.view.Display;
import android.view.SurfaceControlViewHost;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityWindowInfo;
import androidx.test.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
@@ -49,6 +55,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* Tests that AccessibilityNodeInfos from an embedded hierarchy that is present to another
@@ -131,7 +138,7 @@
}
@Test
- public void testEmbeddedViewHasCorrectBoundAfterHostViewMove() {
+ public void testEmbeddedViewHasCorrectBoundAfterHostViewMove() throws TimeoutException {
final AccessibilityNodeInfo target =
findEmbeddedAccessibilityNodeInfo(sUiAutomation.getRootInActiveWindow());
@@ -140,14 +147,13 @@
final Rect oldEmbeddedViewBoundsInScreen = new Rect();
target.getBoundsInScreen(oldEmbeddedViewBoundsInScreen);
- // Move Host SurfaceView from (0, 0) to (100, 100).
- mActivity.requestNewLayoutForTest();
+ // Move Host SurfaceView from (0, 0) to (50, 50).
+ mActivity.requestNewLayoutForTest(50, 50);
- final AccessibilityNodeInfo newTarget =
- findEmbeddedAccessibilityNodeInfo(sUiAutomation.getRootInActiveWindow());
- final AccessibilityNodeInfo parent = newTarget.getParent();
+ target.refresh();
+ final AccessibilityNodeInfo parent = target.getParent();
- newTarget.getBoundsInScreen(newEmbeddedViewBoundsInScreen);
+ target.getBoundsInScreen(newEmbeddedViewBoundsInScreen);
parent.getBoundsInScreen(hostViewBoundsInScreen);
assertTrue("hostViewBoundsInScreen" + hostViewBoundsInScreen.toShortString()
@@ -160,6 +166,22 @@
newEmbeddedViewBoundsInScreen.equals(oldEmbeddedViewBoundsInScreen));
}
+ @Test
+ public void testEmbeddedViewIsInvisibleAfterMovingOutOfScreen() throws TimeoutException {
+ final AccessibilityNodeInfo target =
+ findEmbeddedAccessibilityNodeInfo(sUiAutomation.getRootInActiveWindow());
+ assertTrue("Embedded view should be visible at beginning.",
+ target.isVisibleToUser());
+
+ // Move Host SurfaceView out of screen
+ final Point screenSize = getScreenSize();
+ mActivity.requestNewLayoutForTest(screenSize.x, screenSize.y);
+
+ target.refresh();
+ assertFalse("Embedded view should be invisible after moving out of screen.",
+ target.isVisibleToUser());
+ }
+
private AccessibilityNodeInfo findEmbeddedAccessibilityNodeInfo(AccessibilityNodeInfo root) {
final int childCount = root.getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -177,6 +199,15 @@
return null;
}
+ private Point getScreenSize() {
+ final DisplayManager dm = sInstrumentation.getContext().getSystemService(
+ DisplayManager.class);
+ final Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
+ final DisplayMetrics metrics = new DisplayMetrics();
+ display.getRealMetrics(metrics);
+ return new Point(metrics.widthPixels, metrics.heightPixels);
+ }
+
/**
* This class is an dummy {@link android.app.Activity} used to perform embedded hierarchy
* testing of the accessibility feature by interaction with the UI widgets.
@@ -188,9 +219,6 @@
private static final int DEFAULT_WIDTH = 150;
private static final int DEFAULT_HEIGHT = 150;
- private static final int POSITION_X = 50;
- private static final int POSITION_Y = 50;
-
private SurfaceView mSurfaceView;
private SurfaceControlViewHost mViewHost;
@@ -211,7 +239,7 @@
View layout = getLayoutInflater().inflate(
R.layout.accessibility_embedded_hierarchy_test_embedded_side, null);
- mViewHost.addView(layout, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ mViewHost.setView(layout, DEFAULT_WIDTH, DEFAULT_HEIGHT);
mCountDownLatch.countDown();
}
@@ -234,12 +262,20 @@
}
}
- public void requestNewLayoutForTest() {
- sInstrumentation.runOnMainSync(() -> {
- mSurfaceView.setX(POSITION_X);
- mSurfaceView.setY(POSITION_Y);
- mSurfaceView.requestLayout();
- });
+ public void requestNewLayoutForTest(int x, int y) throws TimeoutException {
+ sUiAutomation.executeAndWaitForEvent(
+ () -> sInstrumentation.runOnMainSync(() -> {
+ mSurfaceView.setX(x);
+ mSurfaceView.setY(y);
+ mSurfaceView.requestLayout();
+ }),
+ (event) -> {
+ final Rect boundsInScreen = new Rect();
+ final AccessibilityWindowInfo window =
+ sUiAutomation.getRootInActiveWindow().getWindow();
+ window.getBoundsInScreen(boundsInScreen);
+ return !boundsInScreen.isEmpty();
+ }, DEFAULT_TIMEOUT_MS);
}
}
}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTakeScreenshotTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTakeScreenshotTest.java
index 93b8a06..15940cc 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTakeScreenshotTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTakeScreenshotTest.java
@@ -17,14 +17,17 @@
package android.accessibilityservice.cts;
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.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibility.cts.common.InstrumentedAccessibilityServiceTestRule;
import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityService.ScreenshotResult;
+import android.accessibilityservice.AccessibilityService.TakeScreenshotCallback;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.ColorSpace;
@@ -41,14 +44,21 @@
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
-
-import java.util.function.Consumer;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
/**
* Test cases for accessibility service takeScreenshot API.
*/
@RunWith(AndroidJUnit4.class)
public class AccessibilityTakeScreenshotTest {
+ /**
+ * The timeout for waiting screenshot had been taken done.
+ */
+ private static final long TIMEOUT_TAKE_SCREENSHOT_DONE_MILLIS = 1000;
+
private InstrumentedAccessibilityServiceTestRule<StubTakeScreenshotService> mServiceRule =
new InstrumentedAccessibilityServiceTestRule<>(StubTakeScreenshotService.class);
@@ -64,9 +74,14 @@
private Context mContext;
private Point mDisplaySize;
private long mStartTestingTime;
+ @Mock
+ private TakeScreenshotCallback mCallback;
+ @Captor
+ private ArgumentCaptor<ScreenshotResult> mSuccessResultArgumentCaptor;
@Before
public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
mService = mServiceRule.getService();
mContext = mService.getApplicationContext();
@@ -80,29 +95,46 @@
@Test
public void testTakeScreenshot_GetScreenshotResult() {
- mStartTestingTime = SystemClock.uptimeMillis();
- Consumer<AccessibilityService.ScreenshotResult> screenshotConsumer =
- new TakeScreenshotConsumer();
- mService.takeScreenshot(Display.DEFAULT_DISPLAY, mContext.getMainExecutor(),
- screenshotConsumer);
+ takeScreenshot();
+ verify(mCallback, timeout(TIMEOUT_TAKE_SCREENSHOT_DONE_MILLIS)).onSuccess(
+ mSuccessResultArgumentCaptor.capture());
+
+ verifyScreenshotResult(mSuccessResultArgumentCaptor.getValue());
}
@Test
public void testTakeScreenshot_RequestIntervalTime() throws Exception {
- final Consumer callback = mock(Consumer.class);
- assertTrue(mService.takeScreenshot(Display.DEFAULT_DISPLAY, mContext.getMainExecutor(),
- callback));
+ takeScreenshot();
+ verify(mCallback, timeout(TIMEOUT_TAKE_SCREENSHOT_DONE_MILLIS)).onSuccess(
+ mSuccessResultArgumentCaptor.capture());
+
Thread.sleep(
AccessibilityService.ACCESSIBILITY_TAKE_SCREENSHOT_REQUEST_INTERVAL_TIMES_MS / 2);
// Requests the API again during interval time from calling the first time.
- assertFalse(mService.takeScreenshot(Display.DEFAULT_DISPLAY, mContext.getMainExecutor(),
- callback));
+ takeScreenshot();
+ verify(mCallback, timeout(TIMEOUT_TAKE_SCREENSHOT_DONE_MILLIS)).onFailure(
+ AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERVAL_TIME_SHORT);
+
Thread.sleep(
AccessibilityService.ACCESSIBILITY_TAKE_SCREENSHOT_REQUEST_INTERVAL_TIMES_MS / 2 +
1);
// Requests the API again after interval time from calling the first time.
- assertTrue(mService.takeScreenshot(Display.DEFAULT_DISPLAY, mContext.getMainExecutor(),
- callback));
+ takeScreenshot();
+ verify(mCallback, timeout(TIMEOUT_TAKE_SCREENSHOT_DONE_MILLIS)).onSuccess(
+ mSuccessResultArgumentCaptor.capture());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testTakeScreenshotWithNonDefaultDisplay_GetIllegalArgumentException() {
+ // DisplayId isn't the default display, should throw illegalArgument exception.
+ mService.takeScreenshot(Display.DEFAULT_DISPLAY + 1,
+ mContext.getMainExecutor(), mCallback);
+ }
+
+ private void takeScreenshot() {
+ mStartTestingTime = SystemClock.uptimeMillis();
+ mService.takeScreenshot(Display.DEFAULT_DISPLAY, mContext.getMainExecutor(),
+ mCallback);
}
private void verifyScreenshotResult(AccessibilityService.ScreenshotResult screenshot) {
@@ -122,10 +154,4 @@
final Bitmap bitmap = Bitmap.wrapHardwareBuffer(hardwareBuffer, colorSpace);
assertNotNull(bitmap);
}
-
- class TakeScreenshotConsumer implements Consumer<AccessibilityService.ScreenshotResult> {
- public void accept(AccessibilityService.ScreenshotResult screenshot) {
- verifyScreenshotResult(screenshot);
- }
- }
}
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index c1a02ab..1c38b39 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -1114,29 +1114,29 @@
}
}
- public void testSetProtectedPackages_failIfNotDeviceOwner() {
+ public void testSetUserControlDisabledPackages_failIfNotDeviceOwner() {
if (!mDeviceAdmin) {
- Log.w(TAG, "Skipping testSetProtectedPackages_failIfNotDeviceOwner()");
+ Log.w(TAG, "Skipping testSetUserControlDisabledPackages_failIfNotDeviceOwner()");
return;
}
final String TEST_PACKAGE_NAME = "package1";
List<String> packages = new ArrayList<>();
packages.add(TEST_PACKAGE_NAME);
try {
- mDevicePolicyManager.setProtectedPackages(mComponent, packages);
- fail("setProtectedPackages did not throw expected SecurityException");
+ mDevicePolicyManager.setUserControlDisabledPackages(mComponent, packages);
+ fail("setUserControlDisabledPackages did not throw expected SecurityException");
} catch(SecurityException e) {
}
}
- public void testGetProtectedPackages_failIfNotDeviceOwner() {
+ public void testGetUserControlDisabledPackages_failIfNotDeviceOwner() {
if (!mDeviceAdmin) {
- Log.w(TAG, "Skipping testGetProtectedPackages_failIfNotDeviceOwner()");
+ Log.w(TAG, "Skipping testGetUserControlDisabledPackages_failIfNotDeviceOwner()");
return;
}
try {
- mDevicePolicyManager.getProtectedPackages(mComponent);
- fail("getProtectedPackages did not throw expected SecurityException");
+ mDevicePolicyManager.getUserControlDisabledPackages(mComponent);
+ fail("getUserControlDisabledPackages did not throw expected SecurityException");
} catch(SecurityException e) {
}
}
diff --git a/tests/app/ActivityManagerApi29Test/AndroidManifest.xml b/tests/app/ActivityManagerApi29Test/AndroidManifest.xml
index 86f1cd2..0c75ff4 100644
--- a/tests/app/ActivityManagerApi29Test/AndroidManifest.xml
+++ b/tests/app/ActivityManagerApi29Test/AndroidManifest.xml
@@ -35,7 +35,7 @@
</intent-filter>
</activity>
<service android:name="LocationForegroundService"
- android:foregroundServiceType="location"
+ android:foregroundServiceType="location|camera|microphone"
android:exported="true">
</service>
</application>
diff --git a/tests/app/AppExitTest/AndroidManifest.xml b/tests/app/AppExitTest/AndroidManifest.xml
index a73a72e..316959d 100644
--- a/tests/app/AppExitTest/AndroidManifest.xml
+++ b/tests/app/AppExitTest/AndroidManifest.xml
@@ -18,6 +18,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.app.cts.appexit">
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
+ <uses-permission android:name="android.permission.READ_LOGS"/>
+
<application android:usesCleartextTraffic="true">
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/app/AppExitTest/AndroidTest.xml b/tests/app/AppExitTest/AndroidTest.xml
index 0fdb0a7..1658417 100644
--- a/tests/app/AppExitTest/AndroidTest.xml
+++ b/tests/app/AppExitTest/AndroidTest.xml
@@ -26,6 +26,16 @@
<option name="test-file-name" value="CtsSimpleApp.apk" />
<option name="test-file-name" value="CtsAppExitTestCases.apk" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command"
+ value="pm grant android.app.cts.appexit android.permission.PACKAGE_USAGE_STATS" />
+ <option name="run-command"
+ value="pm grant android.app.cts.appexit android.permission.READ_LOGS" />
+ <option name="teardown-command"
+ value="pm revoke android.app.cts.appexit android.permission.PACKAGE_USAGE_STATS"/>
+ <option name="teardown-command"
+ value="pm revoke android.app.cts.appexit android.permission.READ_LOGS"/>
+ </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="package" value="android.app.cts.appexit" />
diff --git a/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java b/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java
index b815cc0..5aaca09 100644
--- a/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java
+++ b/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java
@@ -21,11 +21,13 @@
import android.app.ApplicationExitInfo;
import android.app.Instrumentation;
import android.app.cts.android.app.cts.tools.WatchUidRunner;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
+import android.content.IntentFilter;
import android.os.Bundle;
+import android.os.DropBoxManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@@ -46,8 +48,10 @@
import com.android.compatibility.common.util.ShellIdentityUtils;
import com.android.compatibility.common.util.SystemUtil;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.MemInfoReader;
+import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileDescriptor;
@@ -71,6 +75,8 @@
"com.android.cts.launcherapps.simpleapp.SimpleService4";
private static final String STUB_SERVICE_REMOTE_NAME =
"com.android.cts.launcherapps.simpleapp.SimpleService5";
+ private static final String STUB_SERVICE_ISOLATED_NAME =
+ "com.android.cts.launcherapps.simpleapp.SimpleService6";
private static final String STUB_RECEIVER_NAMWE =
"com.android.cts.launcherapps.simpleapp.SimpleReceiver";
private static final String STUB_ROCESS_NAME = STUB_PACKAGE_NAME;
@@ -81,6 +87,7 @@
private static final String EXTRA_ACTION = "action";
private static final String EXTRA_MESSENGER = "messenger";
private static final String EXTRA_PROCESS_NAME = "process";
+ private static final String EXTRA_COOKIE = "cookie";
private static final int ACTION_NONE = 0;
private static final int ACTION_FINISH = 1;
@@ -106,6 +113,9 @@
private int mStubPackageOtherUid;
private int mStubPackageOtherUserPid;
private int mStubPackageRemoteOtherUserPid;
+ private int mStubPackageIsolatedUid;
+ private int mStubPackageIsolatedPid;
+ private String mStubPackageIsolatedProcessName;
private WatchUidRunner mWatcher;
private WatchUidRunner mOtherUidWatcher;
private ActivityManager mActivityManager;
@@ -119,6 +129,7 @@
private UserHandle mCurrentUserHandle;
private int mOtherUserId;
private UserHandle mOtherUserHandle;
+ private DropBoxManager.Entry mAnrEntry;
@Override
protected void setUp() throws Exception {
@@ -152,7 +163,6 @@
mStubPackagePid = msg.arg1;
assertTrue(mStubPackagePid > 0);
}
- didSomething = true;
} else if (STUB_REMOTE_ROCESS_NAME.equals(processName)) {
if (mOtherUserId != 0 && UserHandle.getUserId(msg.arg2) == mOtherUserId) {
mStubPackageRemoteOtherUserPid = msg.arg1;
@@ -161,13 +171,17 @@
mStubPackageRemotePid = msg.arg1;
assertTrue(mStubPackageRemotePid > 0);
}
- didSomething = true;
+ } else { // must be isolated process
+ mStubPackageIsolatedPid = msg.arg1;
+ mStubPackageIsolatedUid = msg.arg2;
+ mStubPackageIsolatedProcessName = processName;
+ assertTrue(mStubPackageIsolatedPid > 0);
+ assertTrue(mStubPackageIsolatedUid > 0);
+ assertNotNull(processName);
}
- if (didSomething) {
- if (mLatch != null) {
- mLatch.countDown();
- }
+ if (mLatch != null) {
+ mLatch.countDown();
}
}
@@ -270,15 +284,18 @@
// Start the target package
private void startService(int commandCode, String serviceName, boolean waitForGone,
boolean other) {
- startService(commandCode, serviceName, waitForGone, true, other);
+ startService(commandCode, serviceName, waitForGone, true, other, false, null);
}
private void startService(int commandCode, String serviceName, boolean waitForGone,
- boolean waitForIdle, boolean other) {
+ boolean waitForIdle, boolean other, boolean includeCookie, byte[] cookie) {
Intent intent = new Intent(EXIT_ACTION);
intent.setClassName(STUB_PACKAGE_NAME, serviceName);
intent.putExtra(EXTRA_ACTION, commandCode);
intent.putExtra(EXTRA_MESSENGER, mMessenger);
+ if (includeCookie) {
+ intent.putExtra(EXTRA_COOKIE, cookie);
+ }
mLatch = new CountDownLatch(1);
UserHandle user = other ? mOtherUserHandle : mCurrentUserHandle;
WatchUidRunner watcher = other ? mOtherUidWatcher : mWatcher;
@@ -292,6 +309,16 @@
awaitForLatch(mLatch);
}
+ private void startIsolatedService(int commandCode, String serviceName) {
+ Intent intent = new Intent(EXIT_ACTION);
+ intent.setClassName(STUB_PACKAGE_NAME, serviceName);
+ intent.putExtra(EXTRA_ACTION, commandCode);
+ intent.putExtra(EXTRA_MESSENGER, mMessenger);
+ mLatch = new CountDownLatch(1);
+ mContext.startServiceAsUser(intent, mCurrentUserHandle);
+ awaitForLatch(mLatch);
+ }
+
private void waitForGone(WatchUidRunner watcher) {
watcher.waitFor(WatchUidRunner.CMD_GONE, null);
// Give a few seconds to generate the exit report.
@@ -464,6 +491,21 @@
// Remove old records to avoid interference with the test.
clearHistoricalExitInfo();
+ final DropBoxManager dbox = mContext.getSystemService(DropBoxManager.class);
+ final CountDownLatch dboxLatch = new CountDownLatch(1);
+ final BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String tag_anr = "data_app_anr";
+ if (tag_anr.equals(intent.getStringExtra(DropBoxManager.EXTRA_TAG))) {
+ mAnrEntry = dbox.getNextEntry(tag_anr, intent.getLongExtra(
+ DropBoxManager.EXTRA_TIME, 0) - 1);
+ dboxLatch.countDown();
+ }
+ }
+ };
+ mContext.registerReceiver(receiver,
+ new IntentFilter(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED));
final long timeout = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.BROADCAST_FG_CONSTANTS, 10 * 1000) * 3;
@@ -483,6 +525,10 @@
// This will result an ANR
mContext.sendOrderedBroadcast(intent, null);
+ // Wait for the early ANR
+ monitor.waitFor(Monitor.WAIT_FOR_EARLY_ANR, timeout);
+ // Continue, so we could collect ANR traces
+ monitor.sendCommand(Monitor.CMD_CONTINUE);
// Wait for the ANR
monitor.waitFor(Monitor.WAIT_FOR_ANR, timeout);
// Kill it
@@ -491,67 +537,85 @@
waitForGone(mWatcher);
long now2 = System.currentTimeMillis();
+ awaitForLatch(dboxLatch);
+ assertTrue(mAnrEntry != null);
+
List<ApplicationExitInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions(
STUB_PACKAGE_NAME, mStubPackagePid, 1,
mActivityManager::getHistoricalProcessExitReasons,
android.Manifest.permission.DUMP);
assertTrue(list != null && list.size() == 1);
- verify(list.get(0), mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME,
+ ApplicationExitInfo info = list.get(0);
+ verify(info, mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME,
ApplicationExitInfo.REASON_ANR, null, null, now, now2);
+ // Verify the traces
+
+ // Read from dropbox
+ final String dboxTrace = mAnrEntry.getText(0x100000 /* 1M */);
+ assertFalse(TextUtils.isEmpty(dboxTrace));
+
+ // Read the input stream from the ApplicationExitInfo
+ String trace = ShellIdentityUtils.invokeMethodWithShellPermissions(info, (i) -> {
+ try (BufferedInputStream input = new BufferedInputStream(i.getTraceInputStream())) {
+ StringBuilder sb = new StringBuilder();
+ byte[] buf = new byte[8192];
+ while (true) {
+ final int len = input.read(buf, 0, buf.length);
+ if (len <= 0) {
+ break;
+ }
+ sb.append(new String(buf, 0, len));
+ }
+ return sb.toString();
+ } catch (IOException e) {
+ return null;
+ }
+ }, android.Manifest.permission.DUMP);
+ assertFalse(TextUtils.isEmpty(trace));
+ assertTrue(trace.indexOf(Integer.toString(info.getPid())) >= 0);
+ assertTrue(trace.indexOf("Cmd line: " + STUB_PACKAGE_NAME) >= 0);
+ assertTrue(dboxTrace.indexOf(trace) >= 0);
+
monitor.finish();
+ mContext.unregisterReceiver(receiver);
}
public void testOther() throws Exception {
// Remove old records to avoid interference with the test.
clearHistoricalExitInfo();
- // Enable a compat feature
- executeShellCmd("am compat enable " + PackageManager.FILTER_APPLICATION_QUERY
- + " " + STUB_PACKAGE_NAME);
- mInstrumentation.getUiAutomation().grantRuntimePermission(
- STUB_PACKAGE_NAME, android.Manifest.permission.READ_CALENDAR);
long now = System.currentTimeMillis();
- // Start a process and do nothing
- startService(ACTION_FINISH, STUB_SERVICE_NAME, false, false);
+ // Start an isolated process and do nothing
+ startIsolatedService(ACTION_NONE, STUB_SERVICE_ISOLATED_NAME);
- // Enable high frequency memory sampling
- executeShellCmd("dumpsys procstats --start-testing");
- // Sleep for a while to wait for the sampling of memory info
- sleep(10000);
- // Stop the high frequency memory sampling
- executeShellCmd("dumpsys procstats --stop-testing");
- // Get the memory info from it.
- String dump = executeShellCmd("dumpsys activity processes " + STUB_PACKAGE_NAME);
- assertNotNull(dump);
- final String lastPss = extractMemString(dump, " lastPss=", ' ');
- final String lastRss = extractMemString(dump, " lastRss=", '\n');
+ final WatchUidRunner watcher = new WatchUidRunner(mInstrumentation,
+ mStubPackageIsolatedUid, WAITFOR_MSEC);
- // Disable the compat feature
- executeShellCmd("am compat disable " + PackageManager.FILTER_APPLICATION_QUERY
- + " " + STUB_PACKAGE_NAME);
+ // Finish the service in the isolated process
+ startIsolatedService(ACTION_FINISH, STUB_SERVICE_ISOLATED_NAME);
- waitForGone(mWatcher);
+ try {
+ // Isolated process should have been killed as long as its service is done.
+ waitForGone(watcher);
+ } finally {
+ watcher.finish();
+ }
long now2 = System.currentTimeMillis();
List<ApplicationExitInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions(
- STUB_PACKAGE_NAME, mStubPackagePid, 1,
+ STUB_PACKAGE_NAME, mStubPackageIsolatedPid, 1,
mActivityManager::getHistoricalProcessExitReasons,
android.Manifest.permission.DUMP);
assertTrue(list != null && list.size() == 1);
ApplicationExitInfo info = list.get(0);
- verify(info, mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME,
- ApplicationExitInfo.REASON_OTHER, null, "PlatformCompat overrides", now, now2);
-
- // Also verify that we get the expected meminfo
- assertEquals(lastPss, DebugUtils.sizeValueToString(
- info.getPss() * 1024, new StringBuilder()));
- assertEquals(lastRss, DebugUtils.sizeValueToString(
- info.getRss() * 1024, new StringBuilder()));
+ verify(info, mStubPackageIsolatedPid, mStubPackageIsolatedUid,
+ mStubPackageIsolatedProcessName, ApplicationExitInfo.REASON_OTHER, null,
+ "isolated not needed", now, now2);
}
private String extractMemString(String dump, String prefix, char nextSep) {
@@ -575,6 +639,18 @@
// Start a process and do nothing
startService(ACTION_FINISH, STUB_SERVICE_NAME, false, false);
+ // Enable high frequency memory sampling
+ executeShellCmd("dumpsys procstats --start-testing");
+ // Sleep for a while to wait for the sampling of memory info
+ sleep(10000);
+ // Stop the high frequency memory sampling
+ executeShellCmd("dumpsys procstats --stop-testing");
+ // Get the memory info from it.
+ String dump = executeShellCmd("dumpsys activity processes " + STUB_PACKAGE_NAME);
+ assertNotNull(dump);
+ final String lastPss = extractMemString(dump, " lastPss=", ' ');
+ final String lastRss = extractMemString(dump, " lastRss=", '\n');
+
// Revoke the read calendar permission
mInstrumentation.getUiAutomation().revokeRuntimePermission(
STUB_PACKAGE_NAME, android.Manifest.permission.READ_CALENDAR);
@@ -591,6 +667,12 @@
ApplicationExitInfo info = list.get(0);
verify(info, mStubPackagePid, mStubPackageUid, STUB_PACKAGE_NAME,
ApplicationExitInfo.REASON_PERMISSION_CHANGE, null, null, now, now2);
+
+ // Also verify that we get the expected meminfo
+ assertEquals(lastPss, DebugUtils.sizeValueToString(
+ info.getPss() * 1024, new StringBuilder()));
+ assertEquals(lastRss, DebugUtils.sizeValueToString(
+ info.getRss() * 1024, new StringBuilder()));
}
public void testCrash() throws Exception {
@@ -691,7 +773,7 @@
now = System.currentTimeMillis();
// Now let the provider exit itself
- startService(ACTION_KILL_PROVIDER, STUB_SERVICE_NAME, false, false, false);
+ startService(ACTION_KILL_PROVIDER, STUB_SERVICE_NAME, false, false, false, false, null);
// Wait for both of the processes gone
waitForGone(mWatcher);
@@ -789,25 +871,39 @@
// Create the test user, we'll remove it during tearDown
prepareTestUser();
+ final byte[] cookie0 = {(byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03,
+ (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07};
+ final byte[] cookie1 = {(byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+ (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08};
+ final byte[] cookie2 = {(byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05,
+ (byte) 0x06, (byte) 0x07, (byte) 0x08, (byte) 0x01};
+ final byte[] cookie3 = {(byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06,
+ (byte) 0x07, (byte) 0x08, (byte) 0x01, (byte) 0x02};
+ final byte[] cookie4 = {(byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
+ (byte) 0x08, (byte) 0x01, (byte) 0x02, (byte) 0x03};
+ final byte[] cookie5 = null;
+
long now = System.currentTimeMillis();
- // Start a process and exit itself
- startService(ACTION_EXIT, STUB_SERVICE_NAME, true, false);
+ // Start a process and do nothing
+ startService(ACTION_NONE, STUB_SERVICE_NAME, false, true, false, true, cookie0);
+ // request to exit by itself with a different cookie
+ startService(ACTION_EXIT, STUB_SERVICE_NAME, true, false, false, true, cookie1);
long now2 = System.currentTimeMillis();
// Start the process in a secondary user and kill itself
- startService(ACTION_KILL, STUB_SERVICE_NAME, true, true);
+ startService(ACTION_KILL, STUB_SERVICE_NAME, true, true, true, true, cookie2);
long now3 = System.currentTimeMillis();
// Start a remote process in a secondary user and exit
- startService(ACTION_EXIT, STUB_SERVICE_REMOTE_NAME, true, true);
+ startService(ACTION_EXIT, STUB_SERVICE_REMOTE_NAME, true, true, true, true, cookie3);
long now4 = System.currentTimeMillis();
// Start a remote process and kill itself
- startService(ACTION_KILL, STUB_SERVICE_REMOTE_NAME, true, false);
+ startService(ACTION_KILL, STUB_SERVICE_REMOTE_NAME, true, true, false, true, cookie4);
long now5 = System.currentTimeMillis();
// drop the permissions
@@ -845,9 +941,10 @@
assertTrue(list != null && list.size() == 2);
verify(list.get(0), mStubPackageRemotePid, mStubPackageUid, STUB_REMOTE_ROCESS_NAME,
- ApplicationExitInfo.REASON_SIGNALED, OsConstants.SIGKILL, null, now4, now5);
+ ApplicationExitInfo.REASON_SIGNALED, OsConstants.SIGKILL, null, now4, now5,
+ cookie4);
verify(list.get(1), mStubPackagePid, mStubPackageUid, STUB_ROCESS_NAME,
- ApplicationExitInfo.REASON_EXIT_SELF, EXIT_CODE, null, now, now2);
+ ApplicationExitInfo.REASON_EXIT_SELF, EXIT_CODE, null, now, now2, cookie1);
// Now try the other user
try {
@@ -870,16 +967,17 @@
assertTrue(list != null && list.size() == 2);
verify(list.get(0), mStubPackageRemoteOtherUserPid, mStubPackageOtherUid,
STUB_REMOTE_ROCESS_NAME, ApplicationExitInfo.REASON_EXIT_SELF, EXIT_CODE,
- null, now3, now4);
+ null, now3, now4, cookie3);
verify(list.get(1), mStubPackageOtherUserPid, mStubPackageOtherUid, STUB_ROCESS_NAME,
- ApplicationExitInfo.REASON_SIGNALED, OsConstants.SIGKILL, null, now2, now3);
+ ApplicationExitInfo.REASON_SIGNALED, OsConstants.SIGKILL, null,
+ now2, now3, cookie2);
// Get the full user permission in order to start service as other user
mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(
android.Manifest.permission.INTERACT_ACROSS_USERS,
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
// Start the process in a secondary user and do nothing
- startService(ACTION_NONE, STUB_SERVICE_NAME, false, true);
+ startService(ACTION_NONE, STUB_SERVICE_NAME, false, true, true, true, cookie5);
// drop the permissions
mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
@@ -896,7 +994,7 @@
android.Manifest.permission.DUMP,
android.Manifest.permission.INTERACT_ACROSS_USERS);
verify(list.get(0), mStubPackageOtherUserPid, mStubPackageOtherUid, STUB_ROCESS_NAME,
- ApplicationExitInfo.REASON_USER_STOPPED, null, null, now6, now7);
+ ApplicationExitInfo.REASON_USER_STOPPED, null, null, now6, now7, cookie5);
int otherUserId = mOtherUserId;
// Now remove the other user
@@ -927,13 +1025,20 @@
assertTrue(list != null && list.size() == 2);
verify(list.get(0), mStubPackageRemotePid, mStubPackageUid, STUB_REMOTE_ROCESS_NAME,
- ApplicationExitInfo.REASON_SIGNALED, OsConstants.SIGKILL, null, now4, now5);
+ ApplicationExitInfo.REASON_SIGNALED, OsConstants.SIGKILL, null, now4, now5,
+ cookie4);
verify(list.get(1), mStubPackagePid, mStubPackageUid, STUB_ROCESS_NAME,
- ApplicationExitInfo.REASON_EXIT_SELF, EXIT_CODE, null, now, now2);
+ ApplicationExitInfo.REASON_EXIT_SELF, EXIT_CODE, null, now, now2, cookie1);
}
private void verify(ApplicationExitInfo info, int pid, int uid, String processName,
int reason, Integer status, String description, long before, long after) {
+ verify(info, pid, uid, processName, reason, status, description, before, after, null);
+ }
+
+ private void verify(ApplicationExitInfo info, int pid, int uid, String processName,
+ int reason, Integer status, String description, long before, long after,
+ byte[] cookie) {
assertNotNull(info);
assertEquals(pid, info.getPid());
assertEquals(uid, info.getRealUid());
@@ -947,13 +1052,17 @@
}
assertTrue(before <= info.getTimestamp());
assertTrue(after >= info.getTimestamp());
+ assertTrue(ArrayUtils.equals(info.getProcessStateSummary(), cookie,
+ cookie == null ? 0 : cookie.length));
}
/**
* A utility class interact with "am monitor"
*/
private static class Monitor {
- static final String WAIT_FOR_ANR = "Waiting after early ANR... available commands:";
+ static final String WAIT_FOR_EARLY_ANR = "Waiting after early ANR... available commands:";
+ static final String WAIT_FOR_ANR = "Waiting after ANR... available commands:";
+ static final String CMD_CONTINUE = "c";
static final String CMD_KILL = "k";
final Instrumentation mInstrumentation;
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index 59368ad..c73b7d1 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -135,14 +135,15 @@
<service android:name="android.app.stubs.LocalStoppedService" />
- <service android:name="android.app.stubs.LocalForegroundService">
+ <service android:name="android.app.stubs.LocalForegroundService"
+ android:foregroundServiceType="camera|microphone">
<intent-filter>
<action android:name="android.app.stubs.FOREGROUND_SERVICE" />
</intent-filter>
</service>
<service android:name="android.app.stubs.LocalForegroundServiceLocation"
- android:foregroundServiceType="location">
+ android:foregroundServiceType="location|camera|microphone">
<intent-filter>
<action android:name="android.app.stubs.FOREGROUND_SERVICE_LOCATION" />
</intent-filter>
diff --git a/tests/app/app/src/android/app/stubs/LocalForegroundServiceLocation.java b/tests/app/app/src/android/app/stubs/LocalForegroundServiceLocation.java
index e013dc2..56346db 100644
--- a/tests/app/app/src/android/app/stubs/LocalForegroundServiceLocation.java
+++ b/tests/app/app/src/android/app/stubs/LocalForegroundServiceLocation.java
@@ -63,7 +63,7 @@
.setContentTitle(getNotificationTitle(mNotificationId))
.setSmallIcon(R.drawable.black)
.build();
- startForeground(mNotificationId, notification, type);
+ startForeground(mNotificationId, notification);
//assertEquals(type, getForegroundServiceType());
break;
default:
diff --git a/tests/app/app/src/android/app/stubs/SendBubbleActivity.java b/tests/app/app/src/android/app/stubs/SendBubbleActivity.java
index e2552bc..223f885 100644
--- a/tests/app/app/src/android/app/stubs/SendBubbleActivity.java
+++ b/tests/app/app/src/android/app/stubs/SendBubbleActivity.java
@@ -28,7 +28,6 @@
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.SystemClock;
-import android.util.Log;
/**
* Used by NotificationManagerTest for testing policy around bubbles, this activity is able to
@@ -59,7 +58,7 @@
* Sends a notification that has bubble metadata but the rest of the notification isn't
* configured correctly so the system won't allow it to bubble.
*/
- public void sendInvalidBubble(int i, boolean autoExpand) {
+ public void sendInvalidBubble(boolean autoExpand) {
Context context = getApplicationContext();
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, new Intent(), 0);
@@ -75,7 +74,6 @@
NotificationManager noMan = (NotificationManager) context.getSystemService(
Context.NOTIFICATION_SERVICE);
noMan.notify(BUBBLE_NOTIF_ID, n);
- Log.d(TAG, "posting bubble: " + n + ", " + i);
}
/** Sends a notification that is properly configured to bubble. */
diff --git a/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java
index 277ec3a..61b5cbc 100644
--- a/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -80,6 +80,12 @@
private static final String PACKAGE_NAME_APP1 = "com.android.app1";
+ private static final String MCC_TO_UPDATE = "987";
+ private static final String MNC_TO_UPDATE = "654";
+ private static final String SHELL_COMMAND_GET_CONFIG = "am get-config";
+ private static final String SHELL_COMMAND_RESULT_CONFIG_NAME_MCC = "mcc";
+ private static final String SHELL_COMMAND_RESULT_CONFIG_NAME_MNC = "mnc";
+
// Return states of the ActivityReceiverFilter.
public static final int RESULT_PASS = 1;
public static final int RESULT_FAIL = 2;
@@ -333,6 +339,11 @@
Log.d(TAG, "executed[" + cmd + "]; output[" + output.trim() + "]");
}
+ private String executeShellCommand(String cmd) throws IOException {
+ final UiDevice uiDevice = UiDevice.getInstance(mInstrumentation);
+ return uiDevice.executeShellCommand(cmd).trim();
+ }
+
private void setForcedAppStandby(String packageName, boolean enabled) throws IOException {
final StringBuilder cmdBuilder = new StringBuilder("appops set ")
.append(packageName)
@@ -426,6 +437,62 @@
}
/**
+ * Due to the corresponding API is hidden in R and will be public in S, this test
+ * is commented and will be un-commented in Android S.
+ *
+ public void testUpdateMccMncConfiguration() throws Exception {
+ // Store the original mcc mnc to set back
+ String[] mccMncConfigOriginal = new String[2];
+ // Store other configs to check they won't be affected
+ Set<String> otherConfigsOriginal = new HashSet<String>();
+ getMccMncConfigsAndOthers(mccMncConfigOriginal, otherConfigsOriginal);
+
+ String[] mccMncConfigToUpdate = new String[] {MCC_TO_UPDATE, MNC_TO_UPDATE};
+ boolean success = ShellIdentityUtils.invokeMethodWithShellPermissions(mActivityManager,
+ (am) -> am.updateMccMncConfiguration(mccMncConfigToUpdate[0],
+ mccMncConfigToUpdate[1]));
+
+ if (success) {
+ String[] mccMncConfigUpdated = new String[2];
+ Set<String> otherConfigsUpdated = new HashSet<String>();
+ getMccMncConfigsAndOthers(mccMncConfigUpdated, otherConfigsUpdated);
+ // Check the mcc mnc are updated as expected
+ assertTrue(Arrays.equals(mccMncConfigToUpdate, mccMncConfigUpdated));
+ // Check other configs are not changed
+ assertTrue(otherConfigsOriginal.equals(otherConfigsUpdated));
+ }
+
+ // Set mcc mnc configs back in the end of the test
+ ShellIdentityUtils.invokeMethodWithShellPermissions(mActivityManager,
+ (am) -> am.updateMccMncConfiguration(mccMncConfigOriginal[0],
+ mccMncConfigOriginal[1]));
+ }
+ */
+
+ /**
+ * Due to the corresponding API is hidden in R and will be public in S, this method
+ * for test "testUpdateMccMncConfiguration" is commented and will be un-commented in
+ * Android S.
+ *
+ private void getMccMncConfigsAndOthers(String[] mccMncConfigs, Set<String> otherConfigs)
+ throws Exception {
+ String[] configs = SystemUtil.runShellCommand(
+ mInstrumentation, SHELL_COMMAND_GET_CONFIG).split(" |\\-");
+ for (String config : configs) {
+ if (config.startsWith(SHELL_COMMAND_RESULT_CONFIG_NAME_MCC)) {
+ mccMncConfigs[0] = config.substring(
+ SHELL_COMMAND_RESULT_CONFIG_NAME_MCC.length());
+ } else if (config.startsWith(SHELL_COMMAND_RESULT_CONFIG_NAME_MNC)) {
+ mccMncConfigs[1] = config.substring(
+ SHELL_COMMAND_RESULT_CONFIG_NAME_MNC.length());
+ } else {
+ otherConfigs.add(config);
+ }
+ }
+ }
+ */
+
+ /**
* Simple test for {@link ActivityManager#isUserAMonkey()} - verifies its false.
*
* TODO: test positive case
@@ -737,7 +804,11 @@
ActivityReceiverFilter appStartedReceiver = new ActivityReceiverFilter(
ACTIVITY_LAUNCHED_ACTION);
+ boolean disabled = "0".equals(executeShellCommand("cmd deviceidle enabled light"));
try {
+ if (disabled) {
+ executeAndLogShellCommand("cmd deviceidle enable light");
+ }
intent = new Intent(Intent.ACTION_MAIN);
intent.setClassName(SIMPLE_PACKAGE_NAME, SIMPLE_PACKAGE_NAME + SIMPLE_ACTIVITY);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -810,6 +881,9 @@
toggleScreenOn(true);
appStartedReceiver.close();
+ if (disabled) {
+ executeAndLogShellCommand("cmd deviceidle disable light");
+ }
SystemUtil.runWithShellPermissionIdentity(() -> {
mActivityManager.forceStopPackage(SIMPLE_PACKAGE_NAME);
});
diff --git a/tests/app/src/android/app/cts/NotificationChannelTest.java b/tests/app/src/android/app/cts/NotificationChannelTest.java
index 184f678..5727237 100644
--- a/tests/app/src/android/app/cts/NotificationChannelTest.java
+++ b/tests/app/src/android/app/cts/NotificationChannelTest.java
@@ -28,7 +28,6 @@
import android.os.Parcel;
import android.provider.Settings;
import android.test.AndroidTestCase;
-import android.text.TextUtils;
public class NotificationChannelTest extends AndroidTestCase {
@@ -83,7 +82,7 @@
channel.setDeleted(true);
channel.setFgServiceShown(true);
channel.setVibrationPattern(new long[] {299, 4562});
- channel.setBlockableSystem(true);
+ channel.setBlockable(true);
channel.setConversationId("parent_channel", "conversation 1");
channel.setImportantConversation(true);
Parcel parcel = Parcel.obtain();
@@ -190,8 +189,8 @@
public void testIsBlockableSystem() {
NotificationChannel channel =
new NotificationChannel("1", "one", IMPORTANCE_DEFAULT);
- channel.setBlockableSystem(true);
- assertTrue(channel.isBlockableSystem());
+ channel.setBlockable(true);
+ assertTrue(channel.isBlockable());
}
public void testIsImportanceLockedByOEM() {
@@ -203,9 +202,9 @@
public void testSystemBlockable() {
NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
- assertEquals(false, channel.isBlockableSystem());
- channel.setBlockableSystem(true);
- assertEquals(true, channel.isBlockableSystem());
+ assertEquals(false, channel.isBlockable());
+ channel.setBlockable(true);
+ assertEquals(true, channel.isBlockable());
}
public void testOriginalImportance() {
@@ -225,4 +224,11 @@
channel.setImportantConversation(true);
assertTrue(channel.isImportantConversation());
}
+
+ public void testHasUserSetSound() {
+ NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
+ channel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
+
+ assertTrue(channel.hasUserSetSound());
+ }
}
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index 73e02c2..10934dd 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -117,6 +117,7 @@
import androidx.test.InstrumentationRegistry;
+import com.android.compatibility.common.util.FeatureUtil;
import com.android.compatibility.common.util.SystemUtil;
import junit.framework.Assert;
@@ -450,8 +451,21 @@
}
}
+ private void setUpNotifListener() {
+ try {
+ toggleListenerAccess(TestNotificationListener.getId(),
+ InstrumentationRegistry.getInstrumentation(), true);
+ mListener = TestNotificationListener.getInstance();
+ mListener.resetData();
+ assertNotNull(mListener);
+ } catch (IOException e) {
+ }
+ }
+
private void sendAndVerifyBubble(final int id, Notification.Builder builder,
Notification.BubbleMetadata data, boolean shouldBeBubble) {
+ setUpNotifListener();
+
final Intent intent = new Intent(mContext, BubbledActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP
@@ -460,8 +474,7 @@
final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
if (data == null) {
- data = new Notification.BubbleMetadata.Builder()
- .createIntentBubble(pendingIntent,
+ data = new Notification.BubbleMetadata.Builder(pendingIntent,
Icon.createWithResource(mContext, R.drawable.black))
.build();
}
@@ -478,50 +491,48 @@
Notification notif = builder.build();
mNotificationManager.notify(id, notif);
- if (!checkNotificationExistence(id, /*shouldExist=*/ true, shouldBeBubble)) {
- fail("couldn't find posted notification bubble with id=" + id);
- }
+ verifyNotificationBubbleState(id, shouldBeBubble);
}
- private StatusBarNotification getNotification(int id) {
- // notification is a bit asynchronous so it may take a few ms to appear in
- // getActiveNotifications()
- // we will check for it for up to 300ms before giving up
- for (int tries = 3; tries-- > 0;) {
- // Need reset flag.
- final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
- for (StatusBarNotification sbn : sbns) {
- if (sbn.getId() == id) {
- return sbn;
+ /**
+ * Make sure {@link #setUpNotifListener()} is called prior to sending the notif and verifying
+ * in this method.
+ */
+ private void verifyNotificationBubbleState(int id, boolean shouldBeBubble) {
+ try {
+ // FLAG_BUBBLE relies on notification being posted, wait for notification listener
+ Thread.sleep(500);
+ } catch (InterruptedException ex) {
+ }
+
+ for (StatusBarNotification sbn : mListener.mPosted) {
+ if (sbn.getId() == id) {
+ boolean isBubble = (sbn.getNotification().flags & FLAG_BUBBLE) != 0;
+ if (isBubble != shouldBeBubble) {
+ final String failure = shouldBeBubble
+ ? "Notification with id= " + id + " wasn't a bubble"
+ : "Notification with id= " + id + " was a bubble and shouldn't be";
+ fail(failure);
+ } else {
+ // pass
+ return;
}
}
- try {
- Thread.sleep(100);
- } catch (InterruptedException ex) {
- // pass
- }
}
- return null;
+ fail("Couldn't find posted notification with id= " + id);
}
private boolean checkNotificationExistence(int id, boolean shouldExist) {
- return checkNotificationExistence(id, shouldExist, false /* shouldBeBubble */);
- }
-
- private boolean checkNotificationExistence(int id, boolean shouldExist,
- boolean shouldBeBubble) {
// notification is a bit asynchronous so it may take a few ms to appear in
// getActiveNotifications()
// we will check for it for up to 300ms before giving up
boolean found = false;
- boolean isBubble = false;
for (int tries = 3; tries--> 0;) {
// Need reset flag.
found = false;
final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
for (StatusBarNotification sbn : sbns) {
- isBubble = (sbn.getNotification().flags & FLAG_BUBBLE) != 0;
- Log.d(TAG, "Found " + sbn.getKey() + " Bubble? " + isBubble);
+ Log.d(TAG, "Found " + sbn.getKey());
if (sbn.getId() == id) {
found = true;
break;
@@ -534,7 +545,7 @@
// pass
}
}
- return (found == shouldExist) && (isBubble == shouldBeBubble);
+ return found == shouldExist;
}
private void assertNotificationCount(int expectedCount) {
@@ -1371,7 +1382,8 @@
}
public void testCanBubble_ranking() throws Exception {
- if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+ if ((mActivityManager.isLowRamDevice() && !FeatureUtil.isWatch())
+ || FeatureUtil.isAutomotive()) {
return;
}
@@ -2769,8 +2781,12 @@
badNumberString);
}
- public void testNotificationManagerBubblePolicy_flagForMessage_failsNoRemoteInput()
+ public void testNotificationManagerBubblePolicy_flagForMessage_passesNoRemoteInput()
throws InterruptedException {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
// turn on bubbles globally
toggleBubbleSetting(true);
@@ -2787,11 +2803,17 @@
SystemClock.currentThreadTimeMillis(), person)
)
.setSmallIcon(android.R.drawable.sym_def_app_icon);
- sendAndVerifyBubble(1, nb, null /* use default metadata */, false);
+ boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
+ sendAndVerifyBubble(1, nb, null /* use default metadata */, shouldBeBubble);
}
public void testNotificationManagerBubblePolicy_flagForMessage_succeeds()
throws InterruptedException {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
+
// turn on bubbles globally
toggleBubbleSetting(true);
@@ -2825,39 +2847,45 @@
public void testNotificationManagerBubblePolicy_flagForMessagingWithService_fails()
throws Exception {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
Intent serviceIntent = new Intent(mContext, BubblesTestService.class);
serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_MESSAGING);
try {
// turn on bubbles globally
toggleBubbleSetting(true);
+
+ setUpNotifListener();
+
mContext.startService(serviceIntent);
- if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
- true /* shouldExist */, false /* shouldBeBubble */)) {
- fail("found bubble notification id=" + BUBBLE_NOTIF_ID
- + " when it should just be a notification");
- }
+ verifyNotificationBubbleState(BUBBLE_NOTIF_ID, false /* shouldBeBubble */);
} finally {
mContext.stopService(serviceIntent);
}
}
public void testNotificationManagerBubblePolicy_flagForPhonecall() throws InterruptedException {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
Intent serviceIntent = new Intent(mContext, BubblesTestService.class);
serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_SUCCESS);
try {
// turn on bubbles globally
toggleBubbleSetting(true);
+
+ setUpNotifListener();
+
mContext.startService(serviceIntent);
boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
- if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
- true /* shouldExist */, shouldBeBubble)) {
- fail("couldn't find posted notification bubble with id=" + BUBBLE_NOTIF_ID);
- }
-
+ verifyNotificationBubbleState(BUBBLE_NOTIF_ID, shouldBeBubble);
} finally {
mContext.stopService(serviceIntent);
}
@@ -2865,19 +2893,22 @@
public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoPerson()
throws InterruptedException {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
Intent serviceIntent = new Intent(mContext, BubblesTestService.class);
serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_NO_PERSON);
try {
// turn on bubbles globally
toggleBubbleSetting(true);
+
+ setUpNotifListener();
+
mContext.startService(serviceIntent);
- if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
- true /* shouldExist */, false /* shouldBeBubble */)) {
- fail("couldn't find posted notification with id=" + BUBBLE_NOTIF_ID
- + " or it was a bubble when it shouldn't be");
- }
+ verifyNotificationBubbleState(BUBBLE_NOTIF_ID, false /* shouldBeBubble */);
} finally {
mContext.stopService(serviceIntent);
}
@@ -2885,6 +2916,10 @@
public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoForeground()
throws InterruptedException {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
// turn on bubbles globally
toggleBubbleSetting(true);
@@ -2901,19 +2936,22 @@
public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoCategory()
throws InterruptedException {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
Intent serviceIntent = new Intent(mContext, BubblesTestService.class);
serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_NO_CATEGORY);
try {
// turn on bubbles globally
toggleBubbleSetting(true);
+
+ setUpNotifListener();
+
mContext.startService(serviceIntent);
- if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
- true /* shouldExist */, false /* shouldBeBubble */)) {
- fail("couldn't find posted notification with id=" + BUBBLE_NOTIF_ID
- + " or it was a bubble when it shouldn't be");
- }
+ verifyNotificationBubbleState(BUBBLE_NOTIF_ID, false /* shouldBeBubble */);
} finally {
mContext.stopService(serviceIntent);
}
@@ -2921,50 +2959,62 @@
public void testNotificationManagerBubblePolicy_flagForPhonecallFailsNoMetadata()
throws InterruptedException {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
Intent serviceIntent = new Intent(mContext, BubblesTestService.class);
serviceIntent.putExtra(EXTRA_TEST_CASE, TEST_NO_BUBBLE_METADATA);
try {
// turn on bubbles globally
toggleBubbleSetting(true);
+
+ setUpNotifListener();
+
mContext.startService(serviceIntent);
- if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
- true /* shouldExist */, false /* shouldBeBubble */)) {
- fail("couldn't find posted notification with id=" + BUBBLE_NOTIF_ID
- + " or it was a bubble when it shouldn't be");
- }
+ verifyNotificationBubbleState(BUBBLE_NOTIF_ID, false /* shouldBeBubble */);
} finally {
mContext.stopService(serviceIntent);
}
}
public void testNotificationManagerBubblePolicy_flagForAppForeground_fails() throws Exception {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
try {
// turn on bubbles globally
toggleBubbleSetting(true);
+ setUpNotifListener();
+
// Start & get the activity
SendBubbleActivity a = startSendBubbleActivity();
// Send a bubble that doesn't fulfill policy from foreground
- a.sendInvalidBubble(4000, false /* autoExpand */);
+ a.sendInvalidBubble(false /* autoExpand */);
// Just because app is foreground, doesn't mean they get to bubble
- if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
- true /* shouldExist */, false /* shouldBeBubble */)) {
- fail("couldn't find posted notification bubble with id=" + BUBBLE_NOTIF_ID);
- }
+ verifyNotificationBubbleState(BUBBLE_NOTIF_ID, false /* shouldBeBubble */);
} finally {
cleanupSendBubbleActivity();
}
}
public void testNotificationManagerBubble_ensureFlaggedDocumentLaunchMode() throws Exception {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
try {
// turn on bubbles globally
toggleBubbleSetting(true);
+ setUpNotifListener();
+
// make ourselves foreground so we can auto-expand the bubble & check the intent flags
SendBubbleActivity a = startSendBubbleActivity();
@@ -2979,10 +3029,7 @@
a.sendBubble(true /* autoExpand */, false /* suppressNotif */);
boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
- if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
- true /* shouldExist */, shouldBeBubble)) {
- fail("couldn't find posted notification bubble with id=" + BUBBLE_NOTIF_ID);
- }
+ verifyNotificationBubbleState(BUBBLE_NOTIF_ID, shouldBeBubble);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -2996,6 +3043,10 @@
public void testNotificationManagerBubblePolicy_flagForShortcut_manifest_fails()
throws Exception {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
// turn on bubbles globally
toggleBubbleSetting(true);
@@ -3025,15 +3076,18 @@
.setSmallIcon(android.R.drawable.sym_def_app_icon);
// BubbleMetadata with manifest shortcut
- Notification.BubbleMetadata data = new Notification.BubbleMetadata.Builder()
- .createShortcutBubble(BUBBLE_SHORTCUT_ID_MANIFEST)
- .build();
+ Notification.BubbleMetadata data =
+ new Notification.BubbleMetadata.Builder(BUBBLE_SHORTCUT_ID_MANIFEST).build();
sendAndVerifyBubble(1, nb, data, false /* shouldBeBubble */);
}
public void testNotificationManagerBubblePolicy_flagForShortcut_dynamic_succeeds()
throws Exception {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
ShortcutManager scmanager = mContext.getSystemService(ShortcutManager.class);
@@ -3078,13 +3132,12 @@
.setSmallIcon(android.R.drawable.sym_def_app_icon);
// BubbleMetadata with our dynamic shortcut ic
- Notification.BubbleMetadata data = new Notification.BubbleMetadata.Builder()
- .createShortcutBubble(BUBBLE_SHORTCUT_ID_DYNAMIC)
- .build();
+ Notification.BubbleMetadata data =
+ new Notification.BubbleMetadata.Builder(BUBBLE_SHORTCUT_ID_DYNAMIC)
+ .build();
boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
sendAndVerifyBubble(1, nb, data, shouldBeBubble);
-
} finally {
// remove the shortcut
scmanager.removeAllDynamicShortcuts();
@@ -3093,6 +3146,10 @@
public void testNotificationManagerBubblePolicy_flagForShortcut_fails_invalidShortcut()
throws Exception {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
// turn on bubbles globally
toggleBubbleSetting(true);
@@ -3122,22 +3179,26 @@
.setSmallIcon(android.R.drawable.sym_def_app_icon);
// BubbleMetadata with shortcut that doesn't exist
- Notification.BubbleMetadata data = new Notification.BubbleMetadata.Builder()
- .createShortcutBubble("shortcutDoesntExist")
- .build();
+ Notification.BubbleMetadata data =
+ new Notification.BubbleMetadata.Builder("shortcutDoesntExist")
+ .build();
sendAndVerifyBubble(1, nb, data, false);
}
public void testNotificationManagerBubblePolicy_flagForShortcut_fails_invalidNotif()
throws Exception {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
// turn on bubbles globally
toggleBubbleSetting(true);
// BubbleMetadata with manifest shortcut
- Notification.BubbleMetadata data = new Notification.BubbleMetadata.Builder()
- .createShortcutBubble(BUBBLE_SHORTCUT_ID_MANIFEST)
- .build();
+ Notification.BubbleMetadata data =
+ new Notification.BubbleMetadata.Builder(BUBBLE_SHORTCUT_ID_MANIFEST)
+ .build();
sendAndVerifyBubble(1, null /* use default notif builder */, data,
false /* shouldBeBubble */);
@@ -3145,6 +3206,10 @@
public void testNotificationManagerBubblePolicy_noFlag_shortcutRemoved()
throws Exception {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
ShortcutManager scmanager = mContext.getSystemService(ShortcutManager.class);
@@ -3152,6 +3217,8 @@
// turn on bubbles globally
toggleBubbleSetting(true);
+ setUpNotifListener();
+
// Make dynamic shortcut
Intent shortcutIntent = new Intent(mContext, SendBubbleActivity.class);
shortcutIntent.setAction(Intent.ACTION_VIEW);
@@ -3188,20 +3255,21 @@
.setActions(replyAction)
.setSmallIcon(android.R.drawable.sym_def_app_icon);
- // BubbleMetadata with our dynamic shortcut ic
- Notification.BubbleMetadata data = new Notification.BubbleMetadata.Builder()
- .createShortcutBubble(BUBBLE_SHORTCUT_ID_DYNAMIC)
- .build();
+ // BubbleMetadata with our dynamic shortcut
+ Notification.BubbleMetadata data =
+ new Notification.BubbleMetadata.Builder(BUBBLE_SHORTCUT_ID_DYNAMIC)
+ .build();
boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
sendAndVerifyBubble(1, nb, data, shouldBeBubble);
+ mListener.resetData();
+
// Now lets delete the shortcut and make sure the notif has been updated to not
// be a bubble.
scmanager.removeAllDynamicShortcuts();
- checkNotificationExistence(1, true /* should exist */, false /* should be bubble */);
-
+ verifyNotificationBubbleState(1, false /* should be bubble */);
} finally {
// remove the shortcut
scmanager.removeAllDynamicShortcuts();
@@ -3209,18 +3277,26 @@
}
public void testNotificationManagerBubbleNotificationSuppression() throws Exception {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
try {
// turn on bubbles globally
toggleBubbleSetting(true);
+ setUpNotifListener();
+
// make ourselves foreground so we can specify suppress notification flag
SendBubbleActivity a = startSendBubbleActivity();
// send the bubble with notification suppressed
a.sendBubble(false /* autoExpand */, true /* suppressNotif */);
+ boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
+ verifyNotificationBubbleState(BUBBLE_NOTIF_ID, shouldBeBubble);
// check for the notification
- StatusBarNotification sbnSuppressed = getNotification(BUBBLE_NOTIF_ID);
+ StatusBarNotification sbnSuppressed = mListener.mPosted.get(0);
assertNotNull(sbnSuppressed);
// check for suppression state
Notification.BubbleMetadata metadata =
@@ -3228,11 +3304,14 @@
assertNotNull(metadata);
assertTrue(metadata.isNotificationSuppressed());
+ mListener.resetData();
+
// send the bubble with notification NOT suppressed
a.sendBubble(false /* autoExpand */, false /* suppressNotif */);
+ verifyNotificationBubbleState(BUBBLE_NOTIF_ID, shouldBeBubble);
// check for the notification
- StatusBarNotification sbnNotSuppressed = getNotification(BUBBLE_NOTIF_ID);
+ StatusBarNotification sbnNotSuppressed = mListener.mPosted.get(0);
assertNotNull(sbnNotSuppressed);
// check for suppression state
metadata = sbnNotSuppressed.getNotification().getBubbleMetadata();
@@ -3243,6 +3322,8 @@
// turn off bubbles globally
toggleBubbleSetting(false);
+
+ mListener.resetData();
}
}
diff --git a/tests/app/src/android/app/cts/NotificationTest.java b/tests/app/src/android/app/cts/NotificationTest.java
index 439f3a9..b9f8784 100644
--- a/tests/app/src/android/app/cts/NotificationTest.java
+++ b/tests/app/src/android/app/cts/NotificationTest.java
@@ -625,15 +625,14 @@
PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
Icon icon = Icon.createWithResource(mContext, 1);
Notification.BubbleMetadata.Builder metadataBuilder =
- new Notification.BubbleMetadata.Builder()
+ new Notification.BubbleMetadata.Builder(bubbleIntent, icon)
.setDesiredHeight(BUBBLE_HEIGHT)
- .createIntentBubble(bubbleIntent, icon)
.setDeleteIntent(deleteIntent);
Notification.BubbleMetadata data = metadataBuilder.build();
assertEquals(BUBBLE_HEIGHT, data.getDesiredHeight());
- assertEquals(icon, data.getBubbleIcon());
- assertEquals(bubbleIntent, data.getBubbleIntent());
+ assertEquals(icon, data.getIcon());
+ assertEquals(bubbleIntent, data.getIntent());
assertEquals(deleteIntent, data.getDeleteIntent());
assertFalse(data.isNotificationSuppressed());
assertFalse(data.getAutoExpandBubble());
@@ -644,18 +643,17 @@
PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
Icon icon = Icon.createWithResource(mContext, 1);
Notification.BubbleMetadata metadata =
- new Notification.BubbleMetadata.Builder()
+ new Notification.BubbleMetadata.Builder(bubbleIntent, icon)
.setDesiredHeight(BUBBLE_HEIGHT)
.setAutoExpandBubble(true)
.setSuppressNotification(true)
- .createIntentBubble(bubbleIntent, icon)
.setDeleteIntent(deleteIntent)
.build();
writeAndReadParcelable(metadata);
assertEquals(BUBBLE_HEIGHT, metadata.getDesiredHeight());
- assertEquals(icon, metadata.getBubbleIcon());
- assertEquals(bubbleIntent, metadata.getBubbleIntent());
+ assertEquals(icon, metadata.getIcon());
+ assertEquals(bubbleIntent, metadata.getIntent());
assertEquals(deleteIntent, metadata.getDeleteIntent());
assertTrue(metadata.getAutoExpandBubble());
assertTrue(metadata.isNotificationSuppressed());
@@ -664,9 +662,8 @@
public void testBubbleMetadataBuilder_shortcutId() {
PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
Notification.BubbleMetadata.Builder metadataBuilder =
- new Notification.BubbleMetadata.Builder()
+ new Notification.BubbleMetadata.Builder(BUBBLE_SHORTCUT_ID)
.setDesiredHeight(BUBBLE_HEIGHT)
- .createShortcutBubble(BUBBLE_SHORTCUT_ID)
.setDeleteIntent(deleteIntent);
Notification.BubbleMetadata data = metadataBuilder.build();
@@ -681,11 +678,10 @@
PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
Notification.BubbleMetadata metadata =
- new Notification.BubbleMetadata.Builder()
+ new Notification.BubbleMetadata.Builder(BUBBLE_SHORTCUT_ID)
.setDesiredHeight(BUBBLE_HEIGHT)
.setAutoExpandBubble(true)
.setSuppressNotification(true)
- .createShortcutBubble(BUBBLE_SHORTCUT_ID)
.setDeleteIntent(deleteIntent)
.build();
@@ -701,73 +697,67 @@
PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
Icon icon = Icon.createWithResource(mContext, 1);
Notification.BubbleMetadata metadata =
- new Notification.BubbleMetadata.Builder()
+ new Notification.BubbleMetadata.Builder(bubbleIntent, icon)
.setDesiredHeightResId(BUBBLE_HEIGHT_RESID)
- .createIntentBubble(bubbleIntent, icon)
.build();
writeAndReadParcelable(metadata);
assertEquals(BUBBLE_HEIGHT_RESID, metadata.getDesiredHeightResId());
- assertEquals(icon, metadata.getBubbleIcon());
- assertEquals(bubbleIntent, metadata.getBubbleIntent());
+ assertEquals(icon, metadata.getIcon());
+ assertEquals(bubbleIntent, metadata.getIntent());
assertFalse(metadata.getAutoExpandBubble());
assertFalse(metadata.isNotificationSuppressed());
}
public void testBubbleMetadataBuilder_throwForNoIntentNoShortcut() {
- Icon icon = Icon.createWithResource(mContext, 1);
Notification.BubbleMetadata.Builder metadataBuilder =
- new Notification.BubbleMetadata.Builder()
- .setDesiredHeight(BUBBLE_HEIGHT);
+ new Notification.BubbleMetadata.Builder();
try {
metadataBuilder.build();
- fail("Should have thrown IllegalArgumentException, no pending intent or shortcutId");
- } catch (IllegalStateException e) {
+ fail("Should have thrown exception, no pending intent or shortcutId");
+ } catch (NullPointerException e) {
// expected
}
}
public void testBubbleMetadataBuilder_noThrowWithShortcut() {
Notification.BubbleMetadata.Builder metadataBuilder =
- new Notification.BubbleMetadata.Builder()
- .setDesiredHeight(BUBBLE_HEIGHT)
- .createShortcutBubble(BUBBLE_SHORTCUT_ID);
+ new Notification.BubbleMetadata.Builder(BUBBLE_SHORTCUT_ID)
+ .setDesiredHeight(BUBBLE_HEIGHT);
Notification.BubbleMetadata metadata = metadataBuilder.build();
assertNotNull(metadata.getShortcutId());
- assertNull(metadata.getBubbleIcon());
- assertNull(metadata.getBubbleIntent());
+ assertNull(metadata.getIcon());
+ assertNull(metadata.getIntent());
}
- public void testBubbleMetadataBuilder_shortcutOverwritesIconIntent() {
+ public void testBubbleMetadataBuilder_shortcutBuilder_throwsForSetIntent() {
PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
- Icon icon = Icon.createWithResource(mContext, 1);
- Notification.BubbleMetadata metadata =
- new Notification.BubbleMetadata.Builder()
- .setDesiredHeightResId(BUBBLE_HEIGHT_RESID)
- .createIntentBubble(bubbleIntent, icon)
- .createShortcutBubble(BUBBLE_SHORTCUT_ID)
- .build();
- assertNotNull(metadata.getShortcutId());
- assertNull(metadata.getBubbleIcon());
- assertNull(metadata.getBubbleIntent());
+ try {
+ Notification.BubbleMetadata.Builder metadataBuilder =
+ new Notification.BubbleMetadata.Builder(BUBBLE_SHORTCUT_ID)
+ .setDesiredHeightResId(BUBBLE_HEIGHT_RESID)
+ .setIntent(bubbleIntent);
+ fail("Should have thrown exception, can't set intent on shortcut builder");
+ } catch (Exception e) {
+ // expected
+ }
}
- public void testBubbleMetadataBuilder_intentIconOverwritesShortcut() {
- PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
- Icon icon = Icon.createWithResource(mContext, 1);
- Notification.BubbleMetadata.Builder metadataBuilder =
- new Notification.BubbleMetadata.Builder()
- .setDesiredHeightResId(BUBBLE_HEIGHT_RESID)
- .createShortcutBubble(BUBBLE_SHORTCUT_ID)
- .createIntentBubble(bubbleIntent, icon);
- Notification.BubbleMetadata metadata = metadataBuilder.build();
- assertNull(metadata.getShortcutId());
- assertNotNull(metadata.getBubbleIcon());
- assertNotNull(metadata.getBubbleIntent());
+ public void testBubbleMetadataBuilder_shortcutBuilder_throwsForSetIcon() {
+ try {
+ Icon icon = Icon.createWithResource(mContext, 1);
+ Notification.BubbleMetadata.Builder metadataBuilder =
+ new Notification.BubbleMetadata.Builder(BUBBLE_SHORTCUT_ID)
+ .setDesiredHeightResId(BUBBLE_HEIGHT_RESID)
+ .setIcon(icon);
+ fail("Should have thrown exception, can't set icon on shortcut builder");
+ } catch (Exception e) {
+ // expected
+ }
}
public void testBubbleMetadataBuilder_notifBubbleShortcutIds_match_noThrow() {
- Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder()
- .createShortcutBubble(BUBBLE_SHORTCUT_ID).build();
+ Notification.BubbleMetadata metadata =
+ new Notification.BubbleMetadata.Builder(BUBBLE_SHORTCUT_ID).build();
mNotification = new Notification.Builder(mContext, CHANNEL.getId())
.setSmallIcon(1)
@@ -781,8 +771,8 @@
}
public void testBubbleMetadataBuilder_notifBubbleShortcutIds_different_throw() {
- Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder()
- .createShortcutBubble(BUBBLE_SHORTCUT_ID).build();
+ Notification.BubbleMetadata metadata =
+ new Notification.BubbleMetadata.Builder(BUBBLE_SHORTCUT_ID).build();
Notification.Builder nb = new Notification.Builder(mContext, CHANNEL.getId())
.setSmallIcon(1)
@@ -806,11 +796,10 @@
PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
Notification.BubbleMetadata.Builder metadataBuilder =
- new Notification.BubbleMetadata.Builder()
- .createIntentBubble(bubbleIntent, icon);
+ new Notification.BubbleMetadata.Builder(bubbleIntent, icon);
Notification.BubbleMetadata metadata = metadataBuilder.build();
- assertNotNull(metadata.getBubbleIcon());
- assertEquals(TYPE_ADAPTIVE_BITMAP, metadata.getBubbleIcon().getType());
+ assertNotNull(metadata.getIcon());
+ assertEquals(TYPE_ADAPTIVE_BITMAP, metadata.getIcon().getType());
}
public void testBubbleMetadataBuilder_noThrowForNonBitmapIcon() {
@@ -818,11 +807,10 @@
PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
Notification.BubbleMetadata.Builder metadataBuilder =
- new Notification.BubbleMetadata.Builder()
- .createIntentBubble(bubbleIntent, icon);
+ new Notification.BubbleMetadata.Builder(bubbleIntent, icon);
Notification.BubbleMetadata metadata = metadataBuilder.build();
- assertNotNull(metadata.getBubbleIcon());
- assertEquals(TYPE_RESOURCE, metadata.getBubbleIcon().getType());
+ assertNotNull(metadata.getIcon());
+ assertEquals(TYPE_RESOURCE, metadata.getIcon().getType());
}
public void testBubbleMetadataBuilder_replaceHeightRes() {
@@ -830,10 +818,9 @@
PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
Icon icon = Icon.createWithResource(mContext, 1);
Notification.BubbleMetadata.Builder metadataBuilder =
- new Notification.BubbleMetadata.Builder()
+ new Notification.BubbleMetadata.Builder(bubbleIntent, icon)
.setDesiredHeight(BUBBLE_HEIGHT)
.setDesiredHeightResId(BUBBLE_HEIGHT_RESID)
- .createIntentBubble(bubbleIntent, icon)
.setDeleteIntent(deleteIntent);
Notification.BubbleMetadata data = metadataBuilder.build();
@@ -848,10 +835,9 @@
PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
Icon icon = Icon.createWithResource(mContext, 1);
Notification.BubbleMetadata.Builder metadataBuilder =
- new Notification.BubbleMetadata.Builder()
+ new Notification.BubbleMetadata.Builder(bubbleIntent, icon)
.setDesiredHeightResId(BUBBLE_HEIGHT_RESID)
.setDesiredHeight(BUBBLE_HEIGHT)
- .createIntentBubble(bubbleIntent, icon)
.setDeleteIntent(deleteIntent);
Notification.BubbleMetadata data = metadataBuilder.build();
@@ -923,9 +909,9 @@
private Notification.BubbleMetadata makeBubbleMetadata() {
PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
- return new Notification.BubbleMetadata.Builder()
- .createIntentBubble(bubbleIntent, Icon.createWithResource(mContext, 1))
- .setDesiredHeight(BUBBLE_HEIGHT)
- .build();
+ return new Notification.BubbleMetadata.Builder(bubbleIntent,
+ Icon.createWithResource(mContext, 1))
+ .setDesiredHeight(BUBBLE_HEIGHT)
+ .build();
}
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
index cd099d7..aa751a2 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
@@ -596,7 +596,7 @@
final Dataset.Builder builder = mPresentation != null
? mInlinePresentation == null
? new Dataset.Builder(mPresentation)
- : new Dataset.Builder(mPresentation, mInlinePresentation)
+ : new Dataset.Builder(mPresentation).setInlinePresentation(mInlinePresentation)
: mInlinePresentation == null
? new Dataset.Builder()
: new Dataset.Builder(mInlinePresentation);
@@ -631,7 +631,7 @@
}
} else {
if (inlinePresentation != null) {
- builder.setInlinePresentation(autofillId, value,
+ builder.setFieldInlinePresentation(autofillId, value,
filter != null ? filter.second : null, inlinePresentation);
} else {
if (filter == null) {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java
index c9434cb..43c8e06 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatasetTest.java
@@ -58,22 +58,29 @@
@Test
public void testBuilder_nullPresentation() {
assertThrows(NullPointerException.class, () -> new Dataset.Builder((RemoteViews) null));
- assertThrows(NullPointerException.class, () -> new Dataset.Builder(null,
- mInlinePresentation));
}
@Test
public void testBuilder_nullInlinePresentation() {
assertThrows(NullPointerException.class,
() -> new Dataset.Builder((InlinePresentation) null));
- assertThrows(NullPointerException.class, () -> new Dataset.Builder(mPresentation, null));
}
@Test
public void testBuilder_validPresentations() {
assertThat(new Dataset.Builder(mPresentation)).isNotNull();
assertThat(new Dataset.Builder(mInlinePresentation)).isNotNull();
- assertThat(new Dataset.Builder(mPresentation, mInlinePresentation)).isNotNull();
+ }
+
+ @Test
+ public void testBuilder_setNullInlinePresentation() {
+ final Dataset.Builder builder = new Dataset.Builder(mPresentation);
+ assertThrows(NullPointerException.class, () -> builder.setInlinePresentation(null));
+ }
+
+ @Test
+ public void testBuilder_setInlinePresentation() {
+ assertThat(new Dataset.Builder().setInlinePresentation(mInlinePresentation)).isNotNull();
}
@Test
@@ -163,8 +170,8 @@
}
@Test
- public void testBuilder_setInlinePresentations() {
- assertThat(new Dataset.Builder().setInlinePresentation(mId, mValue, mFilter,
+ public void testBuilder_setFieldInlinePresentations() {
+ assertThat(new Dataset.Builder().setFieldInlinePresentation(mId, mValue, mFilter,
mInlinePresentation)).isNotNull();
}
@@ -180,6 +187,8 @@
builder.setValue(mId, mValue, mPresentation);
assertThat(builder.build()).isNotNull();
assertThrows(IllegalStateException.class, () -> builder.build());
+ assertThrows(IllegalStateException.class,
+ () -> builder.setInlinePresentation(mInlinePresentation));
assertThrows(IllegalStateException.class, () -> builder.setValue(mId, mValue));
assertThrows(IllegalStateException.class,
() -> builder.setValue(mId, mValue, mPresentation));
@@ -192,6 +201,7 @@
assertThrows(IllegalStateException.class,
() -> builder.setValue(mId, mValue, mFilter, mPresentation, mInlinePresentation));
assertThrows(IllegalStateException.class,
- () -> builder.setInlinePresentation(mId, mValue, mFilter, mInlinePresentation));
+ () -> builder.setFieldInlinePresentation(mId, mValue, mFilter,
+ mInlinePresentation));
}
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
index 136bcba..a4860e3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
@@ -178,6 +178,13 @@
Log.v(TAG, "device idle in " + delta + "ms");
}
+ public void waitForIdleSync() {
+ final long before = SystemClock.elapsedRealtimeNanos();
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ final float delta = ((float) (SystemClock.elapsedRealtimeNanos() - before)) / 1_000_000;
+ Log.v(TAG, "device idle sync in " + delta + "ms");
+ }
+
public void reset() {
mOkToCallAssertNoDatasets = false;
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java
index 70a4818..99cfcf7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java
@@ -527,10 +527,10 @@
.build());
mActivity.onPassword(View::requestFocus);
mUiBot.assertNoDatasetsEver();
- final AugmentedFillRequest request2 = sAugmentedReplier.getNextFillRequest();
- assertBasicRequestInfo(request2, mActivity, passwordId, passwordValue);
- mAugmentedUiBot.assertUiShown(passwordId, "req2");
+ // (TODO: b/141703197) password request temp disabled.
+ mAugmentedUiBot.assertUiGone();
+ sAugmentedReplier.reset();
// Tap on username again...
sAugmentedReplier.addResponse(new CannedAugmentedFillResponse.Builder()
@@ -643,11 +643,11 @@
.build());
mActivity.onPassword(View::requestFocus);
mUiBot.assertNoDatasetsEver();
- final AugmentedFillRequest request2 = sAugmentedReplier.getNextFillRequest();
- assertBasicRequestInfo(request2, mActivity, passwordId, passwordValue);
- callback.assertUiShownEvent(password);
- mAugmentedUiBot.assertUiShown(passwordId, "req2");
+ // (TODO: b/141703197) password request temp disabled.
+ callback.assertNotCalled();
+ mAugmentedUiBot.assertUiGone();
+ sAugmentedReplier.reset();
// Tap on username again...
sAugmentedReplier.addResponse(new CannedAugmentedFillResponse.Builder()
@@ -661,13 +661,14 @@
final AugmentedFillRequest request3 = sAugmentedReplier.getNextFillRequest();
assertBasicRequestInfo(request3, mActivity, usernameId, usernameValue);
final UiObject2 ui = mAugmentedUiBot.assertUiShown(usernameId, "Augment Me");
+ callback.assertUiShownEvent(username);
// ...and autofill this time
mActivity.expectAutoFill("dude", "sweet");
ui.click();
mActivity.assertAutoFilled();
mAugmentedUiBot.assertUiGone();
- callback.assertUiHiddenEvent(password);
+ callback.assertUiHiddenEvent(username);
}
@Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/augmented/CannedAugmentedFillResponse.java b/tests/autofillservice/src/android/autofillservice/cts/augmented/CannedAugmentedFillResponse.java
index 580816d..5a312ef 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/augmented/CannedAugmentedFillResponse.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/augmented/CannedAugmentedFillResponse.java
@@ -177,7 +177,7 @@
new android.service.autofill.Dataset.Builder();
for (Pair<AutofillId, AutofillValue> pair : dataset.getValues()) {
final AutofillId id = pair.first;
- datasetBuilder.setInlinePresentation(id, pair.second, null,
+ datasetBuilder.setFieldInlinePresentation(id, pair.second, null,
dataset.mFieldPresentationById.get(id));
}
list.add(datasetBuilder.build());
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedLoginActivityTest.java
index 1f94de1..79fd26d 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedLoginActivityTest.java
@@ -17,28 +17,18 @@
package android.autofillservice.cts.inline;
import static android.autofillservice.cts.CannedFillResponse.NO_RESPONSE;
-import static android.autofillservice.cts.Timeouts.MOCK_IME_TIMEOUT_MS;
+import static android.autofillservice.cts.Helper.ID_USERNAME;
import static android.autofillservice.cts.augmented.AugmentedHelper.assertBasicRequestInfo;
-import static com.android.cts.mockime.ImeEventStreamTestUtils.expectBindInput;
-import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
-
-import static org.junit.Assume.assumeTrue;
-
import android.autofillservice.cts.AutofillActivityTestRule;
import android.autofillservice.cts.augmented.AugmentedAutofillAutoActivityLaunchTestCase;
import android.autofillservice.cts.augmented.AugmentedLoginActivity;
import android.autofillservice.cts.augmented.CannedAugmentedFillResponse;
import android.autofillservice.cts.augmented.CtsAugmentedAutofillService.AugmentedFillRequest;
-import android.os.Process;
-import android.view.View;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.widget.EditText;
-import com.android.cts.mockime.ImeEventStream;
-import com.android.cts.mockime.MockImeSession;
-
import org.junit.Test;
public class InlineAugmentedLoginActivityTest
@@ -57,28 +47,11 @@
};
}
- private void enableIME() throws Exception {
- final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession();
- assumeTrue("MockIME not available", mockImeSession != null);
- final ImeEventStream stream = mockImeSession.openEventStream();
-
- // Wait until the MockIme gets bound to the TestActivity.
- expectBindInput(stream, Process.myPid(), MOCK_IME_TIMEOUT_MS);
-
- // Wait until IME is displaying.
- mockImeSession.callRequestShowSelf(0);
- expectEvent(stream, event -> "showSoftInput".equals(event.getEventName()),
- MOCK_IME_TIMEOUT_MS);
- expectEvent(stream, event -> "onStartInputView".equals(event.getEventName()),
- MOCK_IME_TIMEOUT_MS);
- }
-
@Test
public void testAugmentedAutoFill_oneDatasetThenFilled() throws Exception {
// Set services
enableService();
enableAugmentedService();
- enableIME();
// Set expectations
final EditText username = mActivity.getUsername();
@@ -97,7 +70,7 @@
.build());
// Trigger auto-fill
- mActivity.onUsername(View::requestFocus);
+ mUiBot.selectByRelativeId(ID_USERNAME);
mUiBot.waitForIdle();
sReplier.getNextFillRequest();
final AugmentedFillRequest request1 = sAugmentedReplier.getNextFillRequest();
@@ -122,7 +95,6 @@
// Set services
enableService();
enableAugmentedService();
- enableIME();
// Set expectations
final EditText username = mActivity.getUsername();
@@ -145,7 +117,7 @@
.build());
// Trigger auto-fill
- mActivity.onUsername(View::requestFocus);
+ mUiBot.selectByRelativeId(ID_USERNAME);
mUiBot.waitForIdle();
sReplier.getNextFillRequest();
final AugmentedFillRequest request1 = sAugmentedReplier.getNextFillRequest();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAuthenticationTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAuthenticationTest.java
index d27f6fc..ed5b391 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAuthenticationTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAuthenticationTest.java
@@ -23,16 +23,11 @@
import static android.autofillservice.cts.Helper.UNUSED_AUTOFILL_VALUE;
import static android.autofillservice.cts.Helper.getContext;
import static android.autofillservice.cts.LoginActivity.getWelcomeMessage;
-import static android.autofillservice.cts.Timeouts.MOCK_IME_TIMEOUT_MS;
import static android.autofillservice.cts.inline.InstrumentedAutoFillServiceInlineEnabled.SERVICE_NAME;
import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_PASSWORD;
-import static com.android.cts.mockime.ImeEventStreamTestUtils.expectBindInput;
-
import static com.google.common.truth.Truth.assertWithMessage;
-import static org.junit.Assume.assumeTrue;
-
import android.autofillservice.cts.AbstractLoginActivityTestCase;
import android.autofillservice.cts.AuthenticationActivity;
import android.autofillservice.cts.CannedFillResponse;
@@ -40,12 +35,8 @@
import android.autofillservice.cts.Helper;
import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
import android.content.IntentSender;
-import android.os.Process;
import android.platform.test.annotations.AppModeFull;
-import com.android.cts.mockime.ImeEventStream;
-import com.android.cts.mockime.MockImeSession;
-
import org.junit.Test;
import java.util.regex.Pattern;
@@ -81,9 +72,6 @@
// Set service.
enableService();
- final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession();
- assumeTrue("MockIME not available", mockImeSession != null);
-
// Prepare the authenticated response
final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
new CannedFillResponse.CannedDataset.Builder()
@@ -101,12 +89,6 @@
sReplier.addResponse(builder.build());
mActivity.expectAutoFill("dude", "sweet");
- final ImeEventStream stream = mockImeSession.openEventStream();
- mockImeSession.callRequestShowSelf(0);
-
- // Wait until the MockIme gets bound to the TestActivity.
- expectBindInput(stream, Process.myPid(), MOCK_IME_TIMEOUT_MS);
-
// Trigger auto-fill.
assertSuggestionShownBySelectViewId(ID_USERNAME, /* childrenCount */ 1);
sReplier.getNextFillRequest();
@@ -117,7 +99,6 @@
// Now tap on 1st field to show it again...
assertSuggestionShownBySelectViewId(ID_USERNAME, /* childrenCount */ 1);
- // TODO(b/149891961): add logic for cancelFirstAttempt
if (cancelFirstAttempt) {
// Trigger the auth dialog, but emulate cancel.
AuthenticationActivity.setResultCode(RESULT_CANCELED);
@@ -146,9 +127,6 @@
// Set service.
enableService();
- final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession();
- assumeTrue("MockIME not available", mockImeSession != null);
-
// Create the authentication intents
final CannedDataset unlockedDataset = new CannedDataset.Builder()
.setField(ID_USERNAME, "dude")
@@ -169,12 +147,6 @@
// Set expectation for the activity
mActivity.expectAutoFill("dude", "sweet");
- final ImeEventStream stream = mockImeSession.openEventStream();
- mockImeSession.callRequestShowSelf(0);
-
- // Wait until the MockIme gets bound to the TestActivity.
- expectBindInput(stream, Process.myPid(), MOCK_IME_TIMEOUT_MS);
-
// Trigger auto-fill, make sure it's showing initially.
assertSuggestionShownBySelectViewId(ID_USERNAME, /* childrenCount */ 1);
sReplier.getNextFillRequest();
@@ -230,9 +202,6 @@
// Set service.
enableService();
- final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession();
- assumeTrue("MockIME not available", mockImeSession != null);
-
// Prepare the authenticated response
final CannedDataset dataset = new CannedDataset.Builder()
.setField(ID_USERNAME, "dude")
@@ -260,12 +229,6 @@
// Set expectation for the activity
mActivity.expectAutoFill("dude", "sweet");
- final ImeEventStream stream = mockImeSession.openEventStream();
- mockImeSession.callRequestShowSelf(0);
-
- // Wait until the MockIme gets bound to the TestActivity.
- expectBindInput(stream, Process.myPid(), MOCK_IME_TIMEOUT_MS);
-
// Trigger auto-fill, make sure it's showing initially.
assertSuggestionShownBySelectViewId(ID_USERNAME, /* childrenCount */ 1);
sReplier.getNextFillRequest();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineFilteringTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineFilteringTest.java
index 1e47dd0..f5d646aca 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineFilteringTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineFilteringTest.java
@@ -19,20 +19,11 @@
import static android.autofillservice.cts.Helper.ID_PASSWORD;
import static android.autofillservice.cts.Helper.ID_USERNAME;
import static android.autofillservice.cts.Helper.getContext;
-import static android.autofillservice.cts.Timeouts.MOCK_IME_TIMEOUT_MS;
import static android.autofillservice.cts.inline.InstrumentedAutoFillServiceInlineEnabled.SERVICE_NAME;
-import static com.android.cts.mockime.ImeEventStreamTestUtils.expectBindInput;
-
-import static org.junit.Assume.assumeTrue;
-
import android.autofillservice.cts.AbstractLoginActivityTestCase;
import android.autofillservice.cts.CannedFillResponse;
import android.autofillservice.cts.Helper;
-import android.os.Process;
-
-import com.android.cts.mockime.ImeEventStream;
-import com.android.cts.mockime.MockImeSession;
import org.junit.Test;
@@ -52,8 +43,6 @@
@Test
public void testFiltering_filtersByPrefix() throws Exception {
enableService();
- final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession();
- assumeTrue("MockIME not available", mockImeSession != null);
// Set expectations.
final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
@@ -72,33 +61,29 @@
sReplier.addResponse(builder.build());
mActivity.expectAutoFill("test", "tweet");
- final ImeEventStream stream = mockImeSession.openEventStream();
- mockImeSession.callRequestShowSelf(0);
- // Wait until the MockIme gets bound to the TestActivity.
- expectBindInput(stream, Process.myPid(), MOCK_IME_TIMEOUT_MS);
-
// Trigger autofill, then make sure it's showing initially.
mUiBot.selectByRelativeId(ID_USERNAME);
- mUiBot.waitForIdle();
+ mUiBot.waitForIdleSync();
mUiBot.assertSuggestionStrip(2);
sReplier.getNextFillRequest();
// Filter out one of the datasets.
mActivity.onUsername((v) -> v.setText("t"));
- mUiBot.waitForIdle();
+ mUiBot.waitForIdleSync();
mUiBot.assertSuggestionStrip(1);
// Filter out both datasets.
mActivity.onUsername((v) -> v.setText("ta"));
- mUiBot.waitForIdle();
+ mUiBot.waitForIdleSync();
mUiBot.assertNoSuggestionStripEver();
// Backspace to bring back one dataset.
mActivity.onUsername((v) -> v.setText("t"));
- mUiBot.waitForIdle();
+ mUiBot.waitForIdleSync();
mUiBot.assertSuggestionStrip(1);
mUiBot.selectSuggestion(0);
+ mUiBot.waitForIdleSync();
mActivity.assertAutoFilled();
}
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
index 1bee09d..af916ac 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
@@ -23,27 +23,17 @@
import static android.autofillservice.cts.Helper.findNodeByResourceId;
import static android.autofillservice.cts.Helper.getContext;
import static android.autofillservice.cts.InstrumentedAutoFillService.waitUntilDisconnected;
-import static android.autofillservice.cts.Timeouts.MOCK_IME_TIMEOUT_MS;
import static android.autofillservice.cts.inline.InstrumentedAutoFillServiceInlineEnabled.SERVICE_NAME;
-import static com.android.cts.mockime.ImeEventStreamTestUtils.editorMatcher;
-import static com.android.cts.mockime.ImeEventStreamTestUtils.expectBindInput;
-import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
-
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-import static org.junit.Assume.assumeTrue;
-
import android.autofillservice.cts.AbstractLoginActivityTestCase;
import android.autofillservice.cts.CannedFillResponse;
import android.autofillservice.cts.Helper;
import android.autofillservice.cts.InstrumentedAutoFillService;
-import android.os.Process;
import android.service.autofill.FillContext;
-
-import com.android.cts.mockime.ImeEventStream;
-import com.android.cts.mockime.MockImeSession;
+import android.view.View;
import org.junit.Test;
@@ -61,21 +51,11 @@
// Set service.
enableService();
- final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession();
- assumeTrue("MockIME not available", mockImeSession != null);
-
sReplier.addResponse(CannedFillResponse.NO_RESPONSE);
- final ImeEventStream stream = mockImeSession.openEventStream();
- mockImeSession.callRequestShowSelf(0);
-
- // Wait until the MockIme gets bound to the TestActivity.
- expectBindInput(stream, Process.myPid(), MOCK_IME_TIMEOUT_MS);
-
// Trigger auto-fill.
- requestFocusOnUsername();
- expectEvent(stream, editorMatcher("onStartInput", mActivity.getUsername().getId()),
- MOCK_IME_TIMEOUT_MS);
+ mUiBot.selectByRelativeId(ID_USERNAME);
+ mUiBot.waitForIdleSync();
sReplier.getNextFillRequest();
@@ -106,9 +86,6 @@
// Set service.
enableService();
- final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession();
- assumeTrue("MockIME not available", mockImeSession != null);
-
final CannedFillResponse.Builder builder = new CannedFillResponse.Builder();
for (int i = 0; i < numDatasets; i++) {
builder.addDataset(new CannedFillResponse.CannedDataset.Builder()
@@ -122,34 +99,20 @@
sReplier.addResponse(builder.build());
mActivity.expectAutoFill("dude" + selectedDatasetIndex, "sweet" + selectedDatasetIndex);
- final ImeEventStream stream = mockImeSession.openEventStream();
-
- // Wait until the MockIme gets bound to the TestActivity.
- expectBindInput(stream, Process.myPid(), MOCK_IME_TIMEOUT_MS);
-
- // Wait until IME is displaying.
- mockImeSession.callRequestShowSelf(0);
- expectEvent(stream, event -> "showSoftInput".equals(event.getEventName()),
- MOCK_IME_TIMEOUT_MS);
- expectEvent(stream, event -> "onStartInputView".equals(event.getEventName()),
- MOCK_IME_TIMEOUT_MS);
-
// Dynamically set password to make sure it's sanitized.
- mActivity.onPassword((v) -> v.setText("I AM GROOT"));
+ mActivity.syncRunOnUiThread(() -> mActivity.onPassword((v) -> v.setText("I AM GROOT")));
+ mUiBot.waitForIdleSync();
// Trigger auto-fill.
- requestFocusOnUsername();
- expectEvent(stream, editorMatcher("onStartInput", mActivity.getUsername().getId()),
- MOCK_IME_TIMEOUT_MS);
-
- // Wait until suggestion strip is updated
- expectEvent(stream, event -> "onSuggestionViewUpdated".equals(event.getEventName()),
- MOCK_IME_TIMEOUT_MS);
+ mActivity.onUsername(View::requestFocus);
+ mUiBot.selectByRelativeId(ID_USERNAME);
+ mUiBot.waitForIdleSync();
mUiBot.assertSuggestionStrip(numDatasets);
mUiBot.assertNoDatasetsEver();
mUiBot.selectSuggestion(selectedDatasetIndex);
+ mUiBot.waitForIdleSync();
// Check the results.
mActivity.assertAutoFilled();
@@ -174,9 +137,6 @@
// Set service.
enableService();
- final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession();
- assumeTrue("MockIME not available", mockImeSession != null);
-
final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
.addDataset(new CannedFillResponse.CannedDataset.Builder()
.setField(ID_USERNAME, "dude")
@@ -197,45 +157,26 @@
sReplier.addResponse(builder.build());
mActivity.expectAutoFill("dude");
- final ImeEventStream stream = mockImeSession.openEventStream();
-
- // Wait until the MockIme gets bound to the TestActivity.
- expectBindInput(stream, Process.myPid(), MOCK_IME_TIMEOUT_MS);
-
- // Wait until IME is displaying.
- mockImeSession.callRequestShowSelf(0);
- expectEvent(stream, event -> "showSoftInput".equals(event.getEventName()),
- MOCK_IME_TIMEOUT_MS);
- expectEvent(stream, event -> "onStartInputView".equals(event.getEventName()),
- MOCK_IME_TIMEOUT_MS);
-
// Trigger auto-fill.
- requestFocusOnUsername();
- expectEvent(stream, editorMatcher("onStartInput", mActivity.getUsername().getId()),
- MOCK_IME_TIMEOUT_MS);
-
- // Wait until suggestion strip is updated
- expectEvent(stream, event -> "onSuggestionViewUpdated".equals(event.getEventName()),
- MOCK_IME_TIMEOUT_MS);
+ mUiBot.selectByRelativeId(ID_USERNAME);
+ mUiBot.waitForIdleSync();
mUiBot.assertNoDatasetsEver();
-
mUiBot.assertSuggestionStrip(1);
// Switch focus to password
- requestFocusOnPassword();
- expectEvent(stream, event -> "onSuggestionViewUpdated".equals(event.getEventName()),
- MOCK_IME_TIMEOUT_MS);
+ mUiBot.selectByRelativeId(ID_PASSWORD);
+ mUiBot.waitForIdleSync();
mUiBot.assertSuggestionStrip(2);
// Switch focus back to username
- requestFocusOnUsername();
- expectEvent(stream, event -> "onSuggestionViewUpdated".equals(event.getEventName()),
- MOCK_IME_TIMEOUT_MS);
+ mUiBot.selectByRelativeId(ID_USERNAME);
+ mUiBot.waitForIdleSync();
mUiBot.assertSuggestionStrip(1);
mUiBot.selectSuggestion(0);
+ mUiBot.waitForIdleSync();
// Check the results.
mActivity.assertAutoFilled();
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
index 01d9a1e2..73e3828 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
@@ -2519,17 +2519,6 @@
CaptureRequest.DISTORTION_CORRECTION_MODE_OFF);
}
- // Scaler settings
- if (mStaticInfo.areKeysAvailable(
- CameraCharacteristics.SCALER_AVAILABLE_ROTATE_AND_CROP_MODES)) {
- List<Integer> rotateAndCropModes = Arrays.asList(toObject(
- props.get(CameraCharacteristics.SCALER_AVAILABLE_ROTATE_AND_CROP_MODES)));
- if (rotateAndCropModes.contains(SCALER_ROTATE_AND_CROP_AUTO)) {
- mCollector.expectKeyValueEquals(request, SCALER_ROTATE_AND_CROP,
- CaptureRequest.SCALER_ROTATE_AND_CROP_AUTO);
- }
- }
-
// TODO: use the list of keys from CameraCharacteristics to avoid expecting
// keys which are not available by this CameraDevice.
}
diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
index 5940493..d6a95bc 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
@@ -733,10 +733,6 @@
waiverKeys.add(CaptureResult.CONTROL_BOKEH_MODE);
}
- if (!staticInfo.isRotateAndCropSupported()) {
- waiverKeys.add(CaptureResult.SCALER_ROTATE_AND_CROP);
- }
-
if (staticInfo.isHardwareLevelAtLeastFull()) {
return waiverKeys;
}
@@ -851,7 +847,6 @@
waiverKeys.add(CaptureResult.STATISTICS_FACE_DETECT_MODE);
waiverKeys.add(CaptureResult.FLASH_MODE);
waiverKeys.add(CaptureResult.SCALER_CROP_REGION);
- waiverKeys.add(CaptureResult.SCALER_ROTATE_AND_CROP);
return waiverKeys;
}
@@ -1024,7 +1019,6 @@
resultKeys.add(CaptureResult.NOISE_REDUCTION_MODE);
resultKeys.add(CaptureResult.REQUEST_PIPELINE_DEPTH);
resultKeys.add(CaptureResult.SCALER_CROP_REGION);
- resultKeys.add(CaptureResult.SCALER_ROTATE_AND_CROP);
resultKeys.add(CaptureResult.SENSOR_EXPOSURE_TIME);
resultKeys.add(CaptureResult.SENSOR_FRAME_DURATION);
resultKeys.add(CaptureResult.SENSOR_SENSITIVITY);
diff --git a/tests/camera/src/android/hardware/camera2/cts/ConcurrentCameraTest.java b/tests/camera/src/android/hardware/camera2/cts/ConcurrentCameraTest.java
index 05118b1..ebff2dd 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ConcurrentCameraTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ConcurrentCameraTest.java
@@ -186,7 +186,7 @@
/**
* Generates a list of combinations used for mandatory stream combination testing.
* Each combination(GeneratedEntry) corresponds to a camera id advertised by
- * getConcurrentStreamingCameraIds().
+ * getConcurrentCameraIds().
*/
private List<HashMap<String, GeneratedEntry>> generateStreamSelections(
Set<String> cameraIdCombination) {
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 770f3e4..07155ff 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -2315,53 +2315,6 @@
}
}
- /**
- * Check rotate-and-crop camera reporting.
- * Every device must report NONE; if actually supporting feature, must report NONE, 90, AUTO at
- * least.
- */
- @Test
- public void testRotateAndCropCharacteristics() {
- for (int i = 0; i < mAllCameraIds.length; i++) {
- Log.i(TAG, "testRotateAndCropCharacteristics: Testing camera ID " + mAllCameraIds[i]);
-
- CameraCharacteristics c = mCharacteristics.get(i);
-
- if (!arrayContains(mCameraIdsUnderTest, mAllCameraIds[i])) {
- // Skip hidden physical cameras
- continue;
- }
-
- int[] availableRotateAndCropModes = c.get(
- CameraCharacteristics.SCALER_AVAILABLE_ROTATE_AND_CROP_MODES);
- assertTrue("availableRotateAndCropModes must not be null",
- availableRotateAndCropModes != null);
- boolean foundAuto = false;
- boolean foundNone = false;
- boolean found90 = false;
- for (int mode : availableRotateAndCropModes) {
- switch(mode) {
- case CameraCharacteristics.SCALER_ROTATE_AND_CROP_NONE:
- foundNone = true;
- break;
- case CameraCharacteristics.SCALER_ROTATE_AND_CROP_90:
- found90 = true;
- break;
- case CameraCharacteristics.SCALER_ROTATE_AND_CROP_AUTO:
- foundAuto = true;
- break;
- }
- }
- if (availableRotateAndCropModes.length > 1) {
- assertTrue("To support SCALER_ROTATE_AND_CROP: NONE, 90, and AUTO must be included",
- foundNone && found90 && foundAuto);
- } else {
- assertTrue("If only one SCALER_ROTATE_AND_CROP value is supported, it must be NONE",
- foundNone);
- }
- }
- }
-
private boolean matchParametersToCharacteritics(Camera.Parameters params,
Camera.CameraInfo info, CameraCharacteristics ch) {
Integer facing = ch.get(CameraCharacteristics.LENS_FACING);
diff --git a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
index af254b1..4a02036 100644
--- a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
@@ -285,16 +285,18 @@
*/
@Test
public void testSingleCapture() throws Exception {
- int[] YUV_FORMAT = {ImageFormat.YUV_420_888};
- testSingleCaptureForFormat(YUV_FORMAT, null, /*addPreviewDelay*/ false);
- int[] PRIVATE_FORMAT = {ImageFormat.PRIVATE};
- testSingleCaptureForFormat(PRIVATE_FORMAT, "private", /*addPreviewDelay*/ true);
int[] JPEG_FORMAT = {ImageFormat.JPEG};
testSingleCaptureForFormat(JPEG_FORMAT, "jpeg", /*addPreviewDelay*/ true);
- int[] RAW_FORMAT = {ImageFormat.RAW_SENSOR};
- testSingleCaptureForFormat(RAW_FORMAT, "raw", /*addPreviewDelay*/ true);
- int[] RAW_JPEG_FORMATS = {ImageFormat.RAW_SENSOR, ImageFormat.JPEG};
- testSingleCaptureForFormat(RAW_JPEG_FORMATS, "raw_jpeg", /*addPreviewDelay*/ true);
+ if (!mTestRule.isPerfMeasure()) {
+ int[] YUV_FORMAT = {ImageFormat.YUV_420_888};
+ testSingleCaptureForFormat(YUV_FORMAT, null, /*addPreviewDelay*/ false);
+ int[] PRIVATE_FORMAT = {ImageFormat.PRIVATE};
+ testSingleCaptureForFormat(PRIVATE_FORMAT, "private", /*addPreviewDelay*/ true);
+ int[] RAW_FORMAT = {ImageFormat.RAW_SENSOR};
+ testSingleCaptureForFormat(RAW_FORMAT, "raw", /*addPreviewDelay*/ true);
+ int[] RAW_JPEG_FORMATS = {ImageFormat.RAW_SENSOR, ImageFormat.JPEG};
+ testSingleCaptureForFormat(RAW_JPEG_FORMATS, "raw_jpeg", /*addPreviewDelay*/ true);
+ }
}
private String appendFormatDescription(String message, String formatDescription) {
@@ -1551,4 +1553,4 @@
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
index 30d1943..067104c 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
@@ -1168,8 +1168,13 @@
", num of frames produced: " + resultListener.getTotalNumFrames());
}
- // Validation.
- validateRecording(videoSz, durationMs, frameDurationMs, FRMDRP_RATE_TOLERANCE);
+ if (isPerfMeasure()) {
+ // Only measure the largest video recording size when measuring perf
+ break;
+ } else {
+ // Validation.
+ validateRecording(videoSz, durationMs, frameDurationMs, FRMDRP_RATE_TOLERANCE);
+ }
}
if (maxVideoFrameRate != -1) {
// At least one CamcorderProfile is present, check FPS
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestRule.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestRule.java
index 13ce89a..f5dedba 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestRule.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestRule.java
@@ -91,8 +91,10 @@
private Context mContext;
private static final String CAMERA_ID_INSTR_ARG_KEY = "camera-id";
+ private static final String CAMERA_PERF_MEASURE = "perf-measure";
private static final Bundle mBundle = InstrumentationRegistry.getArguments();
private static final String mOverrideCameraId = mBundle.getString(CAMERA_ID_INSTR_ARG_KEY);
+ private static final String mPerfMeasure = mBundle.getString(CAMERA_PERF_MEASURE);
public Camera2AndroidTestRule(Context context) {
mContext = context;
@@ -182,6 +184,10 @@
return mCollector;
}
+ public boolean isPerfMeasure() {
+ return mPerfMeasure != null && mPerfMeasure.equals("on");
+ }
+
private String[] deriveCameraIdsUnderTest() throws Exception {
String[] idsUnderTest = mCameraManager.getCameraIdListNoLazy();
assertNotNull("Camera ids shouldn't be null", idsUnderTest);
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2ConcurrentAndroidTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2ConcurrentAndroidTestCase.java
index 8877343..c35e8d5 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2ConcurrentAndroidTestCase.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2ConcurrentAndroidTestCase.java
@@ -124,7 +124,7 @@
}
}
mConcurrentCameraIdCombinations =
- CameraTestUtils.getConcurrentStreamingCameraIds(mCameraManager, mAdoptShellPerm);
+ CameraTestUtils.getConcurrentCameraIds(mCameraManager, mAdoptShellPerm);
assertNotNull("Unable to get concurrent camera combinations",
mConcurrentCameraIdCombinations);
mCameraTestInfos = new HashMap<String, CameraTestInfo>();
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
index dd26ffd..da6593f 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -851,11 +851,11 @@
return idsForTesting.toArray(new String[idsForTesting.size()]);
}
- public static Set<Set<String>> getConcurrentStreamingCameraIds(CameraManager manager,
+ public static Set<Set<String>> getConcurrentCameraIds(CameraManager manager,
boolean getSystemCameras)
throws CameraAccessException {
Set<String> cameraIds = new HashSet<String>(Arrays.asList(getCameraIdListForTesting(manager, getSystemCameras)));
- Set<Set<String>> combinations = manager.getConcurrentStreamingCameraIds();
+ Set<Set<String>> combinations = manager.getConcurrentCameraIds();
Set<Set<String>> correctComb = new HashSet<Set<String>>();
for (Set<String> comb : combinations) {
Set<String> filteredIds = new HashSet<String>();
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
index 82aa09e..a5bedea 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
@@ -2577,26 +2577,6 @@
}
/**
- * Check if rotate and crop is supported
- */
- public boolean isRotateAndCropSupported() {
- int[] availableRotateAndCropModes = mCharacteristics.get(
- CameraCharacteristics.SCALER_AVAILABLE_ROTATE_AND_CROP_MODES);
-
- if (availableRotateAndCropModes == null) {
- return false;
- }
-
- for (int mode : availableRotateAndCropModes) {
- if (mode != CameraMetadata.SCALER_ROTATE_AND_CROP_NONE) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
* Check if distortion correction is supported.
*/
public boolean isDistortionCorrectionSupported() {
diff --git a/tests/camera/utils/src/android/hardware/cts/helpers/CameraParameterizedTestCase.java b/tests/camera/utils/src/android/hardware/cts/helpers/CameraParameterizedTestCase.java
index 047fba5..6a78d60 100644
--- a/tests/camera/utils/src/android/hardware/cts/helpers/CameraParameterizedTestCase.java
+++ b/tests/camera/utils/src/android/hardware/cts/helpers/CameraParameterizedTestCase.java
@@ -44,13 +44,22 @@
public boolean mAdoptShellPerm;
private static final String CAMERA_ID_INSTR_ARG_KEY = "camera-id";
+ private static final String CAMERA_PERF_MEASURE = "perf-measure";
private static final Bundle mBundle = InstrumentationRegistry.getArguments();
protected static final String mOverrideCameraId = mBundle.getString(CAMERA_ID_INSTR_ARG_KEY);
+ protected static final String mPerfMeasure = mBundle.getString(CAMERA_PERF_MEASURE);
+
+ public boolean isPerfMeasure() {
+ return mPerfMeasure != null && mPerfMeasure.equals("on");
+ }
@Parameters
public static Iterable<? extends Object> data() {
List<Boolean> adoptShellPerm = new ArrayList<Boolean>();
- adoptShellPerm.add(true);
+ // Only add adoptShellPerm(true) of camera id is not overridden.
+ if (mPerfMeasure == null || !mPerfMeasure.equals("on")) {
+ adoptShellPerm.add(true);
+ }
adoptShellPerm.add(false);
return adoptShellPerm;
}
diff --git a/tests/framework/base/windowmanager/app/AndroidManifest.xml b/tests/framework/base/windowmanager/app/AndroidManifest.xml
index 507859b..67cae55 100755
--- a/tests/framework/base/windowmanager/app/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app/AndroidManifest.xml
@@ -162,6 +162,16 @@
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
android:exported="true"
/>
+ <activity android:name=".PipActivityWithMinimalSize"
+ android:resizeableActivity="false"
+ android:supportsPictureInPicture="true"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+ android:exported="true"
+ android:taskAffinity="nobody.but.PipActivity">
+ <layout android:minWidth="100dp"
+ android:minHeight="80dp"
+ />
+ </activity>
<activity android:name=".FreeformActivity"
android:resizeableActivity="true"
android:taskAffinity="nobody.but.FreeformActivity"
@@ -544,6 +554,14 @@
</intent-filter>
</service>
+ <activity android:name=".HostActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.server.wm.app.HostActivity"></action>
+ </intent-filter>
+ </activity>
+ <service android:name=".RenderService"
+ android:process=".render_process" />
<activity
android:name=".ClickableToastActivity"
android:exported="true" />
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
index 8a06a46..b5e8de2 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
@@ -50,6 +50,7 @@
public static final ComponentName FONT_SCALE_NO_RELAUNCH_ACTIVITY =
component("FontScaleNoRelaunchActivity");
public static final ComponentName FREEFORM_ACTIVITY = component("FreeformActivity");
+ public static final ComponentName HOST_ACTIVITY = component("HostActivity");
public static final ComponentName KEYGUARD_LOCK_ACTIVITY = component("KeyguardLockActivity");
public static final ComponentName LANDSCAPE_ORIENTATION_ACTIVITY =
component("LandscapeOrientationActivity");
@@ -76,6 +77,8 @@
public static final ComponentName PRESENTATION_ACTIVITY = component("PresentationActivity");
public static final ComponentName PIP_ACTIVITY = component("PipActivity");
public static final ComponentName PIP_ACTIVITY2 = component("PipActivity2");
+ public static final ComponentName PIP_ACTIVITY_WITH_MINIMAL_SIZE = component(
+ "PipActivityWithMinimalSize");
public static final ComponentName PIP_ACTIVITY_WITH_SAME_AFFINITY =
component("PipActivityWithSameAffinity");
public static final ComponentName PIP_ON_STOP_ACTIVITY = component("PipOnStopActivity");
@@ -445,6 +448,10 @@
public static final String PROCESS_NAME = ".unresponsive_activity_process";
}
+ public static class RenderService {
+ public static final String PROCESS_NAME = ".render_process";
+ }
+
/**
* Extra key constants for {@link android.server.wm.app.VirtualDisplayActivity}.
*
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/HostActivity.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/HostActivity.java
new file mode 100644
index 0000000..11354fb
--- /dev/null
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/HostActivity.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2020 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.wm.app;
+
+import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_MOTIONEVENT_DELAY_MS;
+import static android.server.wm.app.RenderService.BROADCAST_EMBED_CONTENT;
+import static android.server.wm.app.RenderService.EXTRAS_BUNDLE;
+import static android.server.wm.app.RenderService.EXTRAS_DISPLAY_ID;
+import static android.server.wm.app.RenderService.EXTRAS_HOST_TOKEN;
+import static android.server.wm.app.RenderService.EXTRAS_SURFACE_PACKAGE;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.view.SurfaceControlViewHost.SurfacePackage;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
+
+public class HostActivity extends Activity implements SurfaceHolder.Callback{
+ private SurfaceView mSurfaceView;
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {}
+
+ @Override
+ public void onServiceDisconnected(ComponentName className) {}
+ };
+
+ private BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ SurfacePackage surfacePackage =
+ intent.getParcelableExtra(EXTRAS_SURFACE_PACKAGE);
+ if (surfacePackage != null) {
+ mSurfaceView.setChildSurfacePackage(surfacePackage);
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BROADCAST_EMBED_CONTENT);
+ registerReceiver(receiver, filter);
+
+ final RelativeLayout content = new RelativeLayout(this);
+ mSurfaceView = new SurfaceView(this);
+ mSurfaceView.setZOrderOnTop(true);
+ content.addView(mSurfaceView,
+ new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
+ RelativeLayout.LayoutParams.MATCH_PARENT));
+ setContentView(content, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ mSurfaceView.getHolder().addCallback(this);
+ }
+
+ @Override
+ protected void onPause() {
+ unregisterReceiver(receiver);
+ super.onPause();
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ Intent mIntent = new Intent(this, RenderService.class);
+ Bundle b = new Bundle();
+ b.putBinder(EXTRAS_HOST_TOKEN, mSurfaceView.getHostToken());
+ b.putInt(EXTRAS_DISPLAY_ID, getDisplayId());
+ b.putInt(EXTRA_ON_MOTIONEVENT_DELAY_MS,
+ getIntent().getIntExtra(EXTRA_ON_MOTIONEVENT_DELAY_MS, 2000));
+ mIntent.putExtra(EXTRAS_BUNDLE, b);
+ bindService(mIntent, mConnection, Context.BIND_AUTO_CREATE|Context.BIND_IMPORTANT);
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {}
+}
diff --git a/apps/CtsVerifier/jni/audio_loopback/audio_utils/roundup.h b/tests/framework/base/windowmanager/app/src/android/server/wm/app/PipActivityWithMinimalSize.java
similarity index 61%
copy from apps/CtsVerifier/jni/audio_loopback/audio_utils/roundup.h
copy to tests/framework/base/windowmanager/app/src/android/server/wm/app/PipActivityWithMinimalSize.java
index ad34289..8c573c0 100644
--- a/apps/CtsVerifier/jni/audio_loopback/audio_utils/roundup.h
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/PipActivityWithMinimalSize.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -11,21 +11,14 @@
* 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.
+ * limitations under the License
*/
-#ifndef ANDROID_AUDIO_ROUNDUP_H
-#define ANDROID_AUDIO_ROUNDUP_H
+package android.server.wm.app;
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Round up to the next highest power of 2
-unsigned roundup(unsigned v);
-
-#ifdef __cplusplus
+/**
+ * An activity that has the same behavior as {@link PipActivity} and specifies
+ * minimal dimension in its manifest.
+ */
+public class PipActivityWithMinimalSize extends PipActivity {
}
-#endif
-
-#endif // ANDROID_AUDIO_ROUNDUP_H
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java
new file mode 100644
index 0000000..58da2d4
--- /dev/null
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 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.wm.app;
+
+import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_MOTIONEVENT_DELAY_MS;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.PixelFormat;
+import android.hardware.display.DisplayManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.SystemClock;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.MotionEvent;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Button;
+
+public class RenderService extends Service {
+ static final String EXTRAS_BUNDLE = "INTENT_BUNDLE";
+ static final String EXTRAS_DISPLAY_ID = "hostDisplayId";
+ static final String EXTRAS_HOST_TOKEN = "hostInputToken";
+ static final String BROADCAST_EMBED_CONTENT
+ = "android.server.wm.app.RenderService.EMBED_CONTENT";
+ static final String EXTRAS_SURFACE_PACKAGE = "surfacePackage";
+
+ private int mOnMotionEventDelayMs;
+
+ private boolean onTouch(View v, MotionEvent event) {
+ SystemClock.sleep(mOnMotionEventDelayMs);
+ // Don't consume the event.
+ return false;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ Bundle b = intent.getBundleExtra(EXTRAS_BUNDLE);
+ IBinder hostToken = b.getBinder(EXTRAS_HOST_TOKEN);
+ int hostDisplayId = b.getInt(EXTRAS_DISPLAY_ID);
+ mOnMotionEventDelayMs = b.getInt(EXTRA_ON_MOTIONEVENT_DELAY_MS);
+
+ SurfaceControlViewHost surfaceControlViewHost = getSurfaceControlViewHost(hostToken,
+ hostDisplayId);
+ sendSurfacePackage(surfaceControlViewHost.getSurfacePackage());
+ return null;
+ }
+
+ private SurfaceControlViewHost getSurfaceControlViewHost(IBinder hostToken, int hostDisplayId) {
+ final Context displayContext = getDisplayContext(hostDisplayId);
+ SurfaceControlViewHost surfaceControlViewHost =
+ new SurfaceControlViewHost(displayContext, displayContext.getDisplay(), hostToken);
+
+ View embeddedView = new Button(this);
+ embeddedView.setOnTouchListener(this::onTouch);
+ DisplayMetrics metrics = new DisplayMetrics();
+ displayContext.getDisplay().getMetrics(metrics);
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(metrics.widthPixels,
+ metrics.heightPixels, TYPE_APPLICATION, 0,
+ PixelFormat.OPAQUE);
+ surfaceControlViewHost.setView(embeddedView, lp);
+ return surfaceControlViewHost;
+ }
+
+ private Context getDisplayContext(int hostDisplayId) {
+ final DisplayManager displayManager = getSystemService(DisplayManager.class);
+ final Display targetDisplay = displayManager.getDisplay(hostDisplayId);
+ return createDisplayContext(targetDisplay);
+ }
+
+ private void sendSurfacePackage(SurfaceControlViewHost.SurfacePackage surfacePackage) {
+ Intent broadcast = new Intent();
+ broadcast.setAction(BROADCAST_EMBED_CONTENT);
+ broadcast.putExtra(EXTRAS_SURFACE_PACKAGE, surfacePackage);
+ sendBroadcast(broadcast);
+ }
+}
diff --git a/tests/framework/base/windowmanager/intent_tests/clearCases/clear-task_with_new-task.json b/tests/framework/base/windowmanager/intent_tests/clearCases/clear-task_with_new-task.json
index 09753b8..18bcd6f81 100644
--- a/tests/framework/base/windowmanager/intent_tests/clearCases/clear-task_with_new-task.json
+++ b/tests/framework/base/windowmanager/intent_tests/clearCases/clear-task_with_new-task.json
@@ -18,37 +18,27 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/clearCases/clear-task_without_new-task.json b/tests/framework/base/windowmanager/intent_tests/clearCases/clear-task_without_new-task.json
index da82d52..cd89b22 100644
--- a/tests/framework/base/windowmanager/intent_tests/clearCases/clear-task_without_new-task.json
+++ b/tests/framework/base/windowmanager/intent_tests/clearCases/clear-task_without_new-task.json
@@ -18,41 +18,31 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/clearCases/test-1.json b/tests/framework/base/windowmanager/intent_tests/clearCases/test-1.json
index 0ee6cc8..8e477ed 100644
--- a/tests/framework/base/windowmanager/intent_tests/clearCases/test-1.json
+++ b/tests/framework/base/windowmanager/intent_tests/clearCases/test-1.json
@@ -18,37 +18,27 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/clearCases/test-2.json b/tests/framework/base/windowmanager/intent_tests/clearCases/test-2.json
index 35fadcc..15f0db4 100644
--- a/tests/framework/base/windowmanager/intent_tests/clearCases/test-2.json
+++ b/tests/framework/base/windowmanager/intent_tests/clearCases/test-2.json
@@ -24,45 +24,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/clearCases/test-3.json b/tests/framework/base/windowmanager/intent_tests/clearCases/test-3.json
index 42f1ffa..304dce9 100644
--- a/tests/framework/base/windowmanager/intent_tests/clearCases/test-3.json
+++ b/tests/framework/base/windowmanager/intent_tests/clearCases/test-3.json
@@ -24,45 +24,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/clearCases/test-4.json b/tests/framework/base/windowmanager/intent_tests/clearCases/test-4.json
index 5b52541..e73fc19 100644
--- a/tests/framework/base/windowmanager/intent_tests/clearCases/test-4.json
+++ b/tests/framework/base/windowmanager/intent_tests/clearCases/test-4.json
@@ -24,45 +24,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/clearCases/test-5.json b/tests/framework/base/windowmanager/intent_tests/clearCases/test-5.json
index 2f1def6..67fba8ac2 100644
--- a/tests/framework/base/windowmanager/intent_tests/clearCases/test-5.json
+++ b/tests/framework/base/windowmanager/intent_tests/clearCases/test-5.json
@@ -24,45 +24,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/clearCases/test-6.json b/tests/framework/base/windowmanager/intent_tests/clearCases/test-6.json
index dce5119..1a1471e 100644
--- a/tests/framework/base/windowmanager/intent_tests/clearCases/test-6.json
+++ b/tests/framework/base/windowmanager/intent_tests/clearCases/test-6.json
@@ -30,49 +30,39 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/test-1.json b/tests/framework/base/windowmanager/intent_tests/forResult/test-1.json
index f901ad1..b26456b 100644
--- a/tests/framework/base/windowmanager/intent_tests/forResult/test-1.json
+++ b/tests/framework/base/windowmanager/intent_tests/forResult/test-1.json
@@ -18,37 +18,27 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/test-2.json b/tests/framework/base/windowmanager/intent_tests/forResult/test-2.json
index 6e97377..c8bcea6 100644
--- a/tests/framework/base/windowmanager/intent_tests/forResult/test-2.json
+++ b/tests/framework/base/windowmanager/intent_tests/forResult/test-2.json
@@ -18,41 +18,31 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/test-3.json b/tests/framework/base/windowmanager/intent_tests/forResult/test-3.json
index da3478d..7c2d5e9 100644
--- a/tests/framework/base/windowmanager/intent_tests/forResult/test-3.json
+++ b/tests/framework/base/windowmanager/intent_tests/forResult/test-3.json
@@ -18,37 +18,27 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleTopActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleTopActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/test-4.json b/tests/framework/base/windowmanager/intent_tests/forResult/test-4.json
index 2ed6023..487e287 100644
--- a/tests/framework/base/windowmanager/intent_tests/forResult/test-4.json
+++ b/tests/framework/base/windowmanager/intent_tests/forResult/test-4.json
@@ -18,41 +18,31 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleTopActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleTopActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleTopActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/test-5.json b/tests/framework/base/windowmanager/intent_tests/forResult/test-5.json
index 0ee6cc8..8e477ed 100644
--- a/tests/framework/base/windowmanager/intent_tests/forResult/test-5.json
+++ b/tests/framework/base/windowmanager/intent_tests/forResult/test-5.json
@@ -18,37 +18,27 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/test-6.json b/tests/framework/base/windowmanager/intent_tests/forResult/test-6.json
index dca9dd2..dc2f620 100644
--- a/tests/framework/base/windowmanager/intent_tests/forResult/test-6.json
+++ b/tests/framework/base/windowmanager/intent_tests/forResult/test-6.json
@@ -18,37 +18,27 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/test-7.json b/tests/framework/base/windowmanager/intent_tests/forResult/test-7.json
index 4599e0f..95c2d0b 100644
--- a/tests/framework/base/windowmanager/intent_tests/forResult/test-7.json
+++ b/tests/framework/base/windowmanager/intent_tests/forResult/test-7.json
@@ -18,49 +18,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/test-8.json b/tests/framework/base/windowmanager/intent_tests/forResult/test-8.json
index 22608c7..032558a 100644
--- a/tests/framework/base/windowmanager/intent_tests/forResult/test-8.json
+++ b/tests/framework/base/windowmanager/intent_tests/forResult/test-8.json
@@ -24,45 +24,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/test-9.json b/tests/framework/base/windowmanager/intent_tests/forResult/test-9.json
index 3f2a71a..588a98d 100644
--- a/tests/framework/base/windowmanager/intent_tests/forResult/test-9.json
+++ b/tests/framework/base/windowmanager/intent_tests/forResult/test-9.json
@@ -24,45 +24,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-1.json b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-1.json
index e4accd3..c0c9af0 100644
--- a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-1.json
+++ b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-1.json
@@ -18,49 +18,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleInstanceActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-10.json b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-10.json
index 0b5a0f5..1f9c91c 100644
--- a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-10.json
+++ b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-10.json
@@ -18,49 +18,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-11.json b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-11.json
index 3b782b0..64cc2c9 100644
--- a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-11.json
+++ b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-11.json
@@ -18,37 +18,27 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleInstanceActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleInstanceActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-12.json b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-12.json
index 63f9948..ca2bb0f 100644
--- a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-12.json
+++ b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-12.json
@@ -18,37 +18,27 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTaskActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleTaskActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTaskActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTaskActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleTaskActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTaskActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-2.json b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-2.json
index baa3996d..cb74d21 100644
--- a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-2.json
+++ b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-2.json
@@ -18,49 +18,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleInstanceActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-3.json b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-3.json
index 53d01b1..fe88fad 100644
--- a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-3.json
+++ b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-3.json
@@ -18,41 +18,31 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-4.json b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-4.json
index 697703b..810f44d 100644
--- a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-4.json
+++ b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-4.json
@@ -18,49 +18,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-5.json b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-5.json
index 2050021..8316f2d 100644
--- a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-5.json
+++ b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-5.json
@@ -18,37 +18,27 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-6.json b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-6.json
index 07e05bc..2957f18 100644
--- a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-6.json
+++ b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-6.json
@@ -18,49 +18,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleTopActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-7.json b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-7.json
index b6354b5..dab125d 100644
--- a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-7.json
+++ b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-7.json
@@ -30,69 +30,51 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
}
]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-8.json b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-8.json
index c8ef9f8..67f9f6f 100644
--- a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-8.json
+++ b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-8.json
@@ -36,69 +36,51 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-9.json b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-9.json
index 296475f..cd1973a 100644
--- a/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-9.json
+++ b/tests/framework/base/windowmanager/intent_tests/newDocumentCases/test-9.json
@@ -36,81 +36,59 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2",
- "state": "RESUMED"
- }
- ]
- }
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2"
- },
- {
- "tasks": [
- {
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity2",
+ "state": "RESUMED"
}
]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
+ }
+ ]
+ },
+ {
+ "activities": [
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/request_new_task_different_affinity-new_task.json b/tests/framework/base/windowmanager/intent_tests/newTask/request_new_task_different_affinity-new_task.json
index 9d878d8..99b4046 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/request_new_task_different_affinity-new_task.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/request_new_task_different_affinity-new_task.json
@@ -18,49 +18,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/request_new_task_same_affinity-same_task.json b/tests/framework/base/windowmanager/intent_tests/newTask/request_new_task_same_affinity-same_task.json
index 6944973..3635017 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/request_new_task_same_affinity-same_task.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/request_new_task_same_affinity-same_task.json
@@ -18,41 +18,31 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity2",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/request_same_task_different_affinity-same_task.json b/tests/framework/base/windowmanager/intent_tests/newTask/request_same_task_different_affinity-same_task.json
index a444299..52470c0 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/request_same_task_different_affinity-same_task.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/request_same_task_different_affinity-same_task.json
@@ -18,41 +18,31 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-1.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-1.json
index e4accd3..c0c9af0 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-1.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-1.json
@@ -18,49 +18,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleInstanceActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-10.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-10.json
index 55c049a..06e5363 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-10.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-10.json
@@ -18,49 +18,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-11.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-11.json
index 7e3ab21..6e93afb 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-11.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-11.json
@@ -18,37 +18,27 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleInstanceActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleInstanceActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-12.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-12.json
index 563683f..769a9b8 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-12.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-12.json
@@ -18,37 +18,27 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTaskActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleTaskActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTaskActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTaskActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleTaskActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTaskActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-13.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-13.json
index 0d6fc3d..4f4f738 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-13.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-13.json
@@ -18,49 +18,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleInstanceActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleInstanceActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-14.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-14.json
index b430952..4f3c581 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-14.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-14.json
@@ -18,41 +18,31 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTaskActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleTaskActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTaskActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTaskActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleTaskActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-15.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-15.json
index 33419d6..b0f1b08 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-15.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-15.json
@@ -18,41 +18,31 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleInstanceActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleInstanceActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-16.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-16.json
index d6eac92..d579057 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-16.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-16.json
@@ -24,61 +24,43 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleInstanceActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleInstanceActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-2.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-2.json
index b9acd47..8441735 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-2.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-2.json
@@ -18,49 +18,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleInstanceActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-3.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-3.json
index 53d01b1..fe88fad 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-3.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-3.json
@@ -18,41 +18,31 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-4.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-4.json
index a394a58..6168dac 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-4.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-4.json
@@ -18,49 +18,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-5.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-5.json
index 38d86eb..1769784 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-5.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-5.json
@@ -18,37 +18,27 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-6.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-6.json
index e279673..94104ee 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-6.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-6.json
@@ -18,41 +18,31 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$SingleTopActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-7.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-7.json
index a7a8232..7209c12 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-7.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-7.json
@@ -30,69 +30,51 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
}
]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-8.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-8.json
index bf57d0c..91f8229 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-8.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-8.json
@@ -36,69 +36,51 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-9.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-9.json
index 5c1bd4e..a257933 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-9.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-9.json
@@ -36,73 +36,55 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity2",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/keep_affinity-request_new_task_with_same_affinity-same_task.json b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/keep_affinity-request_new_task_with_same_affinity-same_task.json
index 3dd2c99..924e7e2 100644
--- a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/keep_affinity-request_new_task_with_same_affinity-same_task.json
+++ b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/keep_affinity-request_new_task_with_same_affinity-same_task.json
@@ -24,49 +24,39 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity2",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_new_task_with_changed_affinity-new_task.json b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_new_task_with_changed_affinity-new_task.json
index 53f01b5..3b8ecb2 100644
--- a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_new_task_with_changed_affinity-new_task.json
+++ b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_new_task_with_changed_affinity-new_task.json
@@ -25,57 +25,43 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity2",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_new_task_with_old_affinity-same_task.json b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_new_task_with_old_affinity-same_task.json
index 2ec6f78..f8ec310b 100644
--- a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_new_task_with_old_affinity-same_task.json
+++ b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_new_task_with_old_affinity-same_task.json
@@ -25,49 +25,39 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_same_task_with_changed_affinity-same_task.json b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_same_task_with_changed_affinity-same_task.json
index 7e31db4..fe0c8b1 100644
--- a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_same_task_with_changed_affinity-same_task.json
+++ b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_same_task_with_changed_affinity-same_task.json
@@ -25,49 +25,39 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity2",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_same_task_with_old_affinity-same_task.json b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_same_task_with_old_affinity-same_task.json
index afd155a..0d6d344 100644
--- a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_same_task_with_old_affinity-same_task.json
+++ b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_change_affinity-request_same_task_with_old_affinity-same_task.json
@@ -25,49 +25,39 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RelinquishTaskIdentityActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_new_task_with_different_affinity-new_task.json b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_new_task_with_different_affinity-new_task.json
index cd6a3a4..e1905d9 100644
--- a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_new_task_with_different_affinity-new_task.json
+++ b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_new_task_with_different_affinity-new_task.json
@@ -18,49 +18,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_new_task_with_same_affinity-same_task.json b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_new_task_with_same_affinity-same_task.json
index 999ee82..78ac855 100644
--- a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_new_task_with_same_affinity-same_task.json
+++ b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_new_task_with_same_affinity-same_task.json
@@ -18,41 +18,31 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_same_task_with_different_affinity-same_task.json b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_same_task_with_different_affinity-same_task.json
index d0ec60c..ed2dfe2 100644
--- a/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_same_task_with_different_affinity-same_task.json
+++ b/tests/framework/base/windowmanager/intent_tests/relinquishTaskIdentity/request_same_task_with_different_affinity-same_task.json
@@ -18,41 +18,31 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1RelinquishTaskIdentityActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/reorderToFront/reorder-to-front.json b/tests/framework/base/windowmanager/intent_tests/reorderToFront/reorder-to-front.json
index 9daaa0f..5e3de96 100644
--- a/tests/framework/base/windowmanager/intent_tests/reorderToFront/reorder-to-front.json
+++ b/tests/framework/base/windowmanager/intent_tests/reorderToFront/reorder-to-front.json
@@ -36,61 +36,51 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity2Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity2Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity2Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity2Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/reorderToFront/reorder-to-front_with_new-task_on_different_affinity.json b/tests/framework/base/windowmanager/intent_tests/reorderToFront/reorder-to-front_with_new-task_on_different_affinity.json
index ab9ae9b..c783577 100644
--- a/tests/framework/base/windowmanager/intent_tests/reorderToFront/reorder-to-front_with_new-task_on_different_affinity.json
+++ b/tests/framework/base/windowmanager/intent_tests/reorderToFront/reorder-to-front_with_new-task_on_different_affinity.json
@@ -31,65 +31,51 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity2Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity2Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity2Activity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity2Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity2Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task.json b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task.json
index 5d5aae5..d306d86 100644
--- a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task.json
+++ b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task.json
@@ -18,41 +18,31 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$NoHistoryActivity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$NoHistoryActivity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$NoHistoryActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_reparent_affinity_in.json b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_reparent_affinity_in.json
index a4d1b7f..691d002 100644
--- a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_reparent_affinity_in.json
+++ b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_reparent_affinity_in.json
@@ -24,57 +24,43 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
},
"endState": {
- "stacks": [
- {
- "tasks": [
+ "tasks": [
+ {
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2",
- "state": "INITIALIZING"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity2",
+ "state": "INITIALIZING"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
- ]
+ ]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_reparent_affinity_in_and_out.json b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_reparent_affinity_in_and_out.json
index 86e0f65..a709c0d 100644
--- a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_reparent_affinity_in_and_out.json
+++ b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_reparent_affinity_in_and_out.json
@@ -36,85 +36,63 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity2",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity2Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity2Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
}
]
}
]
},
"endState": {
- "stacks": [
- {
- "tasks": [
- {
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
- }
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2"
- },
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity2",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
}
]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity2Activity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
+ }
+ ]
+ },
+ {
+ "activities": [
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity2Activity",
+ "state": "STOPPED"
}
]
}
- ]
+ ]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_with_new-task.json b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_with_new-task.json
index c059027..21ea454 100644
--- a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_with_new-task.json
+++ b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_with_new-task.json
@@ -18,37 +18,27 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_with_new-task_new_document.json b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_with_new-task_new_document.json
index 27931ba..a5d5e5e 100644
--- a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_with_new-task_new_document.json
+++ b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/reset-task_with_new-task_new_document.json
@@ -18,49 +18,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$NoHistoryActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$NoHistoryActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$NoHistoryActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-1.json b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-1.json
index 2cf1652..418ea7f 100644
--- a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-1.json
+++ b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-1.json
@@ -24,53 +24,39 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-2.json b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-2.json
index fc3634c..333cfbc 100644
--- a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-2.json
+++ b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-2.json
@@ -24,45 +24,35 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-3.json b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-3.json
index c89cdd3..ac7cbbe 100644
--- a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-3.json
+++ b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-3.json
@@ -30,77 +30,55 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
- }
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
- },
- {
- "tasks": [
- {
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
+ }
+ ]
+ },
+ {
+ "activities": [
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-4.json b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-4.json
index d8f3f7f..27f84bb 100644
--- a/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-4.json
+++ b/tests/framework/base/windowmanager/intent_tests/resetTaskIfNeeded/test-4.json
@@ -30,61 +30,47 @@
]
},
"initialState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2",
- "state": "RESUMED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity2",
+ "state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2"
+ ]
}
]
},
"endState": {
- "stacks": [
+ "tasks": [
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
- "state": "RESUMED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$RegularActivity",
+ "state": "RESUMED"
}
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+ ]
},
{
- "tasks": [
+ "activities": [
{
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity2",
- "state": "STOPPED"
- },
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity2",
+ "state": "STOPPED"
+ },
+ {
+ "name": "android.server.wm.cts/android.server.wm.intent.Activities$TaskAffinity1Activity",
+ "state": "STOPPED"
}
]
}
]
}
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java
index 5045810..608a760 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java
@@ -16,6 +16,7 @@
package android.server.wm;
+import static android.server.wm.app.Components.HOST_ACTIVITY;
import static android.server.wm.app.Components.UNRESPONSIVE_ACTIVITY;
import static android.server.wm.app.Components.UnresponsiveActivity;
import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_DELAY_UI_THREAD_MS;
@@ -26,8 +27,10 @@
import static org.junit.Assert.fail;
+import android.content.ComponentName;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
+import android.server.wm.app.Components.RenderService;
import android.provider.Settings;
import android.server.wm.settings.SettingsSession;
import android.support.test.uiautomator.By;
@@ -75,11 +78,13 @@
public void teardown() {
mHideDialogSetting.close();
stopTestPackage(UNRESPONSIVE_ACTIVITY.getPackageName());
+ stopTestPackage(HOST_ACTIVITY.getPackageName());
}
@Test
public void slowOnCreateWithKeyEventTriggersAnr() {
- startUnresponsiveActivity(EXTRA_ON_CREATE_DELAY_MS, false /* waitForCompletion */);
+ startUnresponsiveActivity(EXTRA_ON_CREATE_DELAY_MS, false /* waitForCompletion */,
+ UNRESPONSIVE_ACTIVITY);
// wait for app to be focused
mWmState.waitAndAssertAppFocus(UNRESPONSIVE_ACTIVITY.getPackageName(),
2000 /* waitTime_ms */);
@@ -93,7 +98,8 @@
@Test
public void slowUiThreadWithKeyEventTriggersAnr() {
- startUnresponsiveActivity(EXTRA_DELAY_UI_THREAD_MS, true /* waitForCompletion */);
+ startUnresponsiveActivity(EXTRA_DELAY_UI_THREAD_MS, true /* waitForCompletion */,
+ UNRESPONSIVE_ACTIVITY);
injectKey(KeyEvent.KEYCODE_BACK, false /* longpress */, false /* sync */);
clickCloseAppOnAnrDialog();
assertEventLogsContainsAnr(UnresponsiveActivity.PROCESS_NAME);
@@ -101,7 +107,8 @@
@Test
public void slowOnKeyEventHandleTriggersAnr() {
- startUnresponsiveActivity(EXTRA_ON_KEYDOWN_DELAY_MS, true /* waitForCompletion */);
+ startUnresponsiveActivity(EXTRA_ON_KEYDOWN_DELAY_MS, true /* waitForCompletion */,
+ UNRESPONSIVE_ACTIVITY);
injectKey(KeyEvent.KEYCODE_BACK, false /* longpress */, false /* sync */);
clickCloseAppOnAnrDialog();
assertEventLogsContainsAnr(UnresponsiveActivity.PROCESS_NAME);
@@ -109,7 +116,8 @@
@Test
public void slowOnTouchEventHandleTriggersAnr() {
- startUnresponsiveActivity(EXTRA_ON_MOTIONEVENT_DELAY_MS, true /* waitForCompletion */);
+ startUnresponsiveActivity(EXTRA_ON_MOTIONEVENT_DELAY_MS, true /* waitForCompletion */,
+ UNRESPONSIVE_ACTIVITY);
// TODO(b/143566069) investigate why we need multiple taps on display to trigger anr.
mWmState.computeState();
@@ -121,6 +129,24 @@
assertEventLogsContainsAnr(UnresponsiveActivity.PROCESS_NAME);
}
+ /**
+ * Verify embedded windows can trigger ANR and the verify embedded app is blamed.
+ */
+ @Test
+ public void embeddedWindowTriggersAnr() {
+ startUnresponsiveActivity(EXTRA_ON_MOTIONEVENT_DELAY_MS, true /* waitForCompletion */,
+ HOST_ACTIVITY);
+
+ // TODO(b/143566069) investigate why we need multiple taps on display to trigger anr.
+ mWmState.computeState();
+ tapOnDisplayCenterAsync(DEFAULT_DISPLAY);
+ SystemClock.sleep(1000);
+ tapOnDisplayCenterAsync(DEFAULT_DISPLAY);
+
+ clickCloseAppOnAnrDialog();
+ assertEventLogsContainsAnr(RenderService.PROCESS_NAME);
+ }
+
private void assertEventLogsContainsAnr(String processName) {
final List<EventLog.Event> events = getEventLogsForComponents(mLogSeparator,
android.util.EventLog.getTagCode("am_anr"));
@@ -147,9 +173,10 @@
fail("Could not find anr dialog");
}
- private void startUnresponsiveActivity(String delayTypeExtra, boolean waitForCompletion) {
+ private void startUnresponsiveActivity(String delayTypeExtra, boolean waitForCompletion,
+ ComponentName activity) {
String flags = waitForCompletion ? " -W -n " : " -n ";
- String startCmd = "am start" + flags + UNRESPONSIVE_ACTIVITY.flattenToString() +
+ String startCmd = "am start" + flags + activity.flattenToString() +
" --ei " + delayTypeExtra + " 30000";
executeShellCommand(startCmd);
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
index 16268d7..27d8121 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
@@ -21,8 +21,10 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.server.wm.CommandSession.ActivityCallback.ON_CONFIGURATION_CHANGED;
import static android.server.wm.ComponentNameUtils.getWindowName;
import static android.server.wm.StateLogger.logE;
import static android.server.wm.WindowManagerState.STATE_RESUMED;
@@ -32,6 +34,7 @@
import static android.server.wm.app.Components.LANDSCAPE_ORIENTATION_ACTIVITY;
import static android.server.wm.app.Components.LAUNCHING_ACTIVITY;
import static android.server.wm.app.Components.NIGHT_MODE_ACTIVITY;
+import static android.server.wm.app.Components.NO_RELAUNCH_ACTIVITY;
import static android.server.wm.app.Components.PORTRAIT_ORIENTATION_ACTIVITY;
import static android.server.wm.app.Components.RESIZEABLE_ACTIVITY;
import static android.server.wm.app.Components.TEST_ACTIVITY;
@@ -953,4 +956,58 @@
private SizeInfo getAppSizeInfo(ActivitySession activitySession) {
return activitySession.getAppConfigInfo().sizeInfo;
}
+
+ /**
+ * Verify that reported display sizes are different for multiple activities with different
+ * configurations running in the same process.
+ */
+ @Test
+ public void testDisplaySizeInSplitScreen() {
+ assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow());
+
+ // Launch two activities in split-screen
+ final ActivitySession primaryActivitySession = createManagedActivityClientSession()
+ .startActivity(getLaunchActivityBuilder()
+ .setUseInstrumentation()
+ .setTargetActivity(RESIZEABLE_ACTIVITY)
+ .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
+ .setWaitForLaunched(true));
+
+ final ActivitySession secondaryActivitySession = createManagedActivityClientSession()
+ .startActivity(getLaunchActivityBuilder()
+ .setUseInstrumentation()
+ .setNewTask(true)
+ .setMultipleTask(true)
+ .setTargetActivity(NO_RELAUNCH_ACTIVITY)
+ .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)
+ .setWaitForLaunched(true));
+
+ // Resize split-screen to make sure that sizes are not the same.
+ separateTestJournal();
+ final int STACK_SIZE = 400;
+ resizeDockedStack(STACK_SIZE, STACK_SIZE, STACK_SIZE, STACK_SIZE);
+
+ waitForOrFail("Activity must receive a configuration change",
+ () -> hasConfigChanged(primaryActivitySession));
+ waitForOrFail("Activity must receive a configuration change",
+ () -> hasConfigChanged(secondaryActivitySession));
+
+ // Check if the sizes reported to activities are different.
+ final SizeInfo primarySizeInfo = primaryActivitySession.getConfigInfo().sizeInfo;
+ final SizeInfo secondarySizeInfo = secondaryActivitySession.getConfigInfo().sizeInfo;
+ final SizeInfo appSizeInfo = secondaryActivitySession.getAppConfigInfo().sizeInfo;
+ // Second activity size info should match the application, since the process is tracking the
+ // configuration of the activity that was added last.
+ assertSizesAreSame(secondarySizeInfo, appSizeInfo);
+ // Primary and secondary activity sizes must be different, since the sizes of the windows
+ // after resize are different.
+ assertNotEquals(primarySizeInfo.displayWidth, secondarySizeInfo.displayWidth);
+ assertNotEquals(primarySizeInfo.displayHeight, secondarySizeInfo.displayHeight);
+ }
+
+ private boolean hasConfigChanged(ActivitySession activitySession) {
+ final List<CommandSession.ActivityCallback> callbackHistory =
+ activitySession.takeCallbackHistory();
+ return callbackHistory != null && callbackHistory.contains(ON_CONFIGURATION_CHANGED);
+ }
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MinimalPostProcessingTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MinimalPostProcessingTests.java
index cc49cf4..1c9f174 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MinimalPostProcessingTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MinimalPostProcessingTests.java
@@ -35,7 +35,6 @@
import org.junit.Test;
@Presubmit
-@FlakyTest(detail = "Promote once confirmed non-flaky")
public class MinimalPostProcessingTests extends ActivityManagerTestBase {
private static final boolean PREFER_MPP = true;
private static final boolean NOT_PREFER_MPP = false;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayLockedKeyguardTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayLockedKeyguardTests.java
index 7f5f871..cf1b454 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayLockedKeyguardTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayLockedKeyguardTests.java
@@ -135,7 +135,6 @@
mWmState.assertVisibility(DISMISS_KEYGUARD_ACTIVITY, true);
}
- @FlakyTest(bugId = 141674516)
@Test
public void testDismissKeyguard_whileOccluded_secondaryDisplay() {
final LockScreenSession lockScreenSession =
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
index 0b44b01..1f24b6b 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
@@ -36,6 +36,7 @@
import static android.server.wm.app.Components.NON_RESIZEABLE_ACTIVITY;
import static android.server.wm.app.Components.PIP_ACTIVITY;
import static android.server.wm.app.Components.PIP_ACTIVITY2;
+import static android.server.wm.app.Components.PIP_ACTIVITY_WITH_MINIMAL_SIZE;
import static android.server.wm.app.Components.PIP_ACTIVITY_WITH_SAME_AFFINITY;
import static android.server.wm.app.Components.PIP_ON_STOP_ACTIVITY;
import static android.server.wm.app.Components.PipActivity.ACTION_ENTER_PIP;
@@ -81,6 +82,8 @@
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.graphics.Rect;
@@ -120,9 +123,7 @@
private static final String TAG = PinnedStackTests.class.getSimpleName();
private static final String APP_OPS_OP_ENTER_PICTURE_IN_PICTURE = "PICTURE_IN_PICTURE";
- private static final int APP_OPS_MODE_ALLOWED = 0;
private static final int APP_OPS_MODE_IGNORED = 1;
- private static final int APP_OPS_MODE_ERRORED = 2;
private static final int ROTATION_0 = 0;
private static final int ROTATION_90 = 1;
@@ -247,6 +248,31 @@
assertPinnedStackActivityIsInDisplayBounds(PIP_ACTIVITY);
}
+ // TODO: launch/size pip to a size smaller than limitation and verify the minWidth/minHeight
+ // is respected after b/149338177.
+ @Test
+ public void testEnterPipWithMinimalSize() throws Exception {
+ // Launch a PiP activity with minimal size specified
+ launchActivity(PIP_ACTIVITY_WITH_MINIMAL_SIZE, EXTRA_ENTER_PIP, "true");
+ // Wait for animation complete since we are comparing size
+ waitForEnterPipAnimationComplete(PIP_ACTIVITY_WITH_MINIMAL_SIZE);
+ assertPinnedStackExists();
+
+ // query the minimal size
+ final PackageManager pm = getInstrumentation().getTargetContext().getPackageManager();
+ final ActivityInfo info = pm.getActivityInfo(
+ PIP_ACTIVITY_WITH_MINIMAL_SIZE, 0 /* flags */);
+ final Size minSize = new Size(info.windowLayout.minWidth, info.windowLayout.minHeight);
+
+ // compare the bounds with minimal size
+ final Rect pipBounds = getPinnedStackBounds();
+ assertTrue("Pinned stack bounds is no smaller than minimal",
+ (pipBounds.width() == minSize.getWidth()
+ && pipBounds.height() >= minSize.getHeight())
+ || (pipBounds.height() == minSize.getHeight()
+ && pipBounds.width() >= minSize.getWidth()));
+ }
+
@Test
public void testEnterPipAspectRatioMin() throws Exception {
testEnterPipAspectRatio(MIN_ASPECT_RATIO_NUMERATOR, MIN_ASPECT_RATIO_DENOMINATOR);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserActivity.java b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserActivity.java
index cb279219..a73521b 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserActivity.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserActivity.java
@@ -23,6 +23,7 @@
import android.app.Activity;
import android.os.Bundle;
import android.os.RemoteCallback;
+import android.os.UserHandle;
import android.util.Log;
public class StartActivityAsUserActivity extends Activity {
@@ -35,10 +36,10 @@
RemoteCallback cb = (RemoteCallback) extra.get(EXTRA_CALLBACK);
if (cb != null) {
Bundle result = new Bundle();
- result.putInt(KEY_USER_ID, getUserId());
+ result.putInt(KEY_USER_ID, UserHandle.myUserId());
cb.sendResult(result);
}
- Log.i(LOG_TAG, "Second activity started with user " + getUserId());
+ Log.i(LOG_TAG, "Second activity started with user " + UserHandle.myUserId());
finish();
}
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java
index 7f8aa01..5506e85 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java
@@ -61,7 +61,6 @@
* atest CtsWindowManagerDeviceTestCases:SurfaceControlViewHostTests
*/
@Presubmit
-@FlakyTest
public class SurfaceControlViewHostTests implements SurfaceHolder.Callback {
private final ActivityTestRule<Activity> mActivityRule = new ActivityTestRule<>(Activity.class);
@@ -117,7 +116,7 @@
mEmbeddedLayoutParams = new WindowManager.LayoutParams(width, height,
WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.OPAQUE);
- mVr.addView(v, mEmbeddedLayoutParams);
+ mVr.setView(v, mEmbeddedLayoutParams);
}
@Override
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
index 2ff0d87..957062b 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
@@ -73,7 +73,6 @@
* atest CtsWindowManagerDeviceTestCases:WindowInsetsAnimationTests
*/
@Presubmit
-@FlakyTest(detail = "Promote once confirmed non-flaky")
public class WindowInsetsAnimationTests extends WindowManagerTestBase {
TestActivity mActivity;
@@ -117,6 +116,7 @@
}
@Test
+ @FlakyTest(detail = "Promote once confirmed non-flaky")
public void testAnimationCallbacks_overlapping() {
WindowInsets before = mActivity.mLastWindowInsets;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/intent/LaunchRunner.java b/tests/framework/base/windowmanager/src/android/server/wm/intent/LaunchRunner.java
index 9e1d67a..badb526 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/intent/LaunchRunner.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/intent/LaunchRunner.java
@@ -20,7 +20,7 @@
import static android.server.wm.intent.StateComparisonException.assertEndStatesEqual;
import static android.server.wm.intent.StateComparisonException.assertInitialStateEqual;
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.google.common.collect.Iterables.getLast;
@@ -71,11 +71,11 @@
* The activities that were already present in the system when the test started.
* So they can be removed form the outputs, otherwise our tests would be system dependent.
*/
- private List<WindowManagerState.ActivityTask> mBaseStacks;
+ private List<WindowManagerState.ActivityTask> mBaseTasks;
public LaunchRunner(IntentTestBase testBase) {
mTestBase = testBase;
- mBaseStacks = getBaseStacks();
+ mBaseTasks = getBaseTasks();
}
/**
@@ -106,7 +106,7 @@
// assert that the state after setup is the same this time as the recorded state.
StateDump setupStateDump = waitDumpAndTrimForVerification(getLast(activityLog),
- testCase.getEndState());
+ testCase.getInitialState());
assertInitialStateEqual(testCase.getInitialState(), setupStateDump);
// apply all the intents in the act stage
@@ -281,8 +281,8 @@
/**
* After the last activity has been launched we wait for a valid state + an extra three seconds
- * so have a stable state of the system. Also all previously known stacks in
- * {@link LaunchRunner#mBaseStacks} is excluded from the output.
+ * so have a stable state of the system. Also all previously known tasks in
+ * {@link LaunchRunner#mBaseTasks} is excluded from the output.
*
* @param activity The last activity to be launched before dumping the state.
* @return A stable {@link StateDump}, meaning no more {@link android.app.Activity} is in a
@@ -294,9 +294,9 @@
// lifecycle state. wait an extra 3 seconds for it to settle
SystemClock.sleep(BEFORE_DUMP_TIMEOUT);
mTestBase.getWmState().computeState(activity.getComponentName());
- List<WindowManagerState.ActivityTask> endStateStacks =
+ List<WindowManagerState.ActivityTask> endStateTasks =
mTestBase.getWmState().getRootTasks();
- return StateDump.fromStacks(endStateStacks, mBaseStacks);
+ return StateDump.fromTasks(endStateTasks, mBaseTasks);
}
/**
@@ -312,21 +312,18 @@
*/
public StateDump waitDumpAndTrimForVerification(Activity activity, StateDump expected) {
mTestBase.getWmState().waitForValidState(activity.getComponentName());
- // The last activity that was launched before the dump could still be in an intermediate
- // lifecycle state. wait an extra 3 seconds for it to settle
- SystemClock.sleep(BEFORE_DUMP_TIMEOUT);
mTestBase.getWmState().waitForWithAmState(
- am -> StateDump.fromStacks(am.getRootTasks(), mBaseStacks).equals(expected),
+ am -> StateDump.fromTasks(am.getRootTasks(), mBaseTasks).equals(expected),
"the activity states match up with what we recorded");
mTestBase.getWmState().computeState(activity.getComponentName());
- List<WindowManagerState.ActivityTask> endStateStacks =
+ List<WindowManagerState.ActivityTask> endStateTasks =
mTestBase.getWmState().getRootTasks();
- return StateDump.fromStacks(endStateStacks, mBaseStacks);
+ return StateDump.fromTasks(endStateTasks, mBaseTasks);
}
- private List<WindowManagerState.ActivityTask> getBaseStacks() {
+ private List<WindowManagerState.ActivityTask> getBaseTasks() {
WindowManagerStateHelper amWmState = mTestBase.getWmState();
amWmState.computeState(new ComponentName[]{});
return amWmState.getRootTasks();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/intent/Persistence.java b/tests/framework/base/windowmanager/src/android/server/wm/intent/Persistence.java
index f3ab41a..5d80e32 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/intent/Persistence.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/intent/Persistence.java
@@ -440,54 +440,57 @@
}
public static class StateDump {
- final List<StackState> mStacks;
+ private static final String TASKS_KEY = "tasks";
- public static StateDump fromStacks(List<WindowManagerState.ActivityTask> activityTasks,
+ /**
+ * The Tasks in this stack ordered from most recent to least recent.
+ */
+ private final List<TaskState> mTasks;
+
+ public static StateDump fromTasks(List<WindowManagerState.ActivityTask> activityTasks,
List<WindowManagerState.ActivityTask> baseStacks) {
- List<StackState> stacks = new ArrayList<>();
- for (WindowManagerState.ActivityTask stack : trimStacks(activityTasks,
- baseStacks)) {
- stacks.add(new StackState(stack));
+ List<TaskState> tasks = new ArrayList<>();
+ for (WindowManagerState.ActivityTask task : trimTasks(activityTasks, baseStacks)) {
+ tasks.add(new TaskState(task));
}
-
- return new StateDump(stacks);
+ return new StateDump(tasks);
}
- public StateDump(List<StackState> stacks) {
- mStacks = stacks;
+ private StateDump(List<TaskState> tasks) {
+ mTasks = tasks;
}
JSONObject toJson() throws JSONException {
- JSONArray stacks = new JSONArray();
- for (StackState stack : mStacks) {
- stacks.put(stack.toJson());
+ JSONArray tasks = new JSONArray();
+ for (TaskState task : mTasks) {
+ tasks.put(task.toJson());
}
- return new JSONObject().put("stacks", stacks);
+ return new JSONObject().put(TASKS_KEY, tasks);
}
static StateDump fromJson(JSONObject object) throws JSONException {
- JSONArray jsonTasks = object.getJSONArray("stacks");
- List<StackState> stacks = new ArrayList<>();
+ JSONArray jsonTasks = object.getJSONArray(TASKS_KEY);
+ List<TaskState> tasks = new ArrayList<>();
for (int i = 0; i < jsonTasks.length(); i++) {
- stacks.add(StackState.fromJson((JSONObject) jsonTasks.get(i)));
+ tasks.add(TaskState.fromJson((JSONObject) jsonTasks.get(i)));
}
- return new StateDump(stacks);
+ return new StateDump(tasks);
}
/**
- * To make the state dump non device specific we remove every stack that was present
- * in the system before recording, by their ID. For example a stack containing the launcher
+ * To make the state dump non device specific we remove every task that was present
+ * in the system before recording, by their ID. For example a task containing the launcher
* activity.
*/
- public static List<WindowManagerState.ActivityTask> trimStacks(
+ public static List<WindowManagerState.ActivityTask> trimTasks(
List<WindowManagerState.ActivityTask> toTrim,
List<WindowManagerState.ActivityTask> trimFrom) {
- for (WindowManagerState.ActivityTask stack : trimFrom) {
- toTrim.removeIf(t -> t.getRootTaskId() == stack.getRootTaskId());
+ for (WindowManagerState.ActivityTask task : trimFrom) {
+ toTrim.removeIf(t -> t.getRootTaskId() == task.getRootTaskId());
}
return toTrim;
@@ -498,103 +501,49 @@
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StateDump stateDump = (StateDump) o;
- return Objects.equals(mStacks, stateDump.mStacks);
+ return Objects.equals(mTasks, stateDump.mTasks);
}
@Override
public int hashCode() {
- return Objects.hash(mStacks);
- }
- }
-
- /**
- * A simplified JSON version of the information in {@link WindowManagerState.ActivityTask}
- */
- public static class StackState {
- private static final String TASKS_KEY = "tasks";
- private static final String RESUMED_ACTIVITY_KEY = "resumedActivity";
-
- /**
- * The component name of the resumedActivity in this Stack, empty string if there is none.
- */
- private final String mResumedActivity;
- /**
- * The Tasks in this stack ordered from most recent to least recent.
- */
- private final List<TaskState> mTasks;
-
- public StackState(String resumedActivity, List<TaskState> tasks) {
- mResumedActivity = resumedActivity;
- mTasks = tasks;
- }
-
- public StackState(WindowManagerState.ActivityTask stack) {
- this.mResumedActivity = stack.getResumedActivity();
- mTasks = new ArrayList<>();
- for (WindowManagerState.ActivityTask task : stack.getTasks()) {
- this.mTasks.add(new TaskState(task));
- }
- }
-
- JSONObject toJson() throws JSONException {
- JSONArray jsonTasks = new JSONArray();
-
- for (TaskState task : mTasks) {
- jsonTasks.put(task.toJson());
- }
-
- return new JSONObject()
- .put(TASKS_KEY, jsonTasks)
- .put(RESUMED_ACTIVITY_KEY, mResumedActivity);
- }
-
- static StackState fromJson(JSONObject object) throws JSONException {
- JSONArray jsonTasks = object.getJSONArray(TASKS_KEY);
- List<TaskState> tasks = new ArrayList<>();
-
- for (int i = 0; i < jsonTasks.length(); i++) {
- tasks.add(TaskState.fromJson((JSONObject) jsonTasks.get(i)));
- }
-
- return new StackState(object.optString(RESUMED_ACTIVITY_KEY, ""), tasks);
- }
-
- public String getResumedActivity() {
- return mResumedActivity;
- }
-
- public List<TaskState> getTasks() {
- return mTasks;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- StackState stack = (StackState) o;
- return Objects.equals(mTasks, stack.mTasks);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mResumedActivity, mTasks);
+ return Objects.hash(mTasks);
}
}
public static class TaskState {
+ private static final String STATE_RESUMED = "RESUMED";
private static final String ACTIVITIES_KEY = "activities";
/**
+ * The component name of the resumedActivity in this state, empty string if there is none.
+ */
+ private final String mResumedActivity;
+
+ /**
* The activities in this task ordered from most recent to least recent.
*/
- private List<ActivityState> mActivities = new ArrayList<>();
+ private final List<ActivityState> mActivities = new ArrayList<>();
- public TaskState(List<ActivityState> activities) {
- mActivities = activities;
+ private TaskState(JSONArray jsonActivities) throws JSONException {
+ String resumedActivity = "";
+ for (int i = 0; i < jsonActivities.length(); i++) {
+ final ActivityState activity =
+ ActivityState.fromJson((JSONObject) jsonActivities.get(i));
+ // The json file shouldn't define multiple resumed activities, but it is fine that
+ // the test will fail when comparing to the real state.
+ if (STATE_RESUMED.equals(activity.getState())) {
+ resumedActivity = activity.getName();
+ }
+ mActivities.add(activity);
+ }
+
+ mResumedActivity = resumedActivity;
}
public TaskState(WindowManagerState.ActivityTask state) {
+ final String resumedActivity = state.getResumedActivity();
+ mResumedActivity = resumedActivity != null ? resumedActivity : "";
for (WindowManagerState.Activity activity : state.getActivities()) {
this.mActivities.add(new ActivityState(activity));
}
@@ -612,14 +561,7 @@
}
static TaskState fromJson(JSONObject object) throws JSONException {
- JSONArray jsonActivities = object.getJSONArray(ACTIVITIES_KEY);
- List<ActivityState> activities = new ArrayList<>();
-
- for (int i = 0; i < jsonActivities.length(); i++) {
- activities.add(ActivityState.fromJson((JSONObject) jsonActivities.get(i)));
- }
-
- return new TaskState(activities);
+ return new TaskState(object.getJSONArray(ACTIVITIES_KEY));
}
public List<ActivityState> getActivities() {
@@ -631,12 +573,13 @@
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TaskState task = (TaskState) o;
- return Objects.equals(mActivities, task.mActivities);
+ return Objects.equals(mResumedActivity, task.mResumedActivity)
+ && Objects.equals(mActivities, task.mActivities);
}
@Override
public int hashCode() {
- return Objects.hash(mActivities);
+ return Objects.hash(mResumedActivity, mActivities);
}
}
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index 8fbb635..e1ecc13 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -546,26 +546,25 @@
}
/**
- * Move around center of the specific display to ensures the display to be focused without
- * triggering potential clicked event to impact the test environment.
+ * Insert an input event (ACTION_DOWN -> ACTION_CANCEL) to ensures the display to be focused
+ * without triggering potential clicked to impact the test environment.
* (e.g: Keyguard credential activated unexpectedly.)
*
* @param displayId the display ID to gain focused by inject swipe action
*/
- protected void moveAroundCenterSync(int displayId) {
+ protected void touchAndCancelOnDisplayCenterSync(int displayId) {
final Rect bounds = mWmState.getDisplay(displayId).getDisplayRect();
+ final int x = bounds.left + bounds.width() / 2;
+ final int y = bounds.top + bounds.height() / 2;
final long downTime = SystemClock.uptimeMillis();
+ injectMotion(downTime, downTime, MotionEvent.ACTION_DOWN, x, y, displayId, true /* sync */);
+
+ final long eventTime = SystemClock.uptimeMillis();
final int touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
- final int downX = bounds.left + bounds.width() / 2;
- final int downY = bounds.top + bounds.height() / 2;
- injectMotion(downTime, downTime, MotionEvent.ACTION_DOWN, downX, downY, displayId, true);
-
- final int moveX = downX + Float.floatToIntBits(touchSlop / 2.0f);
- final int moveY = downY + Float.floatToIntBits(touchSlop / 2.0f);
- injectMotion(downTime, downTime, MotionEvent.ACTION_MOVE, moveX, moveY, displayId, true);
-
- final long upTime = SystemClock.uptimeMillis();
- injectMotion(downTime, upTime, MotionEvent.ACTION_UP, moveX, moveY, displayId, true);
+ final int tapX = x + Math.round(touchSlop / 2.0f);
+ final int tapY = y + Math.round(touchSlop / 2.0f);
+ injectMotion(downTime, eventTime, MotionEvent.ACTION_CANCEL, tapX, tapY, displayId,
+ true /* sync */);
}
protected void tapOnDisplaySync(int x, int y, int displayId) {
@@ -1238,7 +1237,7 @@
public LockScreenSession enterAndConfirmLockCredential() {
// Ensure focus will switch to default display. Meanwhile we cannot tap on center area,
// which may tap on input credential area.
- moveAroundCenterSync(DEFAULT_DISPLAY);
+ touchAndCancelOnDisplayCenterSync(DEFAULT_DISPLAY);
waitForDeviceIdle(3000);
SystemUtil.runWithShellPermissionIdentity(() ->
@@ -1280,7 +1279,7 @@
LockScreenSession unlockDevice() {
// Make sure the unlock button event is send to the default display.
- moveAroundCenterSync(DEFAULT_DISPLAY);
+ touchAndCancelOnDisplayCenterSync(DEFAULT_DISPLAY);
pressUnlockButton();
return this;
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
index e373a62..3f3ac8f 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
@@ -905,7 +905,7 @@
return false;
}
- /** Check if at least one window which matches provided window name is visible. */
+ /** Check if at least one window which matches the specified name has shown it's surface. */
boolean isWindowSurfaceShown(String windowName) {
for (WindowState window : mWindowStates) {
if (window.getName().equals(windowName)) {
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeEventStreamTestUtils.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeEventStreamTestUtils.java
index cee89d8..f08633f 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeEventStreamTestUtils.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeEventStreamTestUtils.java
@@ -291,6 +291,19 @@
}
/**
+ * Checks if {@code eventName} has occurred and given {@param key} has value {@param value}.
+ * @param eventName event name to check.
+ * @param key the key that should be checked.
+ * @param value the expected value for the given {@param key}.
+ */
+ public static void expectEventWithKeyValue(@NonNull ImeEventStream stream,
+ @NonNull String eventName, @NonNull String key, int value, long timeout)
+ throws TimeoutException {
+ expectEvent(stream, event -> TextUtils.equals(eventName, event.getEventName())
+ && value == event.getArguments().getInt(key), timeout);
+ }
+
+ /**
* Waits until {@code MockIme} does not send {@code "onInputViewLayoutChanged"} event
* for a certain period of time ({@code stableThresholdTime} msec).
*
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 6142b9e..3a814db 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
@@ -286,6 +286,8 @@
case "getDisplayId":
return getSystemService(WindowManager.class)
.getDefaultDisplay().getDisplayId();
+ case "verifyLayoutInflaterContext":
+ return getLayoutInflater().getContext() == this;
}
}
return ImeEvent.RETURN_VALUE_UNAVAILABLE;
@@ -408,14 +410,17 @@
private static final class KeyboardLayoutView extends LinearLayout {
@NonNull
+ private final MockIme mMockIme;
+ @NonNull
private final ImeSettings mSettings;
@NonNull
private final View.OnLayoutChangeListener mLayoutListener;
- KeyboardLayoutView(Context context, @NonNull ImeSettings imeSettings,
+ KeyboardLayoutView(MockIme mockIme, @NonNull ImeSettings imeSettings,
@Nullable Consumer<ImeLayoutInfo> onInputViewLayoutChangedCallback) {
- super(context);
+ super(mockIme);
+ mMockIme = mockIme;
mSettings = imeSettings;
setOrientation(VERTICAL);
@@ -509,6 +514,13 @@
}
@Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ mMockIme.getTracer().onWindowVisibilityChanged(() -> {
+ super.onWindowVisibilityChanged(visibility);
+ }, visibility);
+ }
+
+ @Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
removeOnLayoutChangeListener(mLayoutListener);
@@ -859,6 +871,12 @@
recordEventInternal("onStartInput", runnable, arguments);
}
+ public void onWindowVisibilityChanged(@NonNull Runnable runnable, int visibility) {
+ final Bundle arguments = new Bundle();
+ arguments.putInt("visible", visibility);
+ recordEventInternal("onWindowVisibilityChanged", runnable, arguments);
+ }
+
public void onStartInputView(EditorInfo editorInfo, boolean restarting,
@NonNull Runnable runnable) {
final Bundle arguments = new Bundle();
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
index 5e653c6..a407a28 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
@@ -982,4 +982,18 @@
final Bundle params = new Bundle();
return callCommandInternal("getDisplayId", params);
}
+
+ /**
+ * Verifies {@code InputMethodService.getLayoutInflater().getContext()} is equal to
+ * {@code InputMethodService.this}.
+ *
+ * @return {@link ImeCommand} object that can be passed to
+ * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
+ * wait until this event is handled by {@link MockIme}
+ */
+ @NonNull
+ public ImeCommand verifyLayoutInflaterContext() {
+ final Bundle params = new Bundle();
+ return callCommandInternal("verifyLayoutInflaterContext", params);
+ }
}
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/FocusHandlingTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/FocusHandlingTest.java
index ca17cdf..5a2c8c2 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/FocusHandlingTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/FocusHandlingTest.java
@@ -16,6 +16,7 @@
package android.view.inputmethod.cts;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE;
import static android.view.inputmethod.cts.util.TestUtils.runOnMainSync;
@@ -499,6 +500,63 @@
}
}
+ @Test
+ public void testKeyboardStateAfterImeFocusableFlagChanged() throws Exception {
+ final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ try (MockImeSession imeSession = MockImeSession.create(
+ instrumentation.getContext(), instrumentation.getUiAutomation(),
+ new ImeSettings.Builder())) {
+ final ImeEventStream stream = imeSession.openEventStream();
+ final AtomicReference<EditText> editTextRef = new AtomicReference<>();
+ final String marker = getTestMarker();
+ final TestActivity testActivity = TestActivity.startSync(activity-> {
+ // Initially set activity window to not IME focusable.
+ activity.getWindow().addFlags(FLAG_ALT_FOCUSABLE_IM);
+
+ final LinearLayout layout = new LinearLayout(activity);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+ final EditText editText = new EditText(activity);
+ editText.setPrivateImeOptions(marker);
+ editText.setHint("editText");
+ editTextRef.set(editText);
+ editText.requestFocus();
+
+ layout.addView(editText);
+ return layout;
+ });
+ // Wait until the MockIme gets bound to the TestActivity.
+ expectBindInput(stream, Process.myPid(), TIMEOUT);
+
+ // Emulate tap event, expect there is no "onStartInput", and "showSoftInput" happened.
+ final EditText editText = editTextRef.get();
+ CtsTouchUtils.emulateTapOnViewCenter(instrumentation, null, editText);
+ notExpectEvent(stream, editorMatcher("onStartInput", marker), NOT_EXPECT_TIMEOUT);
+ notExpectEvent(stream, event -> "showSoftInput".equals(event.getEventName()),
+ NOT_EXPECT_TIMEOUT);
+
+ // Set testActivity window to be IME focusable.
+ testActivity.getWindow().getDecorView().post(() -> {
+ final WindowManager.LayoutParams params = testActivity.getWindow().getAttributes();
+ testActivity.getWindow().clearFlags(FLAG_ALT_FOCUSABLE_IM);
+ editTextRef.get().requestFocus();
+ });
+
+ // Make sure test activity's window has changed to be IME focusable.
+ TestUtils.waitOnMainUntil(() -> WindowManager.LayoutParams.mayUseInputMethod(
+ testActivity.getWindow().getAttributes().flags), TIMEOUT);
+
+ // Emulate tap event again.
+ CtsTouchUtils.emulateTapOnViewCenter(instrumentation, null, editText);
+ assertTrue(TestUtils.getOnMainSync(() -> editText.hasFocus()
+ && editText.hasWindowFocus()));
+
+ // "onStartInput", and "showSoftInput" must happen when editText became IME focusable.
+ expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
+ expectEvent(stream, event -> "showSoftInput".equals(event.getEventName()), TIMEOUT);
+ }
+ }
+
private static class ServiceSession implements ServiceConnection, AutoCloseable {
private final Context mContext;
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionsRequestTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionsRequestTest.java
index d8db007..429aee0 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionsRequestTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionsRequestTest.java
@@ -20,6 +20,7 @@
import static org.testng.Assert.assertThrows;
+import android.os.LocaleList;
import android.os.Parcel;
import android.util.Size;
import android.view.inline.InlinePresentationSpec;
@@ -32,7 +33,6 @@
import org.junit.runner.RunWith;
import java.util.ArrayList;
-import android.os.LocaleList;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -58,6 +58,23 @@
}
@Test
+ public void testEmptyPresentationSpecsThrowsException() {
+ assertThrows(IllegalStateException.class,
+ () -> new InlineSuggestionsRequest.Builder(new ArrayList<>())
+ .setMaxSuggestionCount(1).build());
+ }
+
+ @Test
+ public void testZeroMaxSuggestionCountThrowsException() {
+ ArrayList<InlinePresentationSpec> presentationSpecs = new ArrayList<>();
+ presentationSpecs.add(new InlinePresentationSpec.Builder(new Size(100, 100),
+ new Size(400, 100)).build());
+ assertThrows(IllegalStateException.class,
+ () -> new InlineSuggestionsRequest.Builder(presentationSpecs)
+ .setMaxSuggestionCount(0).build());
+ }
+
+ @Test
public void testInlineSuggestionsRequestValues() {
final int suggestionCount = 3;
ArrayList<InlinePresentationSpec> presentationSpecs = new ArrayList<>();
@@ -81,6 +98,8 @@
@Test
public void testInlineSuggestionsRequestParcelizeDeparcelize() {
ArrayList<InlinePresentationSpec> presentationSpecs = new ArrayList<>();
+ presentationSpecs.add(
+ new InlinePresentationSpec.Builder(new Size(100, 100), new Size(400, 400)).build());
InlineSuggestionsRequest request =
new InlineSuggestionsRequest.Builder(presentationSpecs).build();
Parcel p = Parcel.obtain();
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java
index 0b20b85..e518f87 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java
@@ -23,6 +23,7 @@
import static android.view.inputmethod.cts.util.TestUtils.waitOnMainUntil;
import static com.android.cts.mockime.ImeEventStreamTestUtils.EventFilterMode.CHECK_EXIT_EVENT_ONLY;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEventWithKeyValue;
import static com.android.cts.mockime.ImeEventStreamTestUtils.editorMatcher;
import static com.android.cts.mockime.ImeEventStreamTestUtils.expectCommand;
import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
@@ -40,6 +41,7 @@
import android.text.TextUtils;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
+import android.view.View;
import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
@@ -116,6 +118,24 @@
});
}
+ @Test
+ public void verifyLayoutInflaterContext() throws Exception {
+ try (MockImeSession imeSession = MockImeSession.create(
+ InstrumentationRegistry.getContext(),
+ InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+ new ImeSettings.Builder())) {
+ final ImeEventStream stream = imeSession.openEventStream();
+
+ createTestActivity(SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ expectEvent(stream, event -> "onStartInputView".equals(event.getEventName()), TIMEOUT);
+
+ final ImeCommand command = imeSession.verifyLayoutInflaterContext();
+ assertTrue("InputMethodService.getLayoutInflater().getContext() must be equal to"
+ + " InputMethodService.this",
+ expectCommand(stream, command, TIMEOUT).getReturnBooleanValue());
+ }
+ }
+
private void verifyImeConsumesBackButton(int backDisposition) throws Exception {
try (MockImeSession imeSession = MockImeSession.create(
InstrumentationRegistry.getContext(),
@@ -181,6 +201,8 @@
imeSession.callRequestHideSelf(0);
expectEvent(stream, event -> "hideSoftInput".equals(event.getEventName()), TIMEOUT);
expectEvent(stream, event -> "onFinishInputView".equals(event.getEventName()), TIMEOUT);
+ expectEventWithKeyValue(stream, "onWindowVisibilityChanged", "visible",
+ View.GONE, TIMEOUT);
}
}
@@ -199,6 +221,8 @@
imeSession.callRequestShowSelf(0);
expectEvent(stream, event -> "showSoftInput".equals(event.getEventName()), TIMEOUT);
expectEvent(stream, event -> "onStartInputView".equals(event.getEventName()), TIMEOUT);
+ expectEventWithKeyValue(stream, "onWindowVisibilityChanged", "visible",
+ View.VISIBLE, TIMEOUT);
}
}
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
index aa5b695..77ad52e 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
@@ -19,6 +19,7 @@
import static android.view.inputmethod.cts.util.TestUtils.getOnMainSync;
import static android.view.inputmethod.cts.util.TestUtils.runOnMainSync;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEventWithKeyValue;
import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
import static com.android.cts.mockime.ImeEventStreamTestUtils.notExpectEvent;
@@ -28,6 +29,7 @@
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Pair;
+import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodManager;
@@ -155,6 +157,8 @@
expectEvent(stream, showSoftInputMatcher(InputMethod.SHOW_EXPLICIT), TIMEOUT);
expectEvent(stream, editorMatcher("onStartInputView", marker), TIMEOUT);
+ expectEventWithKeyValue(stream, "onWindowVisibilityChanged", "visible",
+ View.VISIBLE, TIMEOUT);
// Test hideSoftInputFromWindow() flow
assertTrue("hideSoftInputFromWindow must success if the View has IME focus",
@@ -162,6 +166,8 @@
expectEvent(stream, hideSoftInputMatcher(), TIMEOUT);
expectEvent(stream, onFinishInputViewMatcher(false), TIMEOUT);
+ expectEventWithKeyValue(stream, "onWindowVisibilityChanged", "visible",
+ View.GONE, TIMEOUT);
}
}
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/SearchViewTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/SearchViewTest.java
index 5cf8fd0..2b327f5 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/SearchViewTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/SearchViewTest.java
@@ -19,15 +19,20 @@
import static com.android.cts.mockime.ImeEventStreamTestUtils.EventFilterMode.CHECK_EXIT_EVENT_ONLY;
import static com.android.cts.mockime.ImeEventStreamTestUtils.expectBindInput;
import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.notExpectEvent;
import android.os.Process;
import android.text.InputType;
+import android.view.View;
+import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.cts.util.EndToEndImeTestBase;
import android.view.inputmethod.cts.util.TestActivity;
+import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.LinearLayout;
+import android.widget.ListView;
import android.widget.SearchView;
import androidx.test.InstrumentationRegistry;
@@ -49,6 +54,7 @@
@RunWith(AndroidJUnit4.class)
public class SearchViewTest extends EndToEndImeTestBase {
static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
+ static final long NOT_EXPECT_TIMEOUT = TimeUnit.SECONDS.toMillis(2);
public SearchView launchTestActivity(boolean requestFocus) {
final AtomicReference<SearchView> searchViewRef = new AtomicReference<>();
@@ -77,6 +83,32 @@
return searchViewRef.get();
}
+ private SearchView launchTestActivityWithListView(boolean requestFocus) {
+ final AtomicReference<SearchView> searchViewRef = new AtomicReference<>();
+ TestActivity.startSync(activity -> {
+ final LinearLayout layout = new LinearLayout(activity);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+ final ListView listView = new ListView(activity);
+ layout.addView(listView);
+
+ final SearchView searchView = new SearchView(activity);
+ searchViewRef.set(searchView);
+ listView.setAdapter(new SingleItemAdapter(searchView));
+
+ searchView.setQueryHint("hint");
+ searchView.setIconifiedByDefault(false);
+ searchView.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
+ searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
+ if (requestFocus) {
+ searchView.requestFocus();
+ }
+
+ return layout;
+ });
+ return searchViewRef.get();
+ }
+
@Test
public void testTapThenSetQuery() throws Exception {
try (MockImeSession imeSession = MockImeSession.create(
@@ -132,4 +164,60 @@
CHECK_EXIT_EVENT_ONLY, TIMEOUT);
}
}
+
+ @Test
+ public void testShowImeWhenSearchViewFocusInListView() throws Exception {
+ try (MockImeSession imeSession = MockImeSession.create(
+ InstrumentationRegistry.getContext(),
+ InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+ new ImeSettings.Builder())) {
+ final ImeEventStream stream = imeSession.openEventStream();
+
+ final SearchView searchView = launchTestActivityWithListView(true /* requestFocus */);
+
+ // Emulate tap event on SearchView
+ CtsTouchUtils.emulateTapOnViewCenter(
+ InstrumentationRegistry.getInstrumentation(), null, searchView);
+
+ // Expect input to bind since EditText is focused.
+ expectBindInput(stream, Process.myPid(), TIMEOUT);
+
+ // Wait until "showSoftInput" gets called with a real InputConnection
+ expectEvent(stream, event ->
+ "showSoftInput".equals(event.getEventName())
+ && !event.getExitState().hasDummyInputConnection(),
+ CHECK_EXIT_EVENT_ONLY, TIMEOUT);
+
+ notExpectEvent(stream, event -> "hideSoftInput".equals(event.getEventName()),
+ NOT_EXPECT_TIMEOUT);
+ }
+ }
+
+ static final class SingleItemAdapter extends BaseAdapter {
+ private final SearchView mSearchView;
+
+ SingleItemAdapter(SearchView searchView) {
+ mSearchView = searchView;
+ }
+
+ @Override
+ public int getCount() {
+ return 1;
+ }
+
+ @Override
+ public Object getItem(int i) {
+ return mSearchView;
+ }
+
+ @Override
+ public long getItemId(int i) {
+ return 0;
+ }
+
+ @Override
+ public View getView(int i, View view, ViewGroup viewGroup) {
+ return mSearchView;
+ }
+ }
}
diff --git a/tests/location/location_fine/src/android/location/cts/fine/GnssMeasurementTest.java b/tests/location/location_fine/src/android/location/cts/fine/GnssMeasurementTest.java
index dccf022..2536890 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/GnssMeasurementTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/GnssMeasurementTest.java
@@ -100,13 +100,13 @@
measurement.resetBasebandCn0DbHz();
assertFalse(measurement.hasBasebandCn0DbHz());
- assertTrue(measurement.hasReceiverInterSignalBiasNanos());
- measurement.resetReceiverInterSignalBiasNanos();
- assertFalse(measurement.hasReceiverInterSignalBiasNanos());
+ assertTrue(measurement.hasFullInterSignalBiasNanos());
+ measurement.resetFullInterSignalBiasNanos();
+ assertFalse(measurement.hasFullInterSignalBiasNanos());
- assertTrue(measurement.hasReceiverInterSignalBiasUncertaintyNanos());
- measurement.resetReceiverInterSignalBiasUncertaintyNanos();
- assertFalse(measurement.hasReceiverInterSignalBiasUncertaintyNanos());
+ assertTrue(measurement.hasFullInterSignalBiasUncertaintyNanos());
+ measurement.resetFullInterSignalBiasUncertaintyNanos();
+ assertFalse(measurement.hasFullInterSignalBiasUncertaintyNanos());
assertTrue(measurement.hasSatelliteInterSignalBiasNanos());
measurement.resetSatelliteInterSignalBiasNanos();
@@ -134,8 +134,8 @@
measurement.setPseudorangeRateUncertaintyMetersPerSecond(10.0);
measurement.setReceivedSvTimeNanos(11);
measurement.setReceivedSvTimeUncertaintyNanos(12);
- measurement.setReceiverInterSignalBiasNanos(1.3);
- measurement.setReceiverInterSignalBiasUncertaintyNanos(2.5);
+ measurement.setFullInterSignalBiasNanos(1.3);
+ measurement.setFullInterSignalBiasUncertaintyNanos(2.5);
measurement.setSatelliteInterSignalBiasNanos(5.4);
measurement.setSatelliteInterSignalBiasUncertaintyNanos(10.0);
measurement.setSnrInDb(13.0);
@@ -162,8 +162,8 @@
assertEquals(10.0, measurement.getPseudorangeRateUncertaintyMetersPerSecond(), DELTA);
assertEquals(11, measurement.getReceivedSvTimeNanos());
assertEquals(12, measurement.getReceivedSvTimeUncertaintyNanos());
- assertEquals(1.3, measurement.getReceiverInterSignalBiasNanos(), DELTA);
- assertEquals(2.5, measurement.getReceiverInterSignalBiasUncertaintyNanos(), DELTA);
+ assertEquals(1.3, measurement.getFullInterSignalBiasNanos(), DELTA);
+ assertEquals(2.5, measurement.getFullInterSignalBiasUncertaintyNanos(), DELTA);
assertEquals(5.4, measurement.getSatelliteInterSignalBiasNanos(), DELTA);
assertEquals(10.0, measurement.getSatelliteInterSignalBiasUncertaintyNanos(), DELTA);
assertEquals(13.0, measurement.getSnrInDb(), DELTA);
diff --git a/tests/quickaccesswallet/AndroidManifest.xml b/tests/quickaccesswallet/AndroidManifest.xml
index 3d2ad69..4ad90ab 100755
--- a/tests/quickaccesswallet/AndroidManifest.xml
+++ b/tests/quickaccesswallet/AndroidManifest.xml
@@ -24,10 +24,6 @@
<uses-permission android:name="android.permission.NFC"/>
<!-- Required to test QuickAccessWalletClient feature availability -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
- <uses-permission android:name="android.permission.MANAGE_USERS" />
- <uses-permission android:name="android.permission.CREATE_USERS" />
- <!-- Required to bind to the QuickAccessWalletService -->
- <uses-permission android:name="android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE" />
<application>
<uses-library android:name="android.test.runner" />
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 0ca1fc9..0d834cd 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
@@ -687,6 +687,8 @@
mUsageStatsManager.getAppStandbyBucket(mTargetPackage));
}
+ // TODO(148887416): get this test to work for instant apps
+ @AppModeFull(reason = "Test APK Activity not found when installed as an instant app")
@Test
public void testIsAppInactive_Charging() throws Exception {
setStandByBucket(TEST_APP_PKG, "rare");
diff --git a/tests/tests/appenumeration/AndroidTest.xml b/tests/tests/appenumeration/AndroidTest.xml
index 8db021f..85f1477 100644
--- a/tests/tests/appenumeration/AndroidTest.xml
+++ b/tests/tests/appenumeration/AndroidTest.xml
@@ -29,6 +29,10 @@
<option name="test-file-name" value="CtsAppEnumerationForceQueryable.apk" />
<option name="test-file-name" value="CtsAppEnumerationFilters.apk" />
<option name="test-file-name" value="CtsAppEnumerationNoApi.apk" />
+ <option name="test-file-name" value="CtsAppEnumerationContactsActivityTarget.apk" />
+ <option name="test-file-name" value="CtsAppEnumerationDocumentsActivityTarget.apk" />
+ <option name="test-file-name" value="CtsAppEnumerationShareActivityTarget.apk" />
+ <option name="test-file-name" value="CtsAppEnumerationWebActivityTarget.apk" />
<option name="test-file-name" value="CtsAppEnumerationSharedUidSource.apk" />
<option name="test-file-name" value="CtsAppEnumerationSharedUidTarget.apk" />
<option name="test-file-name" value="CtsAppEnumerationQueriesNothing.apk" />
@@ -42,6 +46,11 @@
<option name="test-file-name" value="CtsAppEnumerationQueriesPackage.apk" />
<option name="test-file-name" value="CtsAppEnumerationQueriesNothingTargetsQ.apk" />
<option name="test-file-name" value="CtsAppEnumerationQueriesNothingHasPermission.apk" />
+ <option name="test-file-name" value="CtsAppEnumerationWildcardBrowsableActivitySource.apk" />
+ <option name="test-file-name" value="CtsAppEnumerationWildcardContactsActivitySource.apk" />
+ <option name="test-file-name" value="CtsAppEnumerationWildcardDocumentEditorActivitySource.apk" />
+ <option name="test-file-name" value="CtsAppEnumerationWildcardShareActivitySource.apk" />
+ <option name="test-file-name" value="CtsAppEnumerationWildcardWebActivitySource.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.appenumeration.cts" />
diff --git a/tests/tests/appenumeration/app/source/Android.bp b/tests/tests/appenumeration/app/source/Android.bp
index f215e77..1da65f6 100644
--- a/tests/tests/appenumeration/app/source/Android.bp
+++ b/tests/tests/appenumeration/app/source/Android.bp
@@ -161,4 +161,64 @@
"vts",
"general-tests",
],
+}
+
+android_test_helper_app {
+ name: "CtsAppEnumerationWildcardBrowsableActivitySource",
+ manifest: "AndroidManifest-queriesWildcard-browsableActivity.xml",
+ defaults: ["CtsAppEnumerationQueriesDefaults"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsAppEnumerationWildcardContactsActivitySource",
+ manifest: "AndroidManifest-queriesWildcard-contactsActivity.xml",
+ defaults: ["CtsAppEnumerationQueriesDefaults"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsAppEnumerationWildcardDocumentEditorActivitySource",
+ manifest: "AndroidManifest-queriesWildcard-documentEditorActivity.xml",
+ defaults: ["CtsAppEnumerationQueriesDefaults"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsAppEnumerationWildcardShareActivitySource",
+ manifest: "AndroidManifest-queriesWildcard-shareActivity.xml",
+ defaults: ["CtsAppEnumerationQueriesDefaults"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsAppEnumerationWildcardWebActivitySource",
+ manifest: "AndroidManifest-queriesWildcard-webActivity.xml",
+ defaults: ["CtsAppEnumerationQueriesDefaults"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
}
\ No newline at end of file
diff --git a/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-browsableActivity.xml b/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-browsableActivity.xml
new file mode 100644
index 0000000..8cf6bfe
--- /dev/null
+++ b/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-browsableActivity.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.appenumeration.queries.wildcard.browsable">
+
+ <queries>
+ <intent>
+ <action android:name="*" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="*" android:host="*" />
+ </intent>
+ </queries>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.appenumeration.cts.query.TestActivity"
+ android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-contactsActivity.xml b/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-contactsActivity.xml
new file mode 100644
index 0000000..a51d7f4
--- /dev/null
+++ b/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-contactsActivity.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.appenumeration.queries.wildcard.contacts">
+
+ <queries>
+ <intent>
+ <action android:name="android.intent.action.VIEW" />
+ <data android:scheme="content"
+ android:host="com.android.contacts"
+ android:mimeType="vnd.android.cursor.item/*" />
+ </intent>
+ </queries>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.appenumeration.cts.query.TestActivity"
+ android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-documentEditorActivity.xml b/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-documentEditorActivity.xml
new file mode 100644
index 0000000..1bfa17e
--- /dev/null
+++ b/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-documentEditorActivity.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.appenumeration.queries.wildcard.editor">
+
+ <queries>
+ <intent>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:mimeType="*/*" />
+ </intent>
+ </queries>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.appenumeration.cts.query.TestActivity"
+ android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/tests/appop/AppWithLongFeatureId/AndroidManifest.xml b/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-shareActivity.xml
similarity index 61%
copy from tests/tests/appop/AppWithLongFeatureId/AndroidManifest.xml
copy to tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-shareActivity.xml
index 17d10e9..57efc78 100644
--- a/tests/tests/appop/AppWithLongFeatureId/AndroidManifest.xml
+++ b/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-shareActivity.xml
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
-
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
@@ -17,9 +16,18 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.app.appops.cts.appwithlongfeatureId">
- <feature android:featureId="1xxxx_xxxx2xxxx_xxxx3xxxx_xxxx4xxxx_xxxx5xxxx_xxxxB" android:label="@string/dummyLabel" />
+ package="android.appenumeration.queries.wildcard.share">
- <application />
+ <queries>
+ <intent>
+ <action android:name="android.intent.action.SEND" />
+ <data android:mimeType="image/jpeg" />
+ </intent>
+ </queries>
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.appenumeration.cts.query.TestActivity"
+ android:exported="true" />
+ </application>
</manifest>
diff --git a/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-webActivity.xml b/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-webActivity.xml
new file mode 100644
index 0000000..3355c35
--- /dev/null
+++ b/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-webActivity.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.appenumeration.queries.wildcard.web">
+
+ <queries>
+ <intent>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" android:host="*"/>
+ </intent>
+ <intent>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="https" android:host="*"/>
+ </intent>
+ </queries>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.appenumeration.cts.query.TestActivity"
+ android:exported="true" />
+ </application>
+</manifest>
diff --git a/tests/tests/appenumeration/app/target/Android.bp b/tests/tests/appenumeration/app/target/Android.bp
index 54f6662..277cb8a 100644
--- a/tests/tests/appenumeration/app/target/Android.bp
+++ b/tests/tests/appenumeration/app/target/Android.bp
@@ -66,4 +66,60 @@
"general-tests",
],
sdk_version: "test_current",
-}
\ No newline at end of file
+}
+
+android_test_helper_app {
+ name: "CtsAppEnumerationContactsActivityTarget",
+ manifest: "AndroidManifest-contactsActivity.xml",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+ sdk_version: "test_current",
+}
+
+android_test_helper_app {
+ name: "CtsAppEnumerationDocumentsActivityTarget",
+ manifest: "AndroidManifest-documentEditorActivity.xml",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+ sdk_version: "test_current",
+}
+
+android_test_helper_app {
+ name: "CtsAppEnumerationShareActivityTarget",
+ manifest: "AndroidManifest-shareActivity.xml",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+ sdk_version: "test_current",
+}
+
+android_test_helper_app {
+ name: "CtsAppEnumerationWebActivityTarget",
+ manifest: "AndroidManifest-webActivity.xml",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+ sdk_version: "test_current",
+}
diff --git a/tests/tests/appenumeration/app/target/AndroidManifest-contactsActivity.xml b/tests/tests/appenumeration/app/target/AndroidManifest-contactsActivity.xml
new file mode 100644
index 0000000..e31d018
--- /dev/null
+++ b/tests/tests/appenumeration/app/target/AndroidManifest-contactsActivity.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.appenumeration.contacts.activity">
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.appenumeration.ContactsActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="content"/>
+ <data android:host="com.android.contacts"/>
+ <data android:mimeType="vnd.android.cursor.item/vnd.android.appenumeration.contacts"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/tests/appenumeration/app/target/AndroidManifest-documentEditorActivity.xml b/tests/tests/appenumeration/app/target/AndroidManifest-documentEditorActivity.xml
new file mode 100644
index 0000000..445f90b
--- /dev/null
+++ b/tests/tests/appenumeration/app/target/AndroidManifest-documentEditorActivity.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.appenumeration.editor.activity">
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.appenumeration.EditorActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW"/>
+ <action android:name="android.intent.action.EDIT"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:mimeType="application/vnd.oasis.opendocument.text"/>
+ <data android:mimeType="application/rtf"/>
+ <data android:mimeType="text/rtf"/>
+ <data android:mimeType="text/plain"/>
+ <data android:mimeType="application/pdf"/>
+ <data android:mimeType="application/x-pdf"/>
+ </intent-filter>
+ </activity>
+
+ </application>
+</manifest>
diff --git a/tests/tests/appenumeration/app/target/AndroidManifest-filters.xml b/tests/tests/appenumeration/app/target/AndroidManifest-filters.xml
index 82e356f..5a91ba1 100644
--- a/tests/tests/appenumeration/app/target/AndroidManifest-filters.xml
+++ b/tests/tests/appenumeration/app/target/AndroidManifest-filters.xml
@@ -19,7 +19,10 @@
package="android.appenumeration.filters">
<application>
<uses-library android:name="android.test.runner" />
- <activity android:name="android.appenumeration.testapp.DummyActivity">
+ <activity android:name="android.appenumeration.testapp.DummyActivity"
+ android:visibleToInstantApps="true">
+ <!-- Marked visible to instant apps to ensure this logic doesn't conflict with non
+ instant filtering -->
<intent-filter>
<action android:name="android.appenumeration.action.ACTIVITY" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/tests/tests/appop/AppWithLongFeatureId/AndroidManifest.xml b/tests/tests/appenumeration/app/target/AndroidManifest-shareActivity.xml
similarity index 60%
copy from tests/tests/appop/AppWithLongFeatureId/AndroidManifest.xml
copy to tests/tests/appenumeration/app/target/AndroidManifest-shareActivity.xml
index 17d10e9..87f621a 100644
--- a/tests/tests/appop/AppWithLongFeatureId/AndroidManifest.xml
+++ b/tests/tests/appenumeration/app/target/AndroidManifest-shareActivity.xml
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
-
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
@@ -17,9 +16,15 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.app.appops.cts.appwithlongfeatureId">
- <feature android:featureId="1xxxx_xxxx2xxxx_xxxx3xxxx_xxxx4xxxx_xxxx5xxxx_xxxxB" android:label="@string/dummyLabel" />
-
- <application />
-
+ package="android.appenumeration.share.activity">
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.appenumeration.ShareActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.SEND"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:mimeType="*/*"/>
+ </intent-filter>
+ </activity>
+ </application>
</manifest>
diff --git a/tests/tests/appenumeration/app/target/AndroidManifest-webActivity.xml b/tests/tests/appenumeration/app/target/AndroidManifest-webActivity.xml
new file mode 100644
index 0000000..e198ea5
--- /dev/null
+++ b/tests/tests/appenumeration/app/target/AndroidManifest-webActivity.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.appenumeration.web.activity">
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.appenumeration.WebActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW"/>
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="http" android:host="appenumeration.android"/>
+ <data android:scheme="https" android:host="appenumeration.android"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java b/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java
index 1afcc65..a189ce3 100644
--- a/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java
+++ b/tests/tests/appenumeration/lib/src/android/appenumeration/cts/Constants.java
@@ -46,6 +46,17 @@
public static final String QUERIES_NOTHING_SHARED_USER = PKG_BASE + "queries.nothing.shareduid";
/** A package that queries via wildcard action. */
public static final String QUERIES_WILDCARD_ACTION = PKG_BASE + "queries.wildcard.action";
+ /** A package that queries for all BROWSABLE intents. */
+ public static final String QUERIES_WILDCARD_BROWSABLE = PKG_BASE + "queries.wildcard.browsable";
+ /** A package that queries for all profile / contact targets. */
+ public static final String QUERIES_WILDCARD_CONTACTS = PKG_BASE + "queries.wildcard.contacts";
+ /** A package that queries for document viewer / editor targets. */
+ public static final String QUERIES_WILDCARD_EDITOR = PKG_BASE + "queries.wildcard.editor";
+ /** A package that queries for all jpeg share targets. */
+ public static final String QUERIES_WILDCARD_SHARE = PKG_BASE + "queries.wildcard.share";
+ /** A package that queries for all web intent browsable targets. */
+ public static final String QUERIES_WILDCARD_WEB = PKG_BASE + "queries.wildcard.web";
+
/** A package that queries for {@link #TARGET_NO_API} package */
public static final String TARGET_SHARED_USER = PKG_BASE + "noapi.shareduid";
/** A package that exposes itself via various intent filters (activities, services, etc.) */
@@ -54,8 +65,16 @@
public static final String TARGET_FORCEQUERYABLE = PKG_BASE + "forcequeryable";
/** A package with no published API and so isn't queryable by anything but package name */
public static final String TARGET_NO_API = PKG_BASE + "noapi";
+ /** A package that offers an activity used for opening / editing file types */
+ public static final String TARGET_EDITOR = PKG_BASE + "editor.activity";
+ /** A package that offers an activity used viewing a contact / profile */
+ public static final String TARGET_CONTACTS = PKG_BASE + "contacts.activity";
+ /** A package that offers an content sharing activity */
+ public static final String TARGET_SHARE = PKG_BASE + "share.activity";
+ /** A package that offers an activity that handles browsable web intents for a specific host */
+ public static final String TARGET_WEB = PKG_BASE + "web.activity";
- public static final String[] ALL_QUERIES_TARGETING_Q_PACKAGES = {
+ public static final String[] ALL_QUERIES_TARGETING_R_PACKAGES = {
QUERIES_NOTHING,
QUERIES_NOTHING_PERM,
QUERIES_ACTIVITY_ACTION,
@@ -66,7 +85,12 @@
QUERIES_UNEXPORTED_PROVIDER_AUTH,
QUERIES_PACKAGE,
QUERIES_NOTHING_SHARED_USER,
- QUERIES_WILDCARD_ACTION
+ QUERIES_WILDCARD_ACTION,
+ QUERIES_WILDCARD_BROWSABLE,
+ QUERIES_WILDCARD_CONTACTS,
+ QUERIES_WILDCARD_EDITOR,
+ QUERIES_WILDCARD_SHARE,
+ QUERIES_WILDCARD_WEB,
};
public static final String ACTIVITY_CLASS_TEST = PKG_BASE + "cts.query.TestActivity";
diff --git a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
index 3f624ee..4fa2bd4 100644
--- a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
+++ b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
@@ -28,7 +28,7 @@
import static android.appenumeration.cts.Constants.ACTION_START_FOR_RESULT;
import static android.appenumeration.cts.Constants.ACTIVITY_CLASS_DUMMY_ACTIVITY;
import static android.appenumeration.cts.Constants.ACTIVITY_CLASS_TEST;
-import static android.appenumeration.cts.Constants.ALL_QUERIES_TARGETING_Q_PACKAGES;
+import static android.appenumeration.cts.Constants.ALL_QUERIES_TARGETING_R_PACKAGES;
import static android.appenumeration.cts.Constants.EXTRA_ERROR;
import static android.appenumeration.cts.Constants.EXTRA_FLAGS;
import static android.appenumeration.cts.Constants.EXTRA_REMOTE_CALLBACK;
@@ -44,10 +44,19 @@
import static android.appenumeration.cts.Constants.QUERIES_UNEXPORTED_PROVIDER_AUTH;
import static android.appenumeration.cts.Constants.QUERIES_UNEXPORTED_SERVICE_ACTION;
import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_ACTION;
+import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_BROWSABLE;
+import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_CONTACTS;
+import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_EDITOR;
+import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_SHARE;
+import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_WEB;
+import static android.appenumeration.cts.Constants.TARGET_CONTACTS;
+import static android.appenumeration.cts.Constants.TARGET_EDITOR;
import static android.appenumeration.cts.Constants.TARGET_FILTERS;
import static android.appenumeration.cts.Constants.TARGET_FORCEQUERYABLE;
import static android.appenumeration.cts.Constants.TARGET_NO_API;
+import static android.appenumeration.cts.Constants.TARGET_SHARE;
import static android.appenumeration.cts.Constants.TARGET_SHARED_USER;
+import static android.appenumeration.cts.Constants.TARGET_WEB;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static org.hamcrest.Matchers.greaterThan;
@@ -326,6 +335,31 @@
assertVisible(QUERIES_PACKAGE, QUERIES_NOTHING_SHARED_USER);
}
+ @Test
+ public void queriesWildcardContacts() throws Exception {
+ assertNotVisible(QUERIES_NOTHING, TARGET_CONTACTS);
+ assertVisible(QUERIES_WILDCARD_CONTACTS, TARGET_CONTACTS);
+ }
+
+ @Test
+ public void queriesWildcardWeb() throws Exception {
+ assertNotVisible(QUERIES_NOTHING, TARGET_WEB);
+ assertVisible(QUERIES_WILDCARD_BROWSABLE, TARGET_WEB);
+ assertVisible(QUERIES_WILDCARD_WEB, TARGET_WEB);
+ }
+
+ @Test
+ public void queriesWildcardEditor() throws Exception {
+ assertNotVisible(QUERIES_NOTHING, TARGET_EDITOR);
+ assertVisible(QUERIES_WILDCARD_EDITOR, TARGET_EDITOR);
+ }
+
+ @Test
+ public void queriesWildcardShareSheet() throws Exception {
+ assertNotVisible(QUERIES_NOTHING, TARGET_SHARE);
+ assertVisible(QUERIES_WILDCARD_SHARE, TARGET_SHARE);
+ }
+
private void assertVisible(String sourcePackageName, String targetPackageName)
throws Exception {
if (!sGlobalFeatureEnabled) return;
@@ -335,7 +369,7 @@
private void setFeatureEnabledForAll(Boolean enabled) {
- for (String pkgName : ALL_QUERIES_TARGETING_Q_PACKAGES) {
+ for (String pkgName : ALL_QUERIES_TARGETING_R_PACKAGES) {
setFeatureEnabledForAll(pkgName, enabled);
}
setFeatureEnabledForAll(QUERIES_NOTHING_Q, enabled == null ? null : false);
diff --git a/tests/tests/appop/AndroidManifest.xml b/tests/tests/appop/AndroidManifest.xml
index ab36586..0c89b6e 100644
--- a/tests/tests/appop/AndroidManifest.xml
+++ b/tests/tests/appop/AndroidManifest.xml
@@ -19,11 +19,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.app.appops.cts"
android:targetSandboxVersion="2">
- <feature android:featureId="testFeature" android:label="@string/dummyLabel" />
- <feature android:featureId="firstFeature" android:label="@string/dummyLabel" />
- <feature android:featureId="secondFeature" android:label="@string/dummyLabel" />
- <feature android:featureId="firstProxyFeature" android:label="@string/dummyLabel" />
- <feature android:featureId="secondProxyFeature" android:label="@string/dummyLabel" />
+ <attribution android:tag="testAttribution" android:label="@string/dummyLabel" />
+ <attribution android:tag="firstAttribution" android:label="@string/dummyLabel" />
+ <attribution android:tag="secondAttribution" android:label="@string/dummyLabel" />
+ <attribution android:tag="firstProxyAttribution" android:label="@string/dummyLabel" />
+ <attribution android:tag="secondProxyAttribution" android:label="@string/dummyLabel" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
diff --git a/tests/tests/appop/AndroidTest.xml b/tests/tests/appop/AndroidTest.xml
index a911b20..386feb4 100644
--- a/tests/tests/appop/AndroidTest.xml
+++ b/tests/tests/appop/AndroidTest.xml
@@ -37,12 +37,12 @@
<option name="push-file" key="CtsAppToBlame1.apk" value="/data/local/tmp/cts/appops/CtsAppToBlame1.apk" />
<option name="push-file" key="CtsAppToBlame2.apk" value="/data/local/tmp/cts/appops/CtsAppToBlame2.apk" />
<option name="push-file" key="CtsAppToCollect.apk" value="/data/local/tmp/cts/appops/CtsAppToCollect.apk" />
- <option name="push-file" key="AppWithDuplicateFeature.apk" value="/data/local/tmp/cts/appops/AppWithDuplicateFeature.apk" />
- <option name="push-file" key="AppWithFeatureInheritingFromExisting.apk" value="/data/local/tmp/cts/appops/AppWithFeatureInheritingFromExisting.apk" />
- <option name="push-file" key="AppWithFeatureInheritingFromSameAsOther.apk" value="/data/local/tmp/cts/appops/AppWithFeatureInheritingFromSameAsOther.apk" />
- <option name="push-file" key="AppWithFeatureInheritingFromSelf.apk" value="/data/local/tmp/cts/appops/AppWithFeatureInheritingFromSelf.apk" />
- <option name="push-file" key="AppWithLongFeatureIdFeature.apk" value="/data/local/tmp/cts/appops/AppWithLongFeatureIdFeature.apk" />
- <option name="push-file" key="AppWithTooManyFeatures.apk" value="/data/local/tmp/cts/appops/AppWithTooManyFeatures.apk" />
+ <option name="push-file" key="AppWithDuplicateAttribution.apk" value="/data/local/tmp/cts/appops/AppWithDuplicateAttribution.apk" />
+ <option name="push-file" key="AppWithAttributionInheritingFromExisting.apk" value="/data/local/tmp/cts/appops/AppWithAttributionInheritingFromExisting.apk" />
+ <option name="push-file" key="AppWithAttributionInheritingFromSameAsOther.apk" value="/data/local/tmp/cts/appops/AppWithAttributionInheritingFromSameAsOther.apk" />
+ <option name="push-file" key="AppWithAttributionInheritingFromSelf.apk" value="/data/local/tmp/cts/appops/AppWithAttributionInheritingFromSelf.apk" />
+ <option name="push-file" key="AppWithLongAttributionTag.apk" value="/data/local/tmp/cts/appops/AppWithLongAttributionTag.apk" />
+ <option name="push-file" key="AppWithTooManyAttributions.apk" value="/data/local/tmp/cts/appops/AppWithTooManyAttributions.apk" />
</target_preparer>
<!-- Remove additional apps if installed -->
diff --git a/tests/tests/appop/AppThatUsesAppOps/AndroidManifest.xml b/tests/tests/appop/AppThatUsesAppOps/AndroidManifest.xml
index e3e4937..df614d8 100644
--- a/tests/tests/appop/AppThatUsesAppOps/AndroidManifest.xml
+++ b/tests/tests/appop/AppThatUsesAppOps/AndroidManifest.xml
@@ -18,7 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.app.appops.cts.appthatusesappops">
- <feature android:featureId="testFeature" android:label="@string/dummyLabel" />
+ <attribution android:tag="testAttribution" android:label="@string/dummyLabel" />
<application>
<service android:name=".AppOpsUserService" android:exported="true" />
diff --git a/tests/tests/appop/AppThatUsesAppOps/res/values/strings.xml b/tests/tests/appop/AppThatUsesAppOps/res/values/strings.xml
index 2d02f14..37d548d 100644
--- a/tests/tests/appop/AppThatUsesAppOps/res/values/strings.xml
+++ b/tests/tests/appop/AppThatUsesAppOps/res/values/strings.xml
@@ -16,5 +16,5 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="dummyLabel">A feature</string>
+ <string name="dummyLabel">An attribution</string>
</resources>
diff --git a/tests/tests/appop/AppThatUsesAppOps/src/android/app/appops/cts/appthatusesappops/AppOpsUserService.kt b/tests/tests/appop/AppThatUsesAppOps/src/android/app/appops/cts/appthatusesappops/AppOpsUserService.kt
index fb87058..ba98da1 100644
--- a/tests/tests/appop/AppThatUsesAppOps/src/android/app/appops/cts/appthatusesappops/AppOpsUserService.kt
+++ b/tests/tests/appop/AppThatUsesAppOps/src/android/app/appops/cts/appthatusesappops/AppOpsUserService.kt
@@ -25,7 +25,7 @@
import android.app.SyncNotedAppOp
import android.app.appops.cts.IAppOpsUserClient
import android.app.appops.cts.IAppOpsUserService
-import android.app.appops.cts.TEST_FEATURE_ID
+import android.app.appops.cts.TEST_ATTRIBUTION_TAG
import android.app.appops.cts.eventually
import android.content.Intent
import android.os.IBinder
@@ -136,7 +136,7 @@
forwardThrowableFrom {
client.noteSyncOp()
- assertThat(noted.map { it.first.featureId to it.first.op })
+ assertThat(noted.map { it.first.attributionTag to it.first.op })
.containsExactly(null to OPSTR_COARSE_LOCATION)
assertThat(noted[0].second.map { it.methodName })
.contains("callApiThatNotesSyncOpAndCheckLog")
@@ -159,11 +159,14 @@
}
}
- override fun callApiThatNotesSyncOpWithFeatureAndCheckLog(client: IAppOpsUserClient) {
+ override fun callApiThatNotesSyncOpWithAttributionAndCheckLog(
+ client: IAppOpsUserClient
+ ) {
forwardThrowableFrom {
- client.noteSyncOpWithFeature(TEST_FEATURE_ID)
+ client.noteSyncOpWithAttribution(TEST_ATTRIBUTION_TAG)
- assertThat(noted.map { it.first.featureId }).containsExactly(TEST_FEATURE_ID)
+ assertThat(noted.map { it.first.attributionTag })
+ .containsExactly(TEST_ATTRIBUTION_TAG)
}
}
@@ -340,7 +343,7 @@
client.noteAsyncOp()
eventually {
- assertThat(asyncNoted.map { it.featureId to it.op })
+ assertThat(asyncNoted.map { it.attributionTag to it.op })
.containsExactly(null to OPSTR_COARSE_LOCATION)
}
assertThat(noted).isEmpty()
@@ -348,15 +351,15 @@
}
}
- override fun callApiThatNotesAsyncOpWithFeatureAndCheckLog(
+ override fun callApiThatNotesAsyncOpWithAttributionAndCheckLog(
client: IAppOpsUserClient
) {
forwardThrowableFrom {
- client.noteAsyncOpWithFeature(TEST_FEATURE_ID)
+ client.noteAsyncOpWithAttribution(TEST_ATTRIBUTION_TAG)
eventually {
- assertThat(asyncNoted.map { it.featureId })
- .containsExactly(TEST_FEATURE_ID)
+ assertThat(asyncNoted.map { it.attributionTag })
+ .containsExactly(TEST_ATTRIBUTION_TAG)
}
}
}
diff --git a/tests/tests/appop/AppToBlame1/AndroidManifest.xml b/tests/tests/appop/AppToBlame1/AndroidManifest.xml
index 55db16b..a8d3638 100644
--- a/tests/tests/appop/AppToBlame1/AndroidManifest.xml
+++ b/tests/tests/appop/AppToBlame1/AndroidManifest.xml
@@ -19,11 +19,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.app.appops.cts.apptoblame"
android:version="1">
- <feature android:featureId="feature1" android:label="@string/dummyLabel" />
- <feature android:featureId="feature2" android:label="@string/dummyLabel" />
- <feature android:featureId="feature3" android:label="@string/dummyLabel" />
- <feature android:featureId="feature4" android:label="@string/dummyLabel" />
- <feature android:featureId="feature5" android:label="@string/dummyLabel" />
+ <attribution android:tag="attribution1" android:label="@string/dummyLabel" />
+ <attribution android:tag="attribution2" android:label="@string/dummyLabel" />
+ <attribution android:tag="attribution3" android:label="@string/dummyLabel" />
+ <attribution android:tag="attribution4" android:label="@string/dummyLabel" />
+ <attribution android:tag="attribution5" android:label="@string/dummyLabel" />
<application />
diff --git a/tests/tests/appop/AppToBlame2/AndroidManifest.xml b/tests/tests/appop/AppToBlame2/AndroidManifest.xml
index 96a490c..ba13fd6 100644
--- a/tests/tests/appop/AppToBlame2/AndroidManifest.xml
+++ b/tests/tests/appop/AppToBlame2/AndroidManifest.xml
@@ -19,14 +19,14 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.app.appops.cts.apptoblame"
android:version="2">
- <feature android:featureId="feature1" android:label="@string/dummyLabel" />
- <feature android:featureId="feature6" android:label="@string/dummyLabel">
- <inherit-from android:featureId="feature2" />
- </feature>
- <feature android:featureId="feature7" android:label="@string/dummyLabel">
- <inherit-from android:featureId="feature4" />
- <inherit-from android:featureId="feature5" />
- </feature>
+ <attribution android:tag="attribution1" android:label="@string/dummyLabel" />
+ <attribution android:tag="attribution6" android:label="@string/dummyLabel">
+ <inherit-from android:tag="attribution2" />
+ </attribution>
+ <attribution android:tag="attribution7" android:label="@string/dummyLabel">
+ <inherit-from android:tag="attribution4" />
+ <inherit-from android:tag="attribution5" />
+ </attribution>
<application />
diff --git a/tests/tests/appop/AppToCollect/AndroidManifest.xml b/tests/tests/appop/AppToCollect/AndroidManifest.xml
index e67cb57..2a0d18d 100644
--- a/tests/tests/appop/AppToCollect/AndroidManifest.xml
+++ b/tests/tests/appop/AppToCollect/AndroidManifest.xml
@@ -19,7 +19,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.app.appops.cts.apptocollect"
android:version="1">
- <feature android:featureId="testFeature" android:label="@string/dummyLabel" />
+ <attribution android:tag="testAttribution" android:label="@string/dummyLabel" />
<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>
diff --git a/tests/tests/appop/AppWithDuplicateFeature/Android.bp b/tests/tests/appop/AppWithAttributionInheritingFromExisting/Android.bp
similarity index 92%
copy from tests/tests/appop/AppWithDuplicateFeature/Android.bp
copy to tests/tests/appop/AppWithAttributionInheritingFromExisting/Android.bp
index a27dacb..2b07c3b 100644
--- a/tests/tests/appop/AppWithDuplicateFeature/Android.bp
+++ b/tests/tests/appop/AppWithAttributionInheritingFromExisting/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
android_test_helper_app {
- name: "AppWithDuplicateFeature",
+ name: "AppWithAttributionInheritingFromExisting",
test_suites: [
"cts",
diff --git a/tests/tests/appop/AppWithFeatureInheritingFromExisting/AndroidManifest.xml b/tests/tests/appop/AppWithAttributionInheritingFromExisting/AndroidManifest.xml
similarity index 72%
rename from tests/tests/appop/AppWithFeatureInheritingFromExisting/AndroidManifest.xml
rename to tests/tests/appop/AppWithAttributionInheritingFromExisting/AndroidManifest.xml
index eb097ef..6b1798b 100644
--- a/tests/tests/appop/AppWithFeatureInheritingFromExisting/AndroidManifest.xml
+++ b/tests/tests/appop/AppWithAttributionInheritingFromExisting/AndroidManifest.xml
@@ -17,11 +17,11 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.app.appops.cts.appwithfeatureinheritingfromexisting">
- <feature android:featureId="feature1" android:label="@string/dummyLabel" />
- <feature android:featureId="feature2" android:label="@string/dummyLabel">
- <inherit-from android:featureId="feature1" />
- </feature>
+ package="android.app.appops.cts.appwithattributioninheritingfromexisting">
+ <attribution android:tag="attribution" android:label="@string/dummyLabel" />
+ <attribution android:tag="attribution2" android:label="@string/dummyLabel">
+ <inherit-from android:tag="attribution" />
+ </attribution>
<application />
diff --git a/tests/tests/appop/AppWithFeatureInheritingFromExisting/res/values/strings.xml b/tests/tests/appop/AppWithAttributionInheritingFromExisting/res/values/strings.xml
similarity index 100%
rename from tests/tests/appop/AppWithFeatureInheritingFromExisting/res/values/strings.xml
rename to tests/tests/appop/AppWithAttributionInheritingFromExisting/res/values/strings.xml
diff --git a/tests/tests/appop/AppWithDuplicateFeature/Android.bp b/tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/Android.bp
similarity index 92%
copy from tests/tests/appop/AppWithDuplicateFeature/Android.bp
copy to tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/Android.bp
index a27dacb..7de79e5 100644
--- a/tests/tests/appop/AppWithDuplicateFeature/Android.bp
+++ b/tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
android_test_helper_app {
- name: "AppWithDuplicateFeature",
+ name: "AppWithAttributionInheritingFromSameAsOther",
test_suites: [
"cts",
diff --git a/tests/tests/appop/AppWithDuplicateFeature/AndroidManifest.xml b/tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/AndroidManifest.xml
similarity index 67%
copy from tests/tests/appop/AppWithDuplicateFeature/AndroidManifest.xml
copy to tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/AndroidManifest.xml
index b7b5297..fcf47a5 100644
--- a/tests/tests/appop/AppWithDuplicateFeature/AndroidManifest.xml
+++ b/tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/AndroidManifest.xml
@@ -17,9 +17,13 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.app.appops.cts.appwithduplicatefeature">
- <feature android:featureId="feature1" android:label="@string/dummyLabel" />
- <feature android:featureId="feature1" android:label="@string/dummyLabel" />
+ package="android.app.appops.cts.appwithattributioninheritingfromsameasother">
+ <attribution android:tag="attribution1" android:label="@string/dummyLabel">
+ <inherit-from android:tag="attribution3" />
+ </attribution>
+ <attribution android:tag="attribution2" android:label="@string/dummyLabel">
+ <inherit-from android:tag="attribution3" />
+ </attribution>
<application />
diff --git a/tests/tests/appop/AppWithFeatureInheritingFromSameAsOther/res/values/strings.xml b/tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/res/values/strings.xml
similarity index 100%
rename from tests/tests/appop/AppWithFeatureInheritingFromSameAsOther/res/values/strings.xml
rename to tests/tests/appop/AppWithAttributionInheritingFromSameAsOther/res/values/strings.xml
diff --git a/tests/tests/appop/AppWithDuplicateFeature/Android.bp b/tests/tests/appop/AppWithAttributionInheritingFromSelf/Android.bp
similarity index 93%
copy from tests/tests/appop/AppWithDuplicateFeature/Android.bp
copy to tests/tests/appop/AppWithAttributionInheritingFromSelf/Android.bp
index a27dacb..4a6e524 100644
--- a/tests/tests/appop/AppWithDuplicateFeature/Android.bp
+++ b/tests/tests/appop/AppWithAttributionInheritingFromSelf/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
android_test_helper_app {
- name: "AppWithDuplicateFeature",
+ name: "AppWithAttributionInheritingFromSelf",
test_suites: [
"cts",
diff --git a/tests/tests/appop/AppWithDuplicateFeature/AndroidManifest.xml b/tests/tests/appop/AppWithAttributionInheritingFromSelf/AndroidManifest.xml
similarity index 77%
copy from tests/tests/appop/AppWithDuplicateFeature/AndroidManifest.xml
copy to tests/tests/appop/AppWithAttributionInheritingFromSelf/AndroidManifest.xml
index b7b5297..3cb4712 100644
--- a/tests/tests/appop/AppWithDuplicateFeature/AndroidManifest.xml
+++ b/tests/tests/appop/AppWithAttributionInheritingFromSelf/AndroidManifest.xml
@@ -17,9 +17,10 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.app.appops.cts.appwithduplicatefeature">
- <feature android:featureId="feature1" android:label="@string/dummyLabel" />
- <feature android:featureId="feature1" android:label="@string/dummyLabel" />
+ package="android.app.appops.cts.appwithattributioninheritingfromself">
+ <attribution android:tag="attribution1" android:label="@string/dummyLabel">
+ <inherit-from android:tag="attribution1" />
+ </attribution>
<application />
diff --git a/tests/tests/appop/AppWithFeatureInheritingFromSelf/res/values/strings.xml b/tests/tests/appop/AppWithAttributionInheritingFromSelf/res/values/strings.xml
similarity index 100%
rename from tests/tests/appop/AppWithFeatureInheritingFromSelf/res/values/strings.xml
rename to tests/tests/appop/AppWithAttributionInheritingFromSelf/res/values/strings.xml
diff --git a/tests/tests/appop/AppWithDuplicateFeature/Android.bp b/tests/tests/appop/AppWithDuplicateAttribution/Android.bp
similarity index 94%
rename from tests/tests/appop/AppWithDuplicateFeature/Android.bp
rename to tests/tests/appop/AppWithDuplicateAttribution/Android.bp
index a27dacb..a4b1272 100644
--- a/tests/tests/appop/AppWithDuplicateFeature/Android.bp
+++ b/tests/tests/appop/AppWithDuplicateAttribution/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
android_test_helper_app {
- name: "AppWithDuplicateFeature",
+ name: "AppWithDuplicateAttribution",
test_suites: [
"cts",
diff --git a/tests/tests/appop/AppWithDuplicateFeature/AndroidManifest.xml b/tests/tests/appop/AppWithDuplicateAttribution/AndroidManifest.xml
similarity index 77%
rename from tests/tests/appop/AppWithDuplicateFeature/AndroidManifest.xml
rename to tests/tests/appop/AppWithDuplicateAttribution/AndroidManifest.xml
index b7b5297..55b0ddb 100644
--- a/tests/tests/appop/AppWithDuplicateFeature/AndroidManifest.xml
+++ b/tests/tests/appop/AppWithDuplicateAttribution/AndroidManifest.xml
@@ -17,9 +17,9 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.app.appops.cts.appwithduplicatefeature">
- <feature android:featureId="feature1" android:label="@string/dummyLabel" />
- <feature android:featureId="feature1" android:label="@string/dummyLabel" />
+ package="android.app.appops.cts.appwithduplicateattribution">
+ <attribution android:tag="attribution1" android:label="@string/dummyLabel" />
+ <attribution android:tag="attribution1" android:label="@string/dummyLabel" />
<application />
diff --git a/tests/tests/appop/AppWithDuplicateFeature/res/values/strings.xml b/tests/tests/appop/AppWithDuplicateAttribution/res/values/strings.xml
similarity index 100%
rename from tests/tests/appop/AppWithDuplicateFeature/res/values/strings.xml
rename to tests/tests/appop/AppWithDuplicateAttribution/res/values/strings.xml
diff --git a/tests/tests/appop/AppWithFeatureInheritingFromExisting/Android.bp b/tests/tests/appop/AppWithFeatureInheritingFromExisting/Android.bp
deleted file mode 100644
index fd498d7..0000000
--- a/tests/tests/appop/AppWithFeatureInheritingFromExisting/Android.bp
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-android_test_helper_app {
- name: "AppWithFeatureInheritingFromExisting",
-
- test_suites: [
- "cts",
- "vts",
- "general-tests",
- ]
-}
\ No newline at end of file
diff --git a/tests/tests/appop/AppWithFeatureInheritingFromSameAsOther/Android.bp b/tests/tests/appop/AppWithFeatureInheritingFromSameAsOther/Android.bp
deleted file mode 100644
index d358ae34..0000000
--- a/tests/tests/appop/AppWithFeatureInheritingFromSameAsOther/Android.bp
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-android_test_helper_app {
- name: "AppWithFeatureInheritingFromSameAsOther",
-
- test_suites: [
- "cts",
- "vts",
- "general-tests",
- ]
-}
\ No newline at end of file
diff --git a/tests/tests/appop/AppWithFeatureInheritingFromSameAsOther/AndroidManifest.xml b/tests/tests/appop/AppWithFeatureInheritingFromSameAsOther/AndroidManifest.xml
deleted file mode 100644
index 5af9edc..0000000
--- a/tests/tests/appop/AppWithFeatureInheritingFromSameAsOther/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.app.appops.cts.appwithfeatureinheritingfromsameasother">
- <feature android:featureId="feature1" android:label="@string/dummyLabel">
- <inherit-from android:featureId="feature3" />
- </feature>
- <feature android:featureId="feature2" android:label="@string/dummyLabel">
- <inherit-from android:featureId="feature3" />
- </feature>
-
- <application />
-
-</manifest>
diff --git a/tests/tests/appop/AppWithFeatureInheritingFromSelf/Android.bp b/tests/tests/appop/AppWithFeatureInheritingFromSelf/Android.bp
deleted file mode 100644
index 4c47869..0000000
--- a/tests/tests/appop/AppWithFeatureInheritingFromSelf/Android.bp
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-android_test_helper_app {
- name: "AppWithFeatureInheritingFromSelf",
-
- test_suites: [
- "cts",
- "vts",
- "general-tests",
- ]
-}
\ No newline at end of file
diff --git a/tests/tests/appop/AppWithFeatureInheritingFromSelf/AndroidManifest.xml b/tests/tests/appop/AppWithFeatureInheritingFromSelf/AndroidManifest.xml
deleted file mode 100644
index ff7e198..0000000
--- a/tests/tests/appop/AppWithFeatureInheritingFromSelf/AndroidManifest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.app.appops.cts.appwithfeatureinheritingfromself">
- <feature android:featureId="feature1" android:label="@string/dummyLabel">
- <inherit-from android:featureId="feature1" />
- </feature>
-
- <application />
-
-</manifest>
diff --git a/tests/tests/appop/AppWithLongFeatureId/Android.bp b/tests/tests/appop/AppWithLongAttributionTag/Android.bp
similarity index 94%
copy from tests/tests/appop/AppWithLongFeatureId/Android.bp
copy to tests/tests/appop/AppWithLongAttributionTag/Android.bp
index e0034f0..5ee3f02 100644
--- a/tests/tests/appop/AppWithLongFeatureId/Android.bp
+++ b/tests/tests/appop/AppWithLongAttributionTag/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
android_test_helper_app {
- name: "AppWithLongFeatureIdFeature",
+ name: "AppWithLongAttributionTag",
test_suites: [
"cts",
diff --git a/tests/tests/appop/AppWithLongFeatureId/AndroidManifest.xml b/tests/tests/appop/AppWithLongAttributionTag/AndroidManifest.xml
similarity index 80%
rename from tests/tests/appop/AppWithLongFeatureId/AndroidManifest.xml
rename to tests/tests/appop/AppWithLongAttributionTag/AndroidManifest.xml
index 17d10e9..e08a32d 100644
--- a/tests/tests/appop/AppWithLongFeatureId/AndroidManifest.xml
+++ b/tests/tests/appop/AppWithLongAttributionTag/AndroidManifest.xml
@@ -17,8 +17,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.app.appops.cts.appwithlongfeatureId">
- <feature android:featureId="1xxxx_xxxx2xxxx_xxxx3xxxx_xxxx4xxxx_xxxx5xxxx_xxxxB" android:label="@string/dummyLabel" />
+ package="android.app.appops.cts.appwithlongattributiontag">
+ <attribution android:tag="1xxxx_xxxx2xxxx_xxxx3xxxx_xxxx4xxxx_xxxx5xxxx_xxxxB" android:label="@string/dummyLabel" />
<application />
diff --git a/tests/tests/appop/AppWithLongFeatureId/res/values/strings.xml b/tests/tests/appop/AppWithLongAttributionTag/res/values/strings.xml
similarity index 100%
rename from tests/tests/appop/AppWithLongFeatureId/res/values/strings.xml
rename to tests/tests/appop/AppWithLongAttributionTag/res/values/strings.xml
diff --git a/tests/tests/appop/AppWithLongFeatureId/Android.bp b/tests/tests/appop/AppWithTooManyAttributions/Android.bp
similarity index 94%
rename from tests/tests/appop/AppWithLongFeatureId/Android.bp
rename to tests/tests/appop/AppWithTooManyAttributions/Android.bp
index e0034f0..80b1bd3 100644
--- a/tests/tests/appop/AppWithLongFeatureId/Android.bp
+++ b/tests/tests/appop/AppWithTooManyAttributions/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
android_test_helper_app {
- name: "AppWithLongFeatureIdFeature",
+ name: "AppWithTooManyAttributions",
test_suites: [
"cts",
diff --git a/tests/tests/appop/AppWithTooManyAttributions/AndroidManifest.xml b/tests/tests/appop/AppWithTooManyAttributions/AndroidManifest.xml
new file mode 100644
index 0000000..debdb8e
--- /dev/null
+++ b/tests/tests/appop/AppWithTooManyAttributions/AndroidManifest.xml
@@ -0,0 +1,1028 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2020 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.app.appops.cts.appwithtoomanyattributions">
+
+ <!-- 1000 attributions are allowed -->
+ <attribution android:tag="f0" android:label="@string/dummyLabel" />
+ <attribution android:tag="f1" android:label="@string/dummyLabel" />
+ <attribution android:tag="f2" android:label="@string/dummyLabel" />
+ <attribution android:tag="f3" android:label="@string/dummyLabel" />
+ <attribution android:tag="f4" android:label="@string/dummyLabel" />
+ <attribution android:tag="f5" android:label="@string/dummyLabel" />
+ <attribution android:tag="f6" android:label="@string/dummyLabel" />
+ <attribution android:tag="f7" android:label="@string/dummyLabel" />
+ <attribution android:tag="f8" android:label="@string/dummyLabel" />
+ <attribution android:tag="f9" android:label="@string/dummyLabel" />
+ <attribution android:tag="f10" android:label="@string/dummyLabel" />
+ <attribution android:tag="f11" android:label="@string/dummyLabel" />
+ <attribution android:tag="f12" android:label="@string/dummyLabel" />
+ <attribution android:tag="f13" android:label="@string/dummyLabel" />
+ <attribution android:tag="f14" android:label="@string/dummyLabel" />
+ <attribution android:tag="f15" android:label="@string/dummyLabel" />
+ <attribution android:tag="f16" android:label="@string/dummyLabel" />
+ <attribution android:tag="f17" android:label="@string/dummyLabel" />
+ <attribution android:tag="f18" android:label="@string/dummyLabel" />
+ <attribution android:tag="f19" android:label="@string/dummyLabel" />
+ <attribution android:tag="f20" android:label="@string/dummyLabel" />
+ <attribution android:tag="f21" android:label="@string/dummyLabel" />
+ <attribution android:tag="f22" android:label="@string/dummyLabel" />
+ <attribution android:tag="f23" android:label="@string/dummyLabel" />
+ <attribution android:tag="f24" android:label="@string/dummyLabel" />
+ <attribution android:tag="f25" android:label="@string/dummyLabel" />
+ <attribution android:tag="f26" android:label="@string/dummyLabel" />
+ <attribution android:tag="f27" android:label="@string/dummyLabel" />
+ <attribution android:tag="f28" android:label="@string/dummyLabel" />
+ <attribution android:tag="f29" android:label="@string/dummyLabel" />
+ <attribution android:tag="f30" android:label="@string/dummyLabel" />
+ <attribution android:tag="f31" android:label="@string/dummyLabel" />
+ <attribution android:tag="f32" android:label="@string/dummyLabel" />
+ <attribution android:tag="f33" android:label="@string/dummyLabel" />
+ <attribution android:tag="f34" android:label="@string/dummyLabel" />
+ <attribution android:tag="f35" android:label="@string/dummyLabel" />
+ <attribution android:tag="f36" android:label="@string/dummyLabel" />
+ <attribution android:tag="f37" android:label="@string/dummyLabel" />
+ <attribution android:tag="f38" android:label="@string/dummyLabel" />
+ <attribution android:tag="f39" android:label="@string/dummyLabel" />
+ <attribution android:tag="f40" android:label="@string/dummyLabel" />
+ <attribution android:tag="f41" android:label="@string/dummyLabel" />
+ <attribution android:tag="f42" android:label="@string/dummyLabel" />
+ <attribution android:tag="f43" android:label="@string/dummyLabel" />
+ <attribution android:tag="f44" android:label="@string/dummyLabel" />
+ <attribution android:tag="f45" android:label="@string/dummyLabel" />
+ <attribution android:tag="f46" android:label="@string/dummyLabel" />
+ <attribution android:tag="f47" android:label="@string/dummyLabel" />
+ <attribution android:tag="f48" android:label="@string/dummyLabel" />
+ <attribution android:tag="f49" android:label="@string/dummyLabel" />
+ <attribution android:tag="f50" android:label="@string/dummyLabel" />
+ <attribution android:tag="f51" android:label="@string/dummyLabel" />
+ <attribution android:tag="f52" android:label="@string/dummyLabel" />
+ <attribution android:tag="f53" android:label="@string/dummyLabel" />
+ <attribution android:tag="f54" android:label="@string/dummyLabel" />
+ <attribution android:tag="f55" android:label="@string/dummyLabel" />
+ <attribution android:tag="f56" android:label="@string/dummyLabel" />
+ <attribution android:tag="f57" android:label="@string/dummyLabel" />
+ <attribution android:tag="f58" android:label="@string/dummyLabel" />
+ <attribution android:tag="f59" android:label="@string/dummyLabel" />
+ <attribution android:tag="f60" android:label="@string/dummyLabel" />
+ <attribution android:tag="f61" android:label="@string/dummyLabel" />
+ <attribution android:tag="f62" android:label="@string/dummyLabel" />
+ <attribution android:tag="f63" android:label="@string/dummyLabel" />
+ <attribution android:tag="f64" android:label="@string/dummyLabel" />
+ <attribution android:tag="f65" android:label="@string/dummyLabel" />
+ <attribution android:tag="f66" android:label="@string/dummyLabel" />
+ <attribution android:tag="f67" android:label="@string/dummyLabel" />
+ <attribution android:tag="f68" android:label="@string/dummyLabel" />
+ <attribution android:tag="f69" android:label="@string/dummyLabel" />
+ <attribution android:tag="f70" android:label="@string/dummyLabel" />
+ <attribution android:tag="f71" android:label="@string/dummyLabel" />
+ <attribution android:tag="f72" android:label="@string/dummyLabel" />
+ <attribution android:tag="f73" android:label="@string/dummyLabel" />
+ <attribution android:tag="f74" android:label="@string/dummyLabel" />
+ <attribution android:tag="f75" android:label="@string/dummyLabel" />
+ <attribution android:tag="f76" android:label="@string/dummyLabel" />
+ <attribution android:tag="f77" android:label="@string/dummyLabel" />
+ <attribution android:tag="f78" android:label="@string/dummyLabel" />
+ <attribution android:tag="f79" android:label="@string/dummyLabel" />
+ <attribution android:tag="f80" android:label="@string/dummyLabel" />
+ <attribution android:tag="f81" android:label="@string/dummyLabel" />
+ <attribution android:tag="f82" android:label="@string/dummyLabel" />
+ <attribution android:tag="f83" android:label="@string/dummyLabel" />
+ <attribution android:tag="f84" android:label="@string/dummyLabel" />
+ <attribution android:tag="f85" android:label="@string/dummyLabel" />
+ <attribution android:tag="f86" android:label="@string/dummyLabel" />
+ <attribution android:tag="f87" android:label="@string/dummyLabel" />
+ <attribution android:tag="f88" android:label="@string/dummyLabel" />
+ <attribution android:tag="f89" android:label="@string/dummyLabel" />
+ <attribution android:tag="f90" android:label="@string/dummyLabel" />
+ <attribution android:tag="f91" android:label="@string/dummyLabel" />
+ <attribution android:tag="f92" android:label="@string/dummyLabel" />
+ <attribution android:tag="f93" android:label="@string/dummyLabel" />
+ <attribution android:tag="f94" android:label="@string/dummyLabel" />
+ <attribution android:tag="f95" android:label="@string/dummyLabel" />
+ <attribution android:tag="f96" android:label="@string/dummyLabel" />
+ <attribution android:tag="f97" android:label="@string/dummyLabel" />
+ <attribution android:tag="f98" android:label="@string/dummyLabel" />
+ <attribution android:tag="f99" android:label="@string/dummyLabel" />
+ <attribution android:tag="f100" android:label="@string/dummyLabel" />
+ <attribution android:tag="f101" android:label="@string/dummyLabel" />
+ <attribution android:tag="f102" android:label="@string/dummyLabel" />
+ <attribution android:tag="f103" android:label="@string/dummyLabel" />
+ <attribution android:tag="f104" android:label="@string/dummyLabel" />
+ <attribution android:tag="f105" android:label="@string/dummyLabel" />
+ <attribution android:tag="f106" android:label="@string/dummyLabel" />
+ <attribution android:tag="f107" android:label="@string/dummyLabel" />
+ <attribution android:tag="f108" android:label="@string/dummyLabel" />
+ <attribution android:tag="f109" android:label="@string/dummyLabel" />
+ <attribution android:tag="f110" android:label="@string/dummyLabel" />
+ <attribution android:tag="f111" android:label="@string/dummyLabel" />
+ <attribution android:tag="f112" android:label="@string/dummyLabel" />
+ <attribution android:tag="f113" android:label="@string/dummyLabel" />
+ <attribution android:tag="f114" android:label="@string/dummyLabel" />
+ <attribution android:tag="f115" android:label="@string/dummyLabel" />
+ <attribution android:tag="f116" android:label="@string/dummyLabel" />
+ <attribution android:tag="f117" android:label="@string/dummyLabel" />
+ <attribution android:tag="f118" android:label="@string/dummyLabel" />
+ <attribution android:tag="f119" android:label="@string/dummyLabel" />
+ <attribution android:tag="f120" android:label="@string/dummyLabel" />
+ <attribution android:tag="f121" android:label="@string/dummyLabel" />
+ <attribution android:tag="f122" android:label="@string/dummyLabel" />
+ <attribution android:tag="f123" android:label="@string/dummyLabel" />
+ <attribution android:tag="f124" android:label="@string/dummyLabel" />
+ <attribution android:tag="f125" android:label="@string/dummyLabel" />
+ <attribution android:tag="f126" android:label="@string/dummyLabel" />
+ <attribution android:tag="f127" android:label="@string/dummyLabel" />
+ <attribution android:tag="f128" android:label="@string/dummyLabel" />
+ <attribution android:tag="f129" android:label="@string/dummyLabel" />
+ <attribution android:tag="f130" android:label="@string/dummyLabel" />
+ <attribution android:tag="f131" android:label="@string/dummyLabel" />
+ <attribution android:tag="f132" android:label="@string/dummyLabel" />
+ <attribution android:tag="f133" android:label="@string/dummyLabel" />
+ <attribution android:tag="f134" android:label="@string/dummyLabel" />
+ <attribution android:tag="f135" android:label="@string/dummyLabel" />
+ <attribution android:tag="f136" android:label="@string/dummyLabel" />
+ <attribution android:tag="f137" android:label="@string/dummyLabel" />
+ <attribution android:tag="f138" android:label="@string/dummyLabel" />
+ <attribution android:tag="f139" android:label="@string/dummyLabel" />
+ <attribution android:tag="f140" android:label="@string/dummyLabel" />
+ <attribution android:tag="f141" android:label="@string/dummyLabel" />
+ <attribution android:tag="f142" android:label="@string/dummyLabel" />
+ <attribution android:tag="f143" android:label="@string/dummyLabel" />
+ <attribution android:tag="f144" android:label="@string/dummyLabel" />
+ <attribution android:tag="f145" android:label="@string/dummyLabel" />
+ <attribution android:tag="f146" android:label="@string/dummyLabel" />
+ <attribution android:tag="f147" android:label="@string/dummyLabel" />
+ <attribution android:tag="f148" android:label="@string/dummyLabel" />
+ <attribution android:tag="f149" android:label="@string/dummyLabel" />
+ <attribution android:tag="f150" android:label="@string/dummyLabel" />
+ <attribution android:tag="f151" android:label="@string/dummyLabel" />
+ <attribution android:tag="f152" android:label="@string/dummyLabel" />
+ <attribution android:tag="f153" android:label="@string/dummyLabel" />
+ <attribution android:tag="f154" android:label="@string/dummyLabel" />
+ <attribution android:tag="f155" android:label="@string/dummyLabel" />
+ <attribution android:tag="f156" android:label="@string/dummyLabel" />
+ <attribution android:tag="f157" android:label="@string/dummyLabel" />
+ <attribution android:tag="f158" android:label="@string/dummyLabel" />
+ <attribution android:tag="f159" android:label="@string/dummyLabel" />
+ <attribution android:tag="f160" android:label="@string/dummyLabel" />
+ <attribution android:tag="f161" android:label="@string/dummyLabel" />
+ <attribution android:tag="f162" android:label="@string/dummyLabel" />
+ <attribution android:tag="f163" android:label="@string/dummyLabel" />
+ <attribution android:tag="f164" android:label="@string/dummyLabel" />
+ <attribution android:tag="f165" android:label="@string/dummyLabel" />
+ <attribution android:tag="f166" android:label="@string/dummyLabel" />
+ <attribution android:tag="f167" android:label="@string/dummyLabel" />
+ <attribution android:tag="f168" android:label="@string/dummyLabel" />
+ <attribution android:tag="f169" android:label="@string/dummyLabel" />
+ <attribution android:tag="f170" android:label="@string/dummyLabel" />
+ <attribution android:tag="f171" android:label="@string/dummyLabel" />
+ <attribution android:tag="f172" android:label="@string/dummyLabel" />
+ <attribution android:tag="f173" android:label="@string/dummyLabel" />
+ <attribution android:tag="f174" android:label="@string/dummyLabel" />
+ <attribution android:tag="f175" android:label="@string/dummyLabel" />
+ <attribution android:tag="f176" android:label="@string/dummyLabel" />
+ <attribution android:tag="f177" android:label="@string/dummyLabel" />
+ <attribution android:tag="f178" android:label="@string/dummyLabel" />
+ <attribution android:tag="f179" android:label="@string/dummyLabel" />
+ <attribution android:tag="f180" android:label="@string/dummyLabel" />
+ <attribution android:tag="f181" android:label="@string/dummyLabel" />
+ <attribution android:tag="f182" android:label="@string/dummyLabel" />
+ <attribution android:tag="f183" android:label="@string/dummyLabel" />
+ <attribution android:tag="f184" android:label="@string/dummyLabel" />
+ <attribution android:tag="f185" android:label="@string/dummyLabel" />
+ <attribution android:tag="f186" android:label="@string/dummyLabel" />
+ <attribution android:tag="f187" android:label="@string/dummyLabel" />
+ <attribution android:tag="f188" android:label="@string/dummyLabel" />
+ <attribution android:tag="f189" android:label="@string/dummyLabel" />
+ <attribution android:tag="f190" android:label="@string/dummyLabel" />
+ <attribution android:tag="f191" android:label="@string/dummyLabel" />
+ <attribution android:tag="f192" android:label="@string/dummyLabel" />
+ <attribution android:tag="f193" android:label="@string/dummyLabel" />
+ <attribution android:tag="f194" android:label="@string/dummyLabel" />
+ <attribution android:tag="f195" android:label="@string/dummyLabel" />
+ <attribution android:tag="f196" android:label="@string/dummyLabel" />
+ <attribution android:tag="f197" android:label="@string/dummyLabel" />
+ <attribution android:tag="f198" android:label="@string/dummyLabel" />
+ <attribution android:tag="f199" android:label="@string/dummyLabel" />
+ <attribution android:tag="f200" android:label="@string/dummyLabel" />
+ <attribution android:tag="f201" android:label="@string/dummyLabel" />
+ <attribution android:tag="f202" android:label="@string/dummyLabel" />
+ <attribution android:tag="f203" android:label="@string/dummyLabel" />
+ <attribution android:tag="f204" android:label="@string/dummyLabel" />
+ <attribution android:tag="f205" android:label="@string/dummyLabel" />
+ <attribution android:tag="f206" android:label="@string/dummyLabel" />
+ <attribution android:tag="f207" android:label="@string/dummyLabel" />
+ <attribution android:tag="f208" android:label="@string/dummyLabel" />
+ <attribution android:tag="f209" android:label="@string/dummyLabel" />
+ <attribution android:tag="f210" android:label="@string/dummyLabel" />
+ <attribution android:tag="f211" android:label="@string/dummyLabel" />
+ <attribution android:tag="f212" android:label="@string/dummyLabel" />
+ <attribution android:tag="f213" android:label="@string/dummyLabel" />
+ <attribution android:tag="f214" android:label="@string/dummyLabel" />
+ <attribution android:tag="f215" android:label="@string/dummyLabel" />
+ <attribution android:tag="f216" android:label="@string/dummyLabel" />
+ <attribution android:tag="f217" android:label="@string/dummyLabel" />
+ <attribution android:tag="f218" android:label="@string/dummyLabel" />
+ <attribution android:tag="f219" android:label="@string/dummyLabel" />
+ <attribution android:tag="f220" android:label="@string/dummyLabel" />
+ <attribution android:tag="f221" android:label="@string/dummyLabel" />
+ <attribution android:tag="f222" android:label="@string/dummyLabel" />
+ <attribution android:tag="f223" android:label="@string/dummyLabel" />
+ <attribution android:tag="f224" android:label="@string/dummyLabel" />
+ <attribution android:tag="f225" android:label="@string/dummyLabel" />
+ <attribution android:tag="f226" android:label="@string/dummyLabel" />
+ <attribution android:tag="f227" android:label="@string/dummyLabel" />
+ <attribution android:tag="f228" android:label="@string/dummyLabel" />
+ <attribution android:tag="f229" android:label="@string/dummyLabel" />
+ <attribution android:tag="f230" android:label="@string/dummyLabel" />
+ <attribution android:tag="f231" android:label="@string/dummyLabel" />
+ <attribution android:tag="f232" android:label="@string/dummyLabel" />
+ <attribution android:tag="f233" android:label="@string/dummyLabel" />
+ <attribution android:tag="f234" android:label="@string/dummyLabel" />
+ <attribution android:tag="f235" android:label="@string/dummyLabel" />
+ <attribution android:tag="f236" android:label="@string/dummyLabel" />
+ <attribution android:tag="f237" android:label="@string/dummyLabel" />
+ <attribution android:tag="f238" android:label="@string/dummyLabel" />
+ <attribution android:tag="f239" android:label="@string/dummyLabel" />
+ <attribution android:tag="f240" android:label="@string/dummyLabel" />
+ <attribution android:tag="f241" android:label="@string/dummyLabel" />
+ <attribution android:tag="f242" android:label="@string/dummyLabel" />
+ <attribution android:tag="f243" android:label="@string/dummyLabel" />
+ <attribution android:tag="f244" android:label="@string/dummyLabel" />
+ <attribution android:tag="f245" android:label="@string/dummyLabel" />
+ <attribution android:tag="f246" android:label="@string/dummyLabel" />
+ <attribution android:tag="f247" android:label="@string/dummyLabel" />
+ <attribution android:tag="f248" android:label="@string/dummyLabel" />
+ <attribution android:tag="f249" android:label="@string/dummyLabel" />
+ <attribution android:tag="f250" android:label="@string/dummyLabel" />
+ <attribution android:tag="f251" android:label="@string/dummyLabel" />
+ <attribution android:tag="f252" android:label="@string/dummyLabel" />
+ <attribution android:tag="f253" android:label="@string/dummyLabel" />
+ <attribution android:tag="f254" android:label="@string/dummyLabel" />
+ <attribution android:tag="f255" android:label="@string/dummyLabel" />
+ <attribution android:tag="f256" android:label="@string/dummyLabel" />
+ <attribution android:tag="f257" android:label="@string/dummyLabel" />
+ <attribution android:tag="f258" android:label="@string/dummyLabel" />
+ <attribution android:tag="f259" android:label="@string/dummyLabel" />
+ <attribution android:tag="f260" android:label="@string/dummyLabel" />
+ <attribution android:tag="f261" android:label="@string/dummyLabel" />
+ <attribution android:tag="f262" android:label="@string/dummyLabel" />
+ <attribution android:tag="f263" android:label="@string/dummyLabel" />
+ <attribution android:tag="f264" android:label="@string/dummyLabel" />
+ <attribution android:tag="f265" android:label="@string/dummyLabel" />
+ <attribution android:tag="f266" android:label="@string/dummyLabel" />
+ <attribution android:tag="f267" android:label="@string/dummyLabel" />
+ <attribution android:tag="f268" android:label="@string/dummyLabel" />
+ <attribution android:tag="f269" android:label="@string/dummyLabel" />
+ <attribution android:tag="f270" android:label="@string/dummyLabel" />
+ <attribution android:tag="f271" android:label="@string/dummyLabel" />
+ <attribution android:tag="f272" android:label="@string/dummyLabel" />
+ <attribution android:tag="f273" android:label="@string/dummyLabel" />
+ <attribution android:tag="f274" android:label="@string/dummyLabel" />
+ <attribution android:tag="f275" android:label="@string/dummyLabel" />
+ <attribution android:tag="f276" android:label="@string/dummyLabel" />
+ <attribution android:tag="f277" android:label="@string/dummyLabel" />
+ <attribution android:tag="f278" android:label="@string/dummyLabel" />
+ <attribution android:tag="f279" android:label="@string/dummyLabel" />
+ <attribution android:tag="f280" android:label="@string/dummyLabel" />
+ <attribution android:tag="f281" android:label="@string/dummyLabel" />
+ <attribution android:tag="f282" android:label="@string/dummyLabel" />
+ <attribution android:tag="f283" android:label="@string/dummyLabel" />
+ <attribution android:tag="f284" android:label="@string/dummyLabel" />
+ <attribution android:tag="f285" android:label="@string/dummyLabel" />
+ <attribution android:tag="f286" android:label="@string/dummyLabel" />
+ <attribution android:tag="f287" android:label="@string/dummyLabel" />
+ <attribution android:tag="f288" android:label="@string/dummyLabel" />
+ <attribution android:tag="f289" android:label="@string/dummyLabel" />
+ <attribution android:tag="f290" android:label="@string/dummyLabel" />
+ <attribution android:tag="f291" android:label="@string/dummyLabel" />
+ <attribution android:tag="f292" android:label="@string/dummyLabel" />
+ <attribution android:tag="f293" android:label="@string/dummyLabel" />
+ <attribution android:tag="f294" android:label="@string/dummyLabel" />
+ <attribution android:tag="f295" android:label="@string/dummyLabel" />
+ <attribution android:tag="f296" android:label="@string/dummyLabel" />
+ <attribution android:tag="f297" android:label="@string/dummyLabel" />
+ <attribution android:tag="f298" android:label="@string/dummyLabel" />
+ <attribution android:tag="f299" android:label="@string/dummyLabel" />
+ <attribution android:tag="f300" android:label="@string/dummyLabel" />
+ <attribution android:tag="f301" android:label="@string/dummyLabel" />
+ <attribution android:tag="f302" android:label="@string/dummyLabel" />
+ <attribution android:tag="f303" android:label="@string/dummyLabel" />
+ <attribution android:tag="f304" android:label="@string/dummyLabel" />
+ <attribution android:tag="f305" android:label="@string/dummyLabel" />
+ <attribution android:tag="f306" android:label="@string/dummyLabel" />
+ <attribution android:tag="f307" android:label="@string/dummyLabel" />
+ <attribution android:tag="f308" android:label="@string/dummyLabel" />
+ <attribution android:tag="f309" android:label="@string/dummyLabel" />
+ <attribution android:tag="f310" android:label="@string/dummyLabel" />
+ <attribution android:tag="f311" android:label="@string/dummyLabel" />
+ <attribution android:tag="f312" android:label="@string/dummyLabel" />
+ <attribution android:tag="f313" android:label="@string/dummyLabel" />
+ <attribution android:tag="f314" android:label="@string/dummyLabel" />
+ <attribution android:tag="f315" android:label="@string/dummyLabel" />
+ <attribution android:tag="f316" android:label="@string/dummyLabel" />
+ <attribution android:tag="f317" android:label="@string/dummyLabel" />
+ <attribution android:tag="f318" android:label="@string/dummyLabel" />
+ <attribution android:tag="f319" android:label="@string/dummyLabel" />
+ <attribution android:tag="f320" android:label="@string/dummyLabel" />
+ <attribution android:tag="f321" android:label="@string/dummyLabel" />
+ <attribution android:tag="f322" android:label="@string/dummyLabel" />
+ <attribution android:tag="f323" android:label="@string/dummyLabel" />
+ <attribution android:tag="f324" android:label="@string/dummyLabel" />
+ <attribution android:tag="f325" android:label="@string/dummyLabel" />
+ <attribution android:tag="f326" android:label="@string/dummyLabel" />
+ <attribution android:tag="f327" android:label="@string/dummyLabel" />
+ <attribution android:tag="f328" android:label="@string/dummyLabel" />
+ <attribution android:tag="f329" android:label="@string/dummyLabel" />
+ <attribution android:tag="f330" android:label="@string/dummyLabel" />
+ <attribution android:tag="f331" android:label="@string/dummyLabel" />
+ <attribution android:tag="f332" android:label="@string/dummyLabel" />
+ <attribution android:tag="f333" android:label="@string/dummyLabel" />
+ <attribution android:tag="f334" android:label="@string/dummyLabel" />
+ <attribution android:tag="f335" android:label="@string/dummyLabel" />
+ <attribution android:tag="f336" android:label="@string/dummyLabel" />
+ <attribution android:tag="f337" android:label="@string/dummyLabel" />
+ <attribution android:tag="f338" android:label="@string/dummyLabel" />
+ <attribution android:tag="f339" android:label="@string/dummyLabel" />
+ <attribution android:tag="f340" android:label="@string/dummyLabel" />
+ <attribution android:tag="f341" android:label="@string/dummyLabel" />
+ <attribution android:tag="f342" android:label="@string/dummyLabel" />
+ <attribution android:tag="f343" android:label="@string/dummyLabel" />
+ <attribution android:tag="f344" android:label="@string/dummyLabel" />
+ <attribution android:tag="f345" android:label="@string/dummyLabel" />
+ <attribution android:tag="f346" android:label="@string/dummyLabel" />
+ <attribution android:tag="f347" android:label="@string/dummyLabel" />
+ <attribution android:tag="f348" android:label="@string/dummyLabel" />
+ <attribution android:tag="f349" android:label="@string/dummyLabel" />
+ <attribution android:tag="f350" android:label="@string/dummyLabel" />
+ <attribution android:tag="f351" android:label="@string/dummyLabel" />
+ <attribution android:tag="f352" android:label="@string/dummyLabel" />
+ <attribution android:tag="f353" android:label="@string/dummyLabel" />
+ <attribution android:tag="f354" android:label="@string/dummyLabel" />
+ <attribution android:tag="f355" android:label="@string/dummyLabel" />
+ <attribution android:tag="f356" android:label="@string/dummyLabel" />
+ <attribution android:tag="f357" android:label="@string/dummyLabel" />
+ <attribution android:tag="f358" android:label="@string/dummyLabel" />
+ <attribution android:tag="f359" android:label="@string/dummyLabel" />
+ <attribution android:tag="f360" android:label="@string/dummyLabel" />
+ <attribution android:tag="f361" android:label="@string/dummyLabel" />
+ <attribution android:tag="f362" android:label="@string/dummyLabel" />
+ <attribution android:tag="f363" android:label="@string/dummyLabel" />
+ <attribution android:tag="f364" android:label="@string/dummyLabel" />
+ <attribution android:tag="f365" android:label="@string/dummyLabel" />
+ <attribution android:tag="f366" android:label="@string/dummyLabel" />
+ <attribution android:tag="f367" android:label="@string/dummyLabel" />
+ <attribution android:tag="f368" android:label="@string/dummyLabel" />
+ <attribution android:tag="f369" android:label="@string/dummyLabel" />
+ <attribution android:tag="f370" android:label="@string/dummyLabel" />
+ <attribution android:tag="f371" android:label="@string/dummyLabel" />
+ <attribution android:tag="f372" android:label="@string/dummyLabel" />
+ <attribution android:tag="f373" android:label="@string/dummyLabel" />
+ <attribution android:tag="f374" android:label="@string/dummyLabel" />
+ <attribution android:tag="f375" android:label="@string/dummyLabel" />
+ <attribution android:tag="f376" android:label="@string/dummyLabel" />
+ <attribution android:tag="f377" android:label="@string/dummyLabel" />
+ <attribution android:tag="f378" android:label="@string/dummyLabel" />
+ <attribution android:tag="f379" android:label="@string/dummyLabel" />
+ <attribution android:tag="f380" android:label="@string/dummyLabel" />
+ <attribution android:tag="f381" android:label="@string/dummyLabel" />
+ <attribution android:tag="f382" android:label="@string/dummyLabel" />
+ <attribution android:tag="f383" android:label="@string/dummyLabel" />
+ <attribution android:tag="f384" android:label="@string/dummyLabel" />
+ <attribution android:tag="f385" android:label="@string/dummyLabel" />
+ <attribution android:tag="f386" android:label="@string/dummyLabel" />
+ <attribution android:tag="f387" android:label="@string/dummyLabel" />
+ <attribution android:tag="f388" android:label="@string/dummyLabel" />
+ <attribution android:tag="f389" android:label="@string/dummyLabel" />
+ <attribution android:tag="f390" android:label="@string/dummyLabel" />
+ <attribution android:tag="f391" android:label="@string/dummyLabel" />
+ <attribution android:tag="f392" android:label="@string/dummyLabel" />
+ <attribution android:tag="f393" android:label="@string/dummyLabel" />
+ <attribution android:tag="f394" android:label="@string/dummyLabel" />
+ <attribution android:tag="f395" android:label="@string/dummyLabel" />
+ <attribution android:tag="f396" android:label="@string/dummyLabel" />
+ <attribution android:tag="f397" android:label="@string/dummyLabel" />
+ <attribution android:tag="f398" android:label="@string/dummyLabel" />
+ <attribution android:tag="f399" android:label="@string/dummyLabel" />
+ <attribution android:tag="f400" android:label="@string/dummyLabel" />
+ <attribution android:tag="f401" android:label="@string/dummyLabel" />
+ <attribution android:tag="f402" android:label="@string/dummyLabel" />
+ <attribution android:tag="f403" android:label="@string/dummyLabel" />
+ <attribution android:tag="f404" android:label="@string/dummyLabel" />
+ <attribution android:tag="f405" android:label="@string/dummyLabel" />
+ <attribution android:tag="f406" android:label="@string/dummyLabel" />
+ <attribution android:tag="f407" android:label="@string/dummyLabel" />
+ <attribution android:tag="f408" android:label="@string/dummyLabel" />
+ <attribution android:tag="f409" android:label="@string/dummyLabel" />
+ <attribution android:tag="f410" android:label="@string/dummyLabel" />
+ <attribution android:tag="f411" android:label="@string/dummyLabel" />
+ <attribution android:tag="f412" android:label="@string/dummyLabel" />
+ <attribution android:tag="f413" android:label="@string/dummyLabel" />
+ <attribution android:tag="f414" android:label="@string/dummyLabel" />
+ <attribution android:tag="f415" android:label="@string/dummyLabel" />
+ <attribution android:tag="f416" android:label="@string/dummyLabel" />
+ <attribution android:tag="f417" android:label="@string/dummyLabel" />
+ <attribution android:tag="f418" android:label="@string/dummyLabel" />
+ <attribution android:tag="f419" android:label="@string/dummyLabel" />
+ <attribution android:tag="f420" android:label="@string/dummyLabel" />
+ <attribution android:tag="f421" android:label="@string/dummyLabel" />
+ <attribution android:tag="f422" android:label="@string/dummyLabel" />
+ <attribution android:tag="f423" android:label="@string/dummyLabel" />
+ <attribution android:tag="f424" android:label="@string/dummyLabel" />
+ <attribution android:tag="f425" android:label="@string/dummyLabel" />
+ <attribution android:tag="f426" android:label="@string/dummyLabel" />
+ <attribution android:tag="f427" android:label="@string/dummyLabel" />
+ <attribution android:tag="f428" android:label="@string/dummyLabel" />
+ <attribution android:tag="f429" android:label="@string/dummyLabel" />
+ <attribution android:tag="f430" android:label="@string/dummyLabel" />
+ <attribution android:tag="f431" android:label="@string/dummyLabel" />
+ <attribution android:tag="f432" android:label="@string/dummyLabel" />
+ <attribution android:tag="f433" android:label="@string/dummyLabel" />
+ <attribution android:tag="f434" android:label="@string/dummyLabel" />
+ <attribution android:tag="f435" android:label="@string/dummyLabel" />
+ <attribution android:tag="f436" android:label="@string/dummyLabel" />
+ <attribution android:tag="f437" android:label="@string/dummyLabel" />
+ <attribution android:tag="f438" android:label="@string/dummyLabel" />
+ <attribution android:tag="f439" android:label="@string/dummyLabel" />
+ <attribution android:tag="f440" android:label="@string/dummyLabel" />
+ <attribution android:tag="f441" android:label="@string/dummyLabel" />
+ <attribution android:tag="f442" android:label="@string/dummyLabel" />
+ <attribution android:tag="f443" android:label="@string/dummyLabel" />
+ <attribution android:tag="f444" android:label="@string/dummyLabel" />
+ <attribution android:tag="f445" android:label="@string/dummyLabel" />
+ <attribution android:tag="f446" android:label="@string/dummyLabel" />
+ <attribution android:tag="f447" android:label="@string/dummyLabel" />
+ <attribution android:tag="f448" android:label="@string/dummyLabel" />
+ <attribution android:tag="f449" android:label="@string/dummyLabel" />
+ <attribution android:tag="f450" android:label="@string/dummyLabel" />
+ <attribution android:tag="f451" android:label="@string/dummyLabel" />
+ <attribution android:tag="f452" android:label="@string/dummyLabel" />
+ <attribution android:tag="f453" android:label="@string/dummyLabel" />
+ <attribution android:tag="f454" android:label="@string/dummyLabel" />
+ <attribution android:tag="f455" android:label="@string/dummyLabel" />
+ <attribution android:tag="f456" android:label="@string/dummyLabel" />
+ <attribution android:tag="f457" android:label="@string/dummyLabel" />
+ <attribution android:tag="f458" android:label="@string/dummyLabel" />
+ <attribution android:tag="f459" android:label="@string/dummyLabel" />
+ <attribution android:tag="f460" android:label="@string/dummyLabel" />
+ <attribution android:tag="f461" android:label="@string/dummyLabel" />
+ <attribution android:tag="f462" android:label="@string/dummyLabel" />
+ <attribution android:tag="f463" android:label="@string/dummyLabel" />
+ <attribution android:tag="f464" android:label="@string/dummyLabel" />
+ <attribution android:tag="f465" android:label="@string/dummyLabel" />
+ <attribution android:tag="f466" android:label="@string/dummyLabel" />
+ <attribution android:tag="f467" android:label="@string/dummyLabel" />
+ <attribution android:tag="f468" android:label="@string/dummyLabel" />
+ <attribution android:tag="f469" android:label="@string/dummyLabel" />
+ <attribution android:tag="f470" android:label="@string/dummyLabel" />
+ <attribution android:tag="f471" android:label="@string/dummyLabel" />
+ <attribution android:tag="f472" android:label="@string/dummyLabel" />
+ <attribution android:tag="f473" android:label="@string/dummyLabel" />
+ <attribution android:tag="f474" android:label="@string/dummyLabel" />
+ <attribution android:tag="f475" android:label="@string/dummyLabel" />
+ <attribution android:tag="f476" android:label="@string/dummyLabel" />
+ <attribution android:tag="f477" android:label="@string/dummyLabel" />
+ <attribution android:tag="f478" android:label="@string/dummyLabel" />
+ <attribution android:tag="f479" android:label="@string/dummyLabel" />
+ <attribution android:tag="f480" android:label="@string/dummyLabel" />
+ <attribution android:tag="f481" android:label="@string/dummyLabel" />
+ <attribution android:tag="f482" android:label="@string/dummyLabel" />
+ <attribution android:tag="f483" android:label="@string/dummyLabel" />
+ <attribution android:tag="f484" android:label="@string/dummyLabel" />
+ <attribution android:tag="f485" android:label="@string/dummyLabel" />
+ <attribution android:tag="f486" android:label="@string/dummyLabel" />
+ <attribution android:tag="f487" android:label="@string/dummyLabel" />
+ <attribution android:tag="f488" android:label="@string/dummyLabel" />
+ <attribution android:tag="f489" android:label="@string/dummyLabel" />
+ <attribution android:tag="f490" android:label="@string/dummyLabel" />
+ <attribution android:tag="f491" android:label="@string/dummyLabel" />
+ <attribution android:tag="f492" android:label="@string/dummyLabel" />
+ <attribution android:tag="f493" android:label="@string/dummyLabel" />
+ <attribution android:tag="f494" android:label="@string/dummyLabel" />
+ <attribution android:tag="f495" android:label="@string/dummyLabel" />
+ <attribution android:tag="f496" android:label="@string/dummyLabel" />
+ <attribution android:tag="f497" android:label="@string/dummyLabel" />
+ <attribution android:tag="f498" android:label="@string/dummyLabel" />
+ <attribution android:tag="f499" android:label="@string/dummyLabel" />
+ <attribution android:tag="f500" android:label="@string/dummyLabel" />
+ <attribution android:tag="f501" android:label="@string/dummyLabel" />
+ <attribution android:tag="f502" android:label="@string/dummyLabel" />
+ <attribution android:tag="f503" android:label="@string/dummyLabel" />
+ <attribution android:tag="f504" android:label="@string/dummyLabel" />
+ <attribution android:tag="f505" android:label="@string/dummyLabel" />
+ <attribution android:tag="f506" android:label="@string/dummyLabel" />
+ <attribution android:tag="f507" android:label="@string/dummyLabel" />
+ <attribution android:tag="f508" android:label="@string/dummyLabel" />
+ <attribution android:tag="f509" android:label="@string/dummyLabel" />
+ <attribution android:tag="f510" android:label="@string/dummyLabel" />
+ <attribution android:tag="f511" android:label="@string/dummyLabel" />
+ <attribution android:tag="f512" android:label="@string/dummyLabel" />
+ <attribution android:tag="f513" android:label="@string/dummyLabel" />
+ <attribution android:tag="f514" android:label="@string/dummyLabel" />
+ <attribution android:tag="f515" android:label="@string/dummyLabel" />
+ <attribution android:tag="f516" android:label="@string/dummyLabel" />
+ <attribution android:tag="f517" android:label="@string/dummyLabel" />
+ <attribution android:tag="f518" android:label="@string/dummyLabel" />
+ <attribution android:tag="f519" android:label="@string/dummyLabel" />
+ <attribution android:tag="f520" android:label="@string/dummyLabel" />
+ <attribution android:tag="f521" android:label="@string/dummyLabel" />
+ <attribution android:tag="f522" android:label="@string/dummyLabel" />
+ <attribution android:tag="f523" android:label="@string/dummyLabel" />
+ <attribution android:tag="f524" android:label="@string/dummyLabel" />
+ <attribution android:tag="f525" android:label="@string/dummyLabel" />
+ <attribution android:tag="f526" android:label="@string/dummyLabel" />
+ <attribution android:tag="f527" android:label="@string/dummyLabel" />
+ <attribution android:tag="f528" android:label="@string/dummyLabel" />
+ <attribution android:tag="f529" android:label="@string/dummyLabel" />
+ <attribution android:tag="f530" android:label="@string/dummyLabel" />
+ <attribution android:tag="f531" android:label="@string/dummyLabel" />
+ <attribution android:tag="f532" android:label="@string/dummyLabel" />
+ <attribution android:tag="f533" android:label="@string/dummyLabel" />
+ <attribution android:tag="f534" android:label="@string/dummyLabel" />
+ <attribution android:tag="f535" android:label="@string/dummyLabel" />
+ <attribution android:tag="f536" android:label="@string/dummyLabel" />
+ <attribution android:tag="f537" android:label="@string/dummyLabel" />
+ <attribution android:tag="f538" android:label="@string/dummyLabel" />
+ <attribution android:tag="f539" android:label="@string/dummyLabel" />
+ <attribution android:tag="f540" android:label="@string/dummyLabel" />
+ <attribution android:tag="f541" android:label="@string/dummyLabel" />
+ <attribution android:tag="f542" android:label="@string/dummyLabel" />
+ <attribution android:tag="f543" android:label="@string/dummyLabel" />
+ <attribution android:tag="f544" android:label="@string/dummyLabel" />
+ <attribution android:tag="f545" android:label="@string/dummyLabel" />
+ <attribution android:tag="f546" android:label="@string/dummyLabel" />
+ <attribution android:tag="f547" android:label="@string/dummyLabel" />
+ <attribution android:tag="f548" android:label="@string/dummyLabel" />
+ <attribution android:tag="f549" android:label="@string/dummyLabel" />
+ <attribution android:tag="f550" android:label="@string/dummyLabel" />
+ <attribution android:tag="f551" android:label="@string/dummyLabel" />
+ <attribution android:tag="f552" android:label="@string/dummyLabel" />
+ <attribution android:tag="f553" android:label="@string/dummyLabel" />
+ <attribution android:tag="f554" android:label="@string/dummyLabel" />
+ <attribution android:tag="f555" android:label="@string/dummyLabel" />
+ <attribution android:tag="f556" android:label="@string/dummyLabel" />
+ <attribution android:tag="f557" android:label="@string/dummyLabel" />
+ <attribution android:tag="f558" android:label="@string/dummyLabel" />
+ <attribution android:tag="f559" android:label="@string/dummyLabel" />
+ <attribution android:tag="f560" android:label="@string/dummyLabel" />
+ <attribution android:tag="f561" android:label="@string/dummyLabel" />
+ <attribution android:tag="f562" android:label="@string/dummyLabel" />
+ <attribution android:tag="f563" android:label="@string/dummyLabel" />
+ <attribution android:tag="f564" android:label="@string/dummyLabel" />
+ <attribution android:tag="f565" android:label="@string/dummyLabel" />
+ <attribution android:tag="f566" android:label="@string/dummyLabel" />
+ <attribution android:tag="f567" android:label="@string/dummyLabel" />
+ <attribution android:tag="f568" android:label="@string/dummyLabel" />
+ <attribution android:tag="f569" android:label="@string/dummyLabel" />
+ <attribution android:tag="f570" android:label="@string/dummyLabel" />
+ <attribution android:tag="f571" android:label="@string/dummyLabel" />
+ <attribution android:tag="f572" android:label="@string/dummyLabel" />
+ <attribution android:tag="f573" android:label="@string/dummyLabel" />
+ <attribution android:tag="f574" android:label="@string/dummyLabel" />
+ <attribution android:tag="f575" android:label="@string/dummyLabel" />
+ <attribution android:tag="f576" android:label="@string/dummyLabel" />
+ <attribution android:tag="f577" android:label="@string/dummyLabel" />
+ <attribution android:tag="f578" android:label="@string/dummyLabel" />
+ <attribution android:tag="f579" android:label="@string/dummyLabel" />
+ <attribution android:tag="f580" android:label="@string/dummyLabel" />
+ <attribution android:tag="f581" android:label="@string/dummyLabel" />
+ <attribution android:tag="f582" android:label="@string/dummyLabel" />
+ <attribution android:tag="f583" android:label="@string/dummyLabel" />
+ <attribution android:tag="f584" android:label="@string/dummyLabel" />
+ <attribution android:tag="f585" android:label="@string/dummyLabel" />
+ <attribution android:tag="f586" android:label="@string/dummyLabel" />
+ <attribution android:tag="f587" android:label="@string/dummyLabel" />
+ <attribution android:tag="f588" android:label="@string/dummyLabel" />
+ <attribution android:tag="f589" android:label="@string/dummyLabel" />
+ <attribution android:tag="f590" android:label="@string/dummyLabel" />
+ <attribution android:tag="f591" android:label="@string/dummyLabel" />
+ <attribution android:tag="f592" android:label="@string/dummyLabel" />
+ <attribution android:tag="f593" android:label="@string/dummyLabel" />
+ <attribution android:tag="f594" android:label="@string/dummyLabel" />
+ <attribution android:tag="f595" android:label="@string/dummyLabel" />
+ <attribution android:tag="f596" android:label="@string/dummyLabel" />
+ <attribution android:tag="f597" android:label="@string/dummyLabel" />
+ <attribution android:tag="f598" android:label="@string/dummyLabel" />
+ <attribution android:tag="f599" android:label="@string/dummyLabel" />
+ <attribution android:tag="f600" android:label="@string/dummyLabel" />
+ <attribution android:tag="f601" android:label="@string/dummyLabel" />
+ <attribution android:tag="f602" android:label="@string/dummyLabel" />
+ <attribution android:tag="f603" android:label="@string/dummyLabel" />
+ <attribution android:tag="f604" android:label="@string/dummyLabel" />
+ <attribution android:tag="f605" android:label="@string/dummyLabel" />
+ <attribution android:tag="f606" android:label="@string/dummyLabel" />
+ <attribution android:tag="f607" android:label="@string/dummyLabel" />
+ <attribution android:tag="f608" android:label="@string/dummyLabel" />
+ <attribution android:tag="f609" android:label="@string/dummyLabel" />
+ <attribution android:tag="f610" android:label="@string/dummyLabel" />
+ <attribution android:tag="f611" android:label="@string/dummyLabel" />
+ <attribution android:tag="f612" android:label="@string/dummyLabel" />
+ <attribution android:tag="f613" android:label="@string/dummyLabel" />
+ <attribution android:tag="f614" android:label="@string/dummyLabel" />
+ <attribution android:tag="f615" android:label="@string/dummyLabel" />
+ <attribution android:tag="f616" android:label="@string/dummyLabel" />
+ <attribution android:tag="f617" android:label="@string/dummyLabel" />
+ <attribution android:tag="f618" android:label="@string/dummyLabel" />
+ <attribution android:tag="f619" android:label="@string/dummyLabel" />
+ <attribution android:tag="f620" android:label="@string/dummyLabel" />
+ <attribution android:tag="f621" android:label="@string/dummyLabel" />
+ <attribution android:tag="f622" android:label="@string/dummyLabel" />
+ <attribution android:tag="f623" android:label="@string/dummyLabel" />
+ <attribution android:tag="f624" android:label="@string/dummyLabel" />
+ <attribution android:tag="f625" android:label="@string/dummyLabel" />
+ <attribution android:tag="f626" android:label="@string/dummyLabel" />
+ <attribution android:tag="f627" android:label="@string/dummyLabel" />
+ <attribution android:tag="f628" android:label="@string/dummyLabel" />
+ <attribution android:tag="f629" android:label="@string/dummyLabel" />
+ <attribution android:tag="f630" android:label="@string/dummyLabel" />
+ <attribution android:tag="f631" android:label="@string/dummyLabel" />
+ <attribution android:tag="f632" android:label="@string/dummyLabel" />
+ <attribution android:tag="f633" android:label="@string/dummyLabel" />
+ <attribution android:tag="f634" android:label="@string/dummyLabel" />
+ <attribution android:tag="f635" android:label="@string/dummyLabel" />
+ <attribution android:tag="f636" android:label="@string/dummyLabel" />
+ <attribution android:tag="f637" android:label="@string/dummyLabel" />
+ <attribution android:tag="f638" android:label="@string/dummyLabel" />
+ <attribution android:tag="f639" android:label="@string/dummyLabel" />
+ <attribution android:tag="f640" android:label="@string/dummyLabel" />
+ <attribution android:tag="f641" android:label="@string/dummyLabel" />
+ <attribution android:tag="f642" android:label="@string/dummyLabel" />
+ <attribution android:tag="f643" android:label="@string/dummyLabel" />
+ <attribution android:tag="f644" android:label="@string/dummyLabel" />
+ <attribution android:tag="f645" android:label="@string/dummyLabel" />
+ <attribution android:tag="f646" android:label="@string/dummyLabel" />
+ <attribution android:tag="f647" android:label="@string/dummyLabel" />
+ <attribution android:tag="f648" android:label="@string/dummyLabel" />
+ <attribution android:tag="f649" android:label="@string/dummyLabel" />
+ <attribution android:tag="f650" android:label="@string/dummyLabel" />
+ <attribution android:tag="f651" android:label="@string/dummyLabel" />
+ <attribution android:tag="f652" android:label="@string/dummyLabel" />
+ <attribution android:tag="f653" android:label="@string/dummyLabel" />
+ <attribution android:tag="f654" android:label="@string/dummyLabel" />
+ <attribution android:tag="f655" android:label="@string/dummyLabel" />
+ <attribution android:tag="f656" android:label="@string/dummyLabel" />
+ <attribution android:tag="f657" android:label="@string/dummyLabel" />
+ <attribution android:tag="f658" android:label="@string/dummyLabel" />
+ <attribution android:tag="f659" android:label="@string/dummyLabel" />
+ <attribution android:tag="f660" android:label="@string/dummyLabel" />
+ <attribution android:tag="f661" android:label="@string/dummyLabel" />
+ <attribution android:tag="f662" android:label="@string/dummyLabel" />
+ <attribution android:tag="f663" android:label="@string/dummyLabel" />
+ <attribution android:tag="f664" android:label="@string/dummyLabel" />
+ <attribution android:tag="f665" android:label="@string/dummyLabel" />
+ <attribution android:tag="f666" android:label="@string/dummyLabel" />
+ <attribution android:tag="f667" android:label="@string/dummyLabel" />
+ <attribution android:tag="f668" android:label="@string/dummyLabel" />
+ <attribution android:tag="f669" android:label="@string/dummyLabel" />
+ <attribution android:tag="f670" android:label="@string/dummyLabel" />
+ <attribution android:tag="f671" android:label="@string/dummyLabel" />
+ <attribution android:tag="f672" android:label="@string/dummyLabel" />
+ <attribution android:tag="f673" android:label="@string/dummyLabel" />
+ <attribution android:tag="f674" android:label="@string/dummyLabel" />
+ <attribution android:tag="f675" android:label="@string/dummyLabel" />
+ <attribution android:tag="f676" android:label="@string/dummyLabel" />
+ <attribution android:tag="f677" android:label="@string/dummyLabel" />
+ <attribution android:tag="f678" android:label="@string/dummyLabel" />
+ <attribution android:tag="f679" android:label="@string/dummyLabel" />
+ <attribution android:tag="f680" android:label="@string/dummyLabel" />
+ <attribution android:tag="f681" android:label="@string/dummyLabel" />
+ <attribution android:tag="f682" android:label="@string/dummyLabel" />
+ <attribution android:tag="f683" android:label="@string/dummyLabel" />
+ <attribution android:tag="f684" android:label="@string/dummyLabel" />
+ <attribution android:tag="f685" android:label="@string/dummyLabel" />
+ <attribution android:tag="f686" android:label="@string/dummyLabel" />
+ <attribution android:tag="f687" android:label="@string/dummyLabel" />
+ <attribution android:tag="f688" android:label="@string/dummyLabel" />
+ <attribution android:tag="f689" android:label="@string/dummyLabel" />
+ <attribution android:tag="f690" android:label="@string/dummyLabel" />
+ <attribution android:tag="f691" android:label="@string/dummyLabel" />
+ <attribution android:tag="f692" android:label="@string/dummyLabel" />
+ <attribution android:tag="f693" android:label="@string/dummyLabel" />
+ <attribution android:tag="f694" android:label="@string/dummyLabel" />
+ <attribution android:tag="f695" android:label="@string/dummyLabel" />
+ <attribution android:tag="f696" android:label="@string/dummyLabel" />
+ <attribution android:tag="f697" android:label="@string/dummyLabel" />
+ <attribution android:tag="f698" android:label="@string/dummyLabel" />
+ <attribution android:tag="f699" android:label="@string/dummyLabel" />
+ <attribution android:tag="f700" android:label="@string/dummyLabel" />
+ <attribution android:tag="f701" android:label="@string/dummyLabel" />
+ <attribution android:tag="f702" android:label="@string/dummyLabel" />
+ <attribution android:tag="f703" android:label="@string/dummyLabel" />
+ <attribution android:tag="f704" android:label="@string/dummyLabel" />
+ <attribution android:tag="f705" android:label="@string/dummyLabel" />
+ <attribution android:tag="f706" android:label="@string/dummyLabel" />
+ <attribution android:tag="f707" android:label="@string/dummyLabel" />
+ <attribution android:tag="f708" android:label="@string/dummyLabel" />
+ <attribution android:tag="f709" android:label="@string/dummyLabel" />
+ <attribution android:tag="f710" android:label="@string/dummyLabel" />
+ <attribution android:tag="f711" android:label="@string/dummyLabel" />
+ <attribution android:tag="f712" android:label="@string/dummyLabel" />
+ <attribution android:tag="f713" android:label="@string/dummyLabel" />
+ <attribution android:tag="f714" android:label="@string/dummyLabel" />
+ <attribution android:tag="f715" android:label="@string/dummyLabel" />
+ <attribution android:tag="f716" android:label="@string/dummyLabel" />
+ <attribution android:tag="f717" android:label="@string/dummyLabel" />
+ <attribution android:tag="f718" android:label="@string/dummyLabel" />
+ <attribution android:tag="f719" android:label="@string/dummyLabel" />
+ <attribution android:tag="f720" android:label="@string/dummyLabel" />
+ <attribution android:tag="f721" android:label="@string/dummyLabel" />
+ <attribution android:tag="f722" android:label="@string/dummyLabel" />
+ <attribution android:tag="f723" android:label="@string/dummyLabel" />
+ <attribution android:tag="f724" android:label="@string/dummyLabel" />
+ <attribution android:tag="f725" android:label="@string/dummyLabel" />
+ <attribution android:tag="f726" android:label="@string/dummyLabel" />
+ <attribution android:tag="f727" android:label="@string/dummyLabel" />
+ <attribution android:tag="f728" android:label="@string/dummyLabel" />
+ <attribution android:tag="f729" android:label="@string/dummyLabel" />
+ <attribution android:tag="f730" android:label="@string/dummyLabel" />
+ <attribution android:tag="f731" android:label="@string/dummyLabel" />
+ <attribution android:tag="f732" android:label="@string/dummyLabel" />
+ <attribution android:tag="f733" android:label="@string/dummyLabel" />
+ <attribution android:tag="f734" android:label="@string/dummyLabel" />
+ <attribution android:tag="f735" android:label="@string/dummyLabel" />
+ <attribution android:tag="f736" android:label="@string/dummyLabel" />
+ <attribution android:tag="f737" android:label="@string/dummyLabel" />
+ <attribution android:tag="f738" android:label="@string/dummyLabel" />
+ <attribution android:tag="f739" android:label="@string/dummyLabel" />
+ <attribution android:tag="f740" android:label="@string/dummyLabel" />
+ <attribution android:tag="f741" android:label="@string/dummyLabel" />
+ <attribution android:tag="f742" android:label="@string/dummyLabel" />
+ <attribution android:tag="f743" android:label="@string/dummyLabel" />
+ <attribution android:tag="f744" android:label="@string/dummyLabel" />
+ <attribution android:tag="f745" android:label="@string/dummyLabel" />
+ <attribution android:tag="f746" android:label="@string/dummyLabel" />
+ <attribution android:tag="f747" android:label="@string/dummyLabel" />
+ <attribution android:tag="f748" android:label="@string/dummyLabel" />
+ <attribution android:tag="f749" android:label="@string/dummyLabel" />
+ <attribution android:tag="f750" android:label="@string/dummyLabel" />
+ <attribution android:tag="f751" android:label="@string/dummyLabel" />
+ <attribution android:tag="f752" android:label="@string/dummyLabel" />
+ <attribution android:tag="f753" android:label="@string/dummyLabel" />
+ <attribution android:tag="f754" android:label="@string/dummyLabel" />
+ <attribution android:tag="f755" android:label="@string/dummyLabel" />
+ <attribution android:tag="f756" android:label="@string/dummyLabel" />
+ <attribution android:tag="f757" android:label="@string/dummyLabel" />
+ <attribution android:tag="f758" android:label="@string/dummyLabel" />
+ <attribution android:tag="f759" android:label="@string/dummyLabel" />
+ <attribution android:tag="f760" android:label="@string/dummyLabel" />
+ <attribution android:tag="f761" android:label="@string/dummyLabel" />
+ <attribution android:tag="f762" android:label="@string/dummyLabel" />
+ <attribution android:tag="f763" android:label="@string/dummyLabel" />
+ <attribution android:tag="f764" android:label="@string/dummyLabel" />
+ <attribution android:tag="f765" android:label="@string/dummyLabel" />
+ <attribution android:tag="f766" android:label="@string/dummyLabel" />
+ <attribution android:tag="f767" android:label="@string/dummyLabel" />
+ <attribution android:tag="f768" android:label="@string/dummyLabel" />
+ <attribution android:tag="f769" android:label="@string/dummyLabel" />
+ <attribution android:tag="f770" android:label="@string/dummyLabel" />
+ <attribution android:tag="f771" android:label="@string/dummyLabel" />
+ <attribution android:tag="f772" android:label="@string/dummyLabel" />
+ <attribution android:tag="f773" android:label="@string/dummyLabel" />
+ <attribution android:tag="f774" android:label="@string/dummyLabel" />
+ <attribution android:tag="f775" android:label="@string/dummyLabel" />
+ <attribution android:tag="f776" android:label="@string/dummyLabel" />
+ <attribution android:tag="f777" android:label="@string/dummyLabel" />
+ <attribution android:tag="f778" android:label="@string/dummyLabel" />
+ <attribution android:tag="f779" android:label="@string/dummyLabel" />
+ <attribution android:tag="f780" android:label="@string/dummyLabel" />
+ <attribution android:tag="f781" android:label="@string/dummyLabel" />
+ <attribution android:tag="f782" android:label="@string/dummyLabel" />
+ <attribution android:tag="f783" android:label="@string/dummyLabel" />
+ <attribution android:tag="f784" android:label="@string/dummyLabel" />
+ <attribution android:tag="f785" android:label="@string/dummyLabel" />
+ <attribution android:tag="f786" android:label="@string/dummyLabel" />
+ <attribution android:tag="f787" android:label="@string/dummyLabel" />
+ <attribution android:tag="f788" android:label="@string/dummyLabel" />
+ <attribution android:tag="f789" android:label="@string/dummyLabel" />
+ <attribution android:tag="f790" android:label="@string/dummyLabel" />
+ <attribution android:tag="f791" android:label="@string/dummyLabel" />
+ <attribution android:tag="f792" android:label="@string/dummyLabel" />
+ <attribution android:tag="f793" android:label="@string/dummyLabel" />
+ <attribution android:tag="f794" android:label="@string/dummyLabel" />
+ <attribution android:tag="f795" android:label="@string/dummyLabel" />
+ <attribution android:tag="f796" android:label="@string/dummyLabel" />
+ <attribution android:tag="f797" android:label="@string/dummyLabel" />
+ <attribution android:tag="f798" android:label="@string/dummyLabel" />
+ <attribution android:tag="f799" android:label="@string/dummyLabel" />
+ <attribution android:tag="f800" android:label="@string/dummyLabel" />
+ <attribution android:tag="f801" android:label="@string/dummyLabel" />
+ <attribution android:tag="f802" android:label="@string/dummyLabel" />
+ <attribution android:tag="f803" android:label="@string/dummyLabel" />
+ <attribution android:tag="f804" android:label="@string/dummyLabel" />
+ <attribution android:tag="f805" android:label="@string/dummyLabel" />
+ <attribution android:tag="f806" android:label="@string/dummyLabel" />
+ <attribution android:tag="f807" android:label="@string/dummyLabel" />
+ <attribution android:tag="f808" android:label="@string/dummyLabel" />
+ <attribution android:tag="f809" android:label="@string/dummyLabel" />
+ <attribution android:tag="f810" android:label="@string/dummyLabel" />
+ <attribution android:tag="f811" android:label="@string/dummyLabel" />
+ <attribution android:tag="f812" android:label="@string/dummyLabel" />
+ <attribution android:tag="f813" android:label="@string/dummyLabel" />
+ <attribution android:tag="f814" android:label="@string/dummyLabel" />
+ <attribution android:tag="f815" android:label="@string/dummyLabel" />
+ <attribution android:tag="f816" android:label="@string/dummyLabel" />
+ <attribution android:tag="f817" android:label="@string/dummyLabel" />
+ <attribution android:tag="f818" android:label="@string/dummyLabel" />
+ <attribution android:tag="f819" android:label="@string/dummyLabel" />
+ <attribution android:tag="f820" android:label="@string/dummyLabel" />
+ <attribution android:tag="f821" android:label="@string/dummyLabel" />
+ <attribution android:tag="f822" android:label="@string/dummyLabel" />
+ <attribution android:tag="f823" android:label="@string/dummyLabel" />
+ <attribution android:tag="f824" android:label="@string/dummyLabel" />
+ <attribution android:tag="f825" android:label="@string/dummyLabel" />
+ <attribution android:tag="f826" android:label="@string/dummyLabel" />
+ <attribution android:tag="f827" android:label="@string/dummyLabel" />
+ <attribution android:tag="f828" android:label="@string/dummyLabel" />
+ <attribution android:tag="f829" android:label="@string/dummyLabel" />
+ <attribution android:tag="f830" android:label="@string/dummyLabel" />
+ <attribution android:tag="f831" android:label="@string/dummyLabel" />
+ <attribution android:tag="f832" android:label="@string/dummyLabel" />
+ <attribution android:tag="f833" android:label="@string/dummyLabel" />
+ <attribution android:tag="f834" android:label="@string/dummyLabel" />
+ <attribution android:tag="f835" android:label="@string/dummyLabel" />
+ <attribution android:tag="f836" android:label="@string/dummyLabel" />
+ <attribution android:tag="f837" android:label="@string/dummyLabel" />
+ <attribution android:tag="f838" android:label="@string/dummyLabel" />
+ <attribution android:tag="f839" android:label="@string/dummyLabel" />
+ <attribution android:tag="f840" android:label="@string/dummyLabel" />
+ <attribution android:tag="f841" android:label="@string/dummyLabel" />
+ <attribution android:tag="f842" android:label="@string/dummyLabel" />
+ <attribution android:tag="f843" android:label="@string/dummyLabel" />
+ <attribution android:tag="f844" android:label="@string/dummyLabel" />
+ <attribution android:tag="f845" android:label="@string/dummyLabel" />
+ <attribution android:tag="f846" android:label="@string/dummyLabel" />
+ <attribution android:tag="f847" android:label="@string/dummyLabel" />
+ <attribution android:tag="f848" android:label="@string/dummyLabel" />
+ <attribution android:tag="f849" android:label="@string/dummyLabel" />
+ <attribution android:tag="f850" android:label="@string/dummyLabel" />
+ <attribution android:tag="f851" android:label="@string/dummyLabel" />
+ <attribution android:tag="f852" android:label="@string/dummyLabel" />
+ <attribution android:tag="f853" android:label="@string/dummyLabel" />
+ <attribution android:tag="f854" android:label="@string/dummyLabel" />
+ <attribution android:tag="f855" android:label="@string/dummyLabel" />
+ <attribution android:tag="f856" android:label="@string/dummyLabel" />
+ <attribution android:tag="f857" android:label="@string/dummyLabel" />
+ <attribution android:tag="f858" android:label="@string/dummyLabel" />
+ <attribution android:tag="f859" android:label="@string/dummyLabel" />
+ <attribution android:tag="f860" android:label="@string/dummyLabel" />
+ <attribution android:tag="f861" android:label="@string/dummyLabel" />
+ <attribution android:tag="f862" android:label="@string/dummyLabel" />
+ <attribution android:tag="f863" android:label="@string/dummyLabel" />
+ <attribution android:tag="f864" android:label="@string/dummyLabel" />
+ <attribution android:tag="f865" android:label="@string/dummyLabel" />
+ <attribution android:tag="f866" android:label="@string/dummyLabel" />
+ <attribution android:tag="f867" android:label="@string/dummyLabel" />
+ <attribution android:tag="f868" android:label="@string/dummyLabel" />
+ <attribution android:tag="f869" android:label="@string/dummyLabel" />
+ <attribution android:tag="f870" android:label="@string/dummyLabel" />
+ <attribution android:tag="f871" android:label="@string/dummyLabel" />
+ <attribution android:tag="f872" android:label="@string/dummyLabel" />
+ <attribution android:tag="f873" android:label="@string/dummyLabel" />
+ <attribution android:tag="f874" android:label="@string/dummyLabel" />
+ <attribution android:tag="f875" android:label="@string/dummyLabel" />
+ <attribution android:tag="f876" android:label="@string/dummyLabel" />
+ <attribution android:tag="f877" android:label="@string/dummyLabel" />
+ <attribution android:tag="f878" android:label="@string/dummyLabel" />
+ <attribution android:tag="f879" android:label="@string/dummyLabel" />
+ <attribution android:tag="f880" android:label="@string/dummyLabel" />
+ <attribution android:tag="f881" android:label="@string/dummyLabel" />
+ <attribution android:tag="f882" android:label="@string/dummyLabel" />
+ <attribution android:tag="f883" android:label="@string/dummyLabel" />
+ <attribution android:tag="f884" android:label="@string/dummyLabel" />
+ <attribution android:tag="f885" android:label="@string/dummyLabel" />
+ <attribution android:tag="f886" android:label="@string/dummyLabel" />
+ <attribution android:tag="f887" android:label="@string/dummyLabel" />
+ <attribution android:tag="f888" android:label="@string/dummyLabel" />
+ <attribution android:tag="f889" android:label="@string/dummyLabel" />
+ <attribution android:tag="f890" android:label="@string/dummyLabel" />
+ <attribution android:tag="f891" android:label="@string/dummyLabel" />
+ <attribution android:tag="f892" android:label="@string/dummyLabel" />
+ <attribution android:tag="f893" android:label="@string/dummyLabel" />
+ <attribution android:tag="f894" android:label="@string/dummyLabel" />
+ <attribution android:tag="f895" android:label="@string/dummyLabel" />
+ <attribution android:tag="f896" android:label="@string/dummyLabel" />
+ <attribution android:tag="f897" android:label="@string/dummyLabel" />
+ <attribution android:tag="f898" android:label="@string/dummyLabel" />
+ <attribution android:tag="f899" android:label="@string/dummyLabel" />
+ <attribution android:tag="f900" android:label="@string/dummyLabel" />
+ <attribution android:tag="f901" android:label="@string/dummyLabel" />
+ <attribution android:tag="f902" android:label="@string/dummyLabel" />
+ <attribution android:tag="f903" android:label="@string/dummyLabel" />
+ <attribution android:tag="f904" android:label="@string/dummyLabel" />
+ <attribution android:tag="f905" android:label="@string/dummyLabel" />
+ <attribution android:tag="f906" android:label="@string/dummyLabel" />
+ <attribution android:tag="f907" android:label="@string/dummyLabel" />
+ <attribution android:tag="f908" android:label="@string/dummyLabel" />
+ <attribution android:tag="f909" android:label="@string/dummyLabel" />
+ <attribution android:tag="f910" android:label="@string/dummyLabel" />
+ <attribution android:tag="f911" android:label="@string/dummyLabel" />
+ <attribution android:tag="f912" android:label="@string/dummyLabel" />
+ <attribution android:tag="f913" android:label="@string/dummyLabel" />
+ <attribution android:tag="f914" android:label="@string/dummyLabel" />
+ <attribution android:tag="f915" android:label="@string/dummyLabel" />
+ <attribution android:tag="f916" android:label="@string/dummyLabel" />
+ <attribution android:tag="f917" android:label="@string/dummyLabel" />
+ <attribution android:tag="f918" android:label="@string/dummyLabel" />
+ <attribution android:tag="f919" android:label="@string/dummyLabel" />
+ <attribution android:tag="f920" android:label="@string/dummyLabel" />
+ <attribution android:tag="f921" android:label="@string/dummyLabel" />
+ <attribution android:tag="f922" android:label="@string/dummyLabel" />
+ <attribution android:tag="f923" android:label="@string/dummyLabel" />
+ <attribution android:tag="f924" android:label="@string/dummyLabel" />
+ <attribution android:tag="f925" android:label="@string/dummyLabel" />
+ <attribution android:tag="f926" android:label="@string/dummyLabel" />
+ <attribution android:tag="f927" android:label="@string/dummyLabel" />
+ <attribution android:tag="f928" android:label="@string/dummyLabel" />
+ <attribution android:tag="f929" android:label="@string/dummyLabel" />
+ <attribution android:tag="f930" android:label="@string/dummyLabel" />
+ <attribution android:tag="f931" android:label="@string/dummyLabel" />
+ <attribution android:tag="f932" android:label="@string/dummyLabel" />
+ <attribution android:tag="f933" android:label="@string/dummyLabel" />
+ <attribution android:tag="f934" android:label="@string/dummyLabel" />
+ <attribution android:tag="f935" android:label="@string/dummyLabel" />
+ <attribution android:tag="f936" android:label="@string/dummyLabel" />
+ <attribution android:tag="f937" android:label="@string/dummyLabel" />
+ <attribution android:tag="f938" android:label="@string/dummyLabel" />
+ <attribution android:tag="f939" android:label="@string/dummyLabel" />
+ <attribution android:tag="f940" android:label="@string/dummyLabel" />
+ <attribution android:tag="f941" android:label="@string/dummyLabel" />
+ <attribution android:tag="f942" android:label="@string/dummyLabel" />
+ <attribution android:tag="f943" android:label="@string/dummyLabel" />
+ <attribution android:tag="f944" android:label="@string/dummyLabel" />
+ <attribution android:tag="f945" android:label="@string/dummyLabel" />
+ <attribution android:tag="f946" android:label="@string/dummyLabel" />
+ <attribution android:tag="f947" android:label="@string/dummyLabel" />
+ <attribution android:tag="f948" android:label="@string/dummyLabel" />
+ <attribution android:tag="f949" android:label="@string/dummyLabel" />
+ <attribution android:tag="f950" android:label="@string/dummyLabel" />
+ <attribution android:tag="f951" android:label="@string/dummyLabel" />
+ <attribution android:tag="f952" android:label="@string/dummyLabel" />
+ <attribution android:tag="f953" android:label="@string/dummyLabel" />
+ <attribution android:tag="f954" android:label="@string/dummyLabel" />
+ <attribution android:tag="f955" android:label="@string/dummyLabel" />
+ <attribution android:tag="f956" android:label="@string/dummyLabel" />
+ <attribution android:tag="f957" android:label="@string/dummyLabel" />
+ <attribution android:tag="f958" android:label="@string/dummyLabel" />
+ <attribution android:tag="f959" android:label="@string/dummyLabel" />
+ <attribution android:tag="f960" android:label="@string/dummyLabel" />
+ <attribution android:tag="f961" android:label="@string/dummyLabel" />
+ <attribution android:tag="f962" android:label="@string/dummyLabel" />
+ <attribution android:tag="f963" android:label="@string/dummyLabel" />
+ <attribution android:tag="f964" android:label="@string/dummyLabel" />
+ <attribution android:tag="f965" android:label="@string/dummyLabel" />
+ <attribution android:tag="f966" android:label="@string/dummyLabel" />
+ <attribution android:tag="f967" android:label="@string/dummyLabel" />
+ <attribution android:tag="f968" android:label="@string/dummyLabel" />
+ <attribution android:tag="f969" android:label="@string/dummyLabel" />
+ <attribution android:tag="f970" android:label="@string/dummyLabel" />
+ <attribution android:tag="f971" android:label="@string/dummyLabel" />
+ <attribution android:tag="f972" android:label="@string/dummyLabel" />
+ <attribution android:tag="f973" android:label="@string/dummyLabel" />
+ <attribution android:tag="f974" android:label="@string/dummyLabel" />
+ <attribution android:tag="f975" android:label="@string/dummyLabel" />
+ <attribution android:tag="f976" android:label="@string/dummyLabel" />
+ <attribution android:tag="f977" android:label="@string/dummyLabel" />
+ <attribution android:tag="f978" android:label="@string/dummyLabel" />
+ <attribution android:tag="f979" android:label="@string/dummyLabel" />
+ <attribution android:tag="f980" android:label="@string/dummyLabel" />
+ <attribution android:tag="f981" android:label="@string/dummyLabel" />
+ <attribution android:tag="f982" android:label="@string/dummyLabel" />
+ <attribution android:tag="f983" android:label="@string/dummyLabel" />
+ <attribution android:tag="f984" android:label="@string/dummyLabel" />
+ <attribution android:tag="f985" android:label="@string/dummyLabel" />
+ <attribution android:tag="f986" android:label="@string/dummyLabel" />
+ <attribution android:tag="f987" android:label="@string/dummyLabel" />
+ <attribution android:tag="f988" android:label="@string/dummyLabel" />
+ <attribution android:tag="f989" android:label="@string/dummyLabel" />
+ <attribution android:tag="f990" android:label="@string/dummyLabel" />
+ <attribution android:tag="f991" android:label="@string/dummyLabel" />
+ <attribution android:tag="f992" android:label="@string/dummyLabel" />
+ <attribution android:tag="f993" android:label="@string/dummyLabel" />
+ <attribution android:tag="f994" android:label="@string/dummyLabel" />
+ <attribution android:tag="f995" android:label="@string/dummyLabel" />
+ <attribution android:tag="f996" android:label="@string/dummyLabel" />
+ <attribution android:tag="f997" android:label="@string/dummyLabel" />
+ <attribution android:tag="f998" android:label="@string/dummyLabel" />
+ <attribution android:tag="f999" android:label="@string/dummyLabel" />
+
+ <attribution android:tag="toomany" android:label="@string/dummyLabel" />
+
+ <application />
+
+</manifest>
diff --git a/tests/tests/appop/AppWithTooManyFeatures/res/values/strings.xml b/tests/tests/appop/AppWithTooManyAttributions/res/values/strings.xml
similarity index 100%
rename from tests/tests/appop/AppWithTooManyFeatures/res/values/strings.xml
rename to tests/tests/appop/AppWithTooManyAttributions/res/values/strings.xml
diff --git a/tests/tests/appop/AppWithTooManyFeatures/Android.bp b/tests/tests/appop/AppWithTooManyFeatures/Android.bp
deleted file mode 100644
index bc769d6..0000000
--- a/tests/tests/appop/AppWithTooManyFeatures/Android.bp
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (C) 2020 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.
-
-android_test_helper_app {
- name: "AppWithTooManyFeatures",
-
- test_suites: [
- "cts",
- "vts",
- "general-tests",
- ]
-}
\ No newline at end of file
diff --git a/tests/tests/appop/AppWithTooManyFeatures/AndroidManifest.xml b/tests/tests/appop/AppWithTooManyFeatures/AndroidManifest.xml
deleted file mode 100644
index eeecef7..0000000
--- a/tests/tests/appop/AppWithTooManyFeatures/AndroidManifest.xml
+++ /dev/null
@@ -1,1028 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2020 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.app.appops.cts.appwithtoomanyfeatures">
-
- <!-- 1000 features are allowed -->
- <feature android:featureId="f0" android:label="@string/dummyLabel" />
- <feature android:featureId="f1" android:label="@string/dummyLabel" />
- <feature android:featureId="f2" android:label="@string/dummyLabel" />
- <feature android:featureId="f3" android:label="@string/dummyLabel" />
- <feature android:featureId="f4" android:label="@string/dummyLabel" />
- <feature android:featureId="f5" android:label="@string/dummyLabel" />
- <feature android:featureId="f6" android:label="@string/dummyLabel" />
- <feature android:featureId="f7" android:label="@string/dummyLabel" />
- <feature android:featureId="f8" android:label="@string/dummyLabel" />
- <feature android:featureId="f9" android:label="@string/dummyLabel" />
- <feature android:featureId="f10" android:label="@string/dummyLabel" />
- <feature android:featureId="f11" android:label="@string/dummyLabel" />
- <feature android:featureId="f12" android:label="@string/dummyLabel" />
- <feature android:featureId="f13" android:label="@string/dummyLabel" />
- <feature android:featureId="f14" android:label="@string/dummyLabel" />
- <feature android:featureId="f15" android:label="@string/dummyLabel" />
- <feature android:featureId="f16" android:label="@string/dummyLabel" />
- <feature android:featureId="f17" android:label="@string/dummyLabel" />
- <feature android:featureId="f18" android:label="@string/dummyLabel" />
- <feature android:featureId="f19" android:label="@string/dummyLabel" />
- <feature android:featureId="f20" android:label="@string/dummyLabel" />
- <feature android:featureId="f21" android:label="@string/dummyLabel" />
- <feature android:featureId="f22" android:label="@string/dummyLabel" />
- <feature android:featureId="f23" android:label="@string/dummyLabel" />
- <feature android:featureId="f24" android:label="@string/dummyLabel" />
- <feature android:featureId="f25" android:label="@string/dummyLabel" />
- <feature android:featureId="f26" android:label="@string/dummyLabel" />
- <feature android:featureId="f27" android:label="@string/dummyLabel" />
- <feature android:featureId="f28" android:label="@string/dummyLabel" />
- <feature android:featureId="f29" android:label="@string/dummyLabel" />
- <feature android:featureId="f30" android:label="@string/dummyLabel" />
- <feature android:featureId="f31" android:label="@string/dummyLabel" />
- <feature android:featureId="f32" android:label="@string/dummyLabel" />
- <feature android:featureId="f33" android:label="@string/dummyLabel" />
- <feature android:featureId="f34" android:label="@string/dummyLabel" />
- <feature android:featureId="f35" android:label="@string/dummyLabel" />
- <feature android:featureId="f36" android:label="@string/dummyLabel" />
- <feature android:featureId="f37" android:label="@string/dummyLabel" />
- <feature android:featureId="f38" android:label="@string/dummyLabel" />
- <feature android:featureId="f39" android:label="@string/dummyLabel" />
- <feature android:featureId="f40" android:label="@string/dummyLabel" />
- <feature android:featureId="f41" android:label="@string/dummyLabel" />
- <feature android:featureId="f42" android:label="@string/dummyLabel" />
- <feature android:featureId="f43" android:label="@string/dummyLabel" />
- <feature android:featureId="f44" android:label="@string/dummyLabel" />
- <feature android:featureId="f45" android:label="@string/dummyLabel" />
- <feature android:featureId="f46" android:label="@string/dummyLabel" />
- <feature android:featureId="f47" android:label="@string/dummyLabel" />
- <feature android:featureId="f48" android:label="@string/dummyLabel" />
- <feature android:featureId="f49" android:label="@string/dummyLabel" />
- <feature android:featureId="f50" android:label="@string/dummyLabel" />
- <feature android:featureId="f51" android:label="@string/dummyLabel" />
- <feature android:featureId="f52" android:label="@string/dummyLabel" />
- <feature android:featureId="f53" android:label="@string/dummyLabel" />
- <feature android:featureId="f54" android:label="@string/dummyLabel" />
- <feature android:featureId="f55" android:label="@string/dummyLabel" />
- <feature android:featureId="f56" android:label="@string/dummyLabel" />
- <feature android:featureId="f57" android:label="@string/dummyLabel" />
- <feature android:featureId="f58" android:label="@string/dummyLabel" />
- <feature android:featureId="f59" android:label="@string/dummyLabel" />
- <feature android:featureId="f60" android:label="@string/dummyLabel" />
- <feature android:featureId="f61" android:label="@string/dummyLabel" />
- <feature android:featureId="f62" android:label="@string/dummyLabel" />
- <feature android:featureId="f63" android:label="@string/dummyLabel" />
- <feature android:featureId="f64" android:label="@string/dummyLabel" />
- <feature android:featureId="f65" android:label="@string/dummyLabel" />
- <feature android:featureId="f66" android:label="@string/dummyLabel" />
- <feature android:featureId="f67" android:label="@string/dummyLabel" />
- <feature android:featureId="f68" android:label="@string/dummyLabel" />
- <feature android:featureId="f69" android:label="@string/dummyLabel" />
- <feature android:featureId="f70" android:label="@string/dummyLabel" />
- <feature android:featureId="f71" android:label="@string/dummyLabel" />
- <feature android:featureId="f72" android:label="@string/dummyLabel" />
- <feature android:featureId="f73" android:label="@string/dummyLabel" />
- <feature android:featureId="f74" android:label="@string/dummyLabel" />
- <feature android:featureId="f75" android:label="@string/dummyLabel" />
- <feature android:featureId="f76" android:label="@string/dummyLabel" />
- <feature android:featureId="f77" android:label="@string/dummyLabel" />
- <feature android:featureId="f78" android:label="@string/dummyLabel" />
- <feature android:featureId="f79" android:label="@string/dummyLabel" />
- <feature android:featureId="f80" android:label="@string/dummyLabel" />
- <feature android:featureId="f81" android:label="@string/dummyLabel" />
- <feature android:featureId="f82" android:label="@string/dummyLabel" />
- <feature android:featureId="f83" android:label="@string/dummyLabel" />
- <feature android:featureId="f84" android:label="@string/dummyLabel" />
- <feature android:featureId="f85" android:label="@string/dummyLabel" />
- <feature android:featureId="f86" android:label="@string/dummyLabel" />
- <feature android:featureId="f87" android:label="@string/dummyLabel" />
- <feature android:featureId="f88" android:label="@string/dummyLabel" />
- <feature android:featureId="f89" android:label="@string/dummyLabel" />
- <feature android:featureId="f90" android:label="@string/dummyLabel" />
- <feature android:featureId="f91" android:label="@string/dummyLabel" />
- <feature android:featureId="f92" android:label="@string/dummyLabel" />
- <feature android:featureId="f93" android:label="@string/dummyLabel" />
- <feature android:featureId="f94" android:label="@string/dummyLabel" />
- <feature android:featureId="f95" android:label="@string/dummyLabel" />
- <feature android:featureId="f96" android:label="@string/dummyLabel" />
- <feature android:featureId="f97" android:label="@string/dummyLabel" />
- <feature android:featureId="f98" android:label="@string/dummyLabel" />
- <feature android:featureId="f99" android:label="@string/dummyLabel" />
- <feature android:featureId="f100" android:label="@string/dummyLabel" />
- <feature android:featureId="f101" android:label="@string/dummyLabel" />
- <feature android:featureId="f102" android:label="@string/dummyLabel" />
- <feature android:featureId="f103" android:label="@string/dummyLabel" />
- <feature android:featureId="f104" android:label="@string/dummyLabel" />
- <feature android:featureId="f105" android:label="@string/dummyLabel" />
- <feature android:featureId="f106" android:label="@string/dummyLabel" />
- <feature android:featureId="f107" android:label="@string/dummyLabel" />
- <feature android:featureId="f108" android:label="@string/dummyLabel" />
- <feature android:featureId="f109" android:label="@string/dummyLabel" />
- <feature android:featureId="f110" android:label="@string/dummyLabel" />
- <feature android:featureId="f111" android:label="@string/dummyLabel" />
- <feature android:featureId="f112" android:label="@string/dummyLabel" />
- <feature android:featureId="f113" android:label="@string/dummyLabel" />
- <feature android:featureId="f114" android:label="@string/dummyLabel" />
- <feature android:featureId="f115" android:label="@string/dummyLabel" />
- <feature android:featureId="f116" android:label="@string/dummyLabel" />
- <feature android:featureId="f117" android:label="@string/dummyLabel" />
- <feature android:featureId="f118" android:label="@string/dummyLabel" />
- <feature android:featureId="f119" android:label="@string/dummyLabel" />
- <feature android:featureId="f120" android:label="@string/dummyLabel" />
- <feature android:featureId="f121" android:label="@string/dummyLabel" />
- <feature android:featureId="f122" android:label="@string/dummyLabel" />
- <feature android:featureId="f123" android:label="@string/dummyLabel" />
- <feature android:featureId="f124" android:label="@string/dummyLabel" />
- <feature android:featureId="f125" android:label="@string/dummyLabel" />
- <feature android:featureId="f126" android:label="@string/dummyLabel" />
- <feature android:featureId="f127" android:label="@string/dummyLabel" />
- <feature android:featureId="f128" android:label="@string/dummyLabel" />
- <feature android:featureId="f129" android:label="@string/dummyLabel" />
- <feature android:featureId="f130" android:label="@string/dummyLabel" />
- <feature android:featureId="f131" android:label="@string/dummyLabel" />
- <feature android:featureId="f132" android:label="@string/dummyLabel" />
- <feature android:featureId="f133" android:label="@string/dummyLabel" />
- <feature android:featureId="f134" android:label="@string/dummyLabel" />
- <feature android:featureId="f135" android:label="@string/dummyLabel" />
- <feature android:featureId="f136" android:label="@string/dummyLabel" />
- <feature android:featureId="f137" android:label="@string/dummyLabel" />
- <feature android:featureId="f138" android:label="@string/dummyLabel" />
- <feature android:featureId="f139" android:label="@string/dummyLabel" />
- <feature android:featureId="f140" android:label="@string/dummyLabel" />
- <feature android:featureId="f141" android:label="@string/dummyLabel" />
- <feature android:featureId="f142" android:label="@string/dummyLabel" />
- <feature android:featureId="f143" android:label="@string/dummyLabel" />
- <feature android:featureId="f144" android:label="@string/dummyLabel" />
- <feature android:featureId="f145" android:label="@string/dummyLabel" />
- <feature android:featureId="f146" android:label="@string/dummyLabel" />
- <feature android:featureId="f147" android:label="@string/dummyLabel" />
- <feature android:featureId="f148" android:label="@string/dummyLabel" />
- <feature android:featureId="f149" android:label="@string/dummyLabel" />
- <feature android:featureId="f150" android:label="@string/dummyLabel" />
- <feature android:featureId="f151" android:label="@string/dummyLabel" />
- <feature android:featureId="f152" android:label="@string/dummyLabel" />
- <feature android:featureId="f153" android:label="@string/dummyLabel" />
- <feature android:featureId="f154" android:label="@string/dummyLabel" />
- <feature android:featureId="f155" android:label="@string/dummyLabel" />
- <feature android:featureId="f156" android:label="@string/dummyLabel" />
- <feature android:featureId="f157" android:label="@string/dummyLabel" />
- <feature android:featureId="f158" android:label="@string/dummyLabel" />
- <feature android:featureId="f159" android:label="@string/dummyLabel" />
- <feature android:featureId="f160" android:label="@string/dummyLabel" />
- <feature android:featureId="f161" android:label="@string/dummyLabel" />
- <feature android:featureId="f162" android:label="@string/dummyLabel" />
- <feature android:featureId="f163" android:label="@string/dummyLabel" />
- <feature android:featureId="f164" android:label="@string/dummyLabel" />
- <feature android:featureId="f165" android:label="@string/dummyLabel" />
- <feature android:featureId="f166" android:label="@string/dummyLabel" />
- <feature android:featureId="f167" android:label="@string/dummyLabel" />
- <feature android:featureId="f168" android:label="@string/dummyLabel" />
- <feature android:featureId="f169" android:label="@string/dummyLabel" />
- <feature android:featureId="f170" android:label="@string/dummyLabel" />
- <feature android:featureId="f171" android:label="@string/dummyLabel" />
- <feature android:featureId="f172" android:label="@string/dummyLabel" />
- <feature android:featureId="f173" android:label="@string/dummyLabel" />
- <feature android:featureId="f174" android:label="@string/dummyLabel" />
- <feature android:featureId="f175" android:label="@string/dummyLabel" />
- <feature android:featureId="f176" android:label="@string/dummyLabel" />
- <feature android:featureId="f177" android:label="@string/dummyLabel" />
- <feature android:featureId="f178" android:label="@string/dummyLabel" />
- <feature android:featureId="f179" android:label="@string/dummyLabel" />
- <feature android:featureId="f180" android:label="@string/dummyLabel" />
- <feature android:featureId="f181" android:label="@string/dummyLabel" />
- <feature android:featureId="f182" android:label="@string/dummyLabel" />
- <feature android:featureId="f183" android:label="@string/dummyLabel" />
- <feature android:featureId="f184" android:label="@string/dummyLabel" />
- <feature android:featureId="f185" android:label="@string/dummyLabel" />
- <feature android:featureId="f186" android:label="@string/dummyLabel" />
- <feature android:featureId="f187" android:label="@string/dummyLabel" />
- <feature android:featureId="f188" android:label="@string/dummyLabel" />
- <feature android:featureId="f189" android:label="@string/dummyLabel" />
- <feature android:featureId="f190" android:label="@string/dummyLabel" />
- <feature android:featureId="f191" android:label="@string/dummyLabel" />
- <feature android:featureId="f192" android:label="@string/dummyLabel" />
- <feature android:featureId="f193" android:label="@string/dummyLabel" />
- <feature android:featureId="f194" android:label="@string/dummyLabel" />
- <feature android:featureId="f195" android:label="@string/dummyLabel" />
- <feature android:featureId="f196" android:label="@string/dummyLabel" />
- <feature android:featureId="f197" android:label="@string/dummyLabel" />
- <feature android:featureId="f198" android:label="@string/dummyLabel" />
- <feature android:featureId="f199" android:label="@string/dummyLabel" />
- <feature android:featureId="f200" android:label="@string/dummyLabel" />
- <feature android:featureId="f201" android:label="@string/dummyLabel" />
- <feature android:featureId="f202" android:label="@string/dummyLabel" />
- <feature android:featureId="f203" android:label="@string/dummyLabel" />
- <feature android:featureId="f204" android:label="@string/dummyLabel" />
- <feature android:featureId="f205" android:label="@string/dummyLabel" />
- <feature android:featureId="f206" android:label="@string/dummyLabel" />
- <feature android:featureId="f207" android:label="@string/dummyLabel" />
- <feature android:featureId="f208" android:label="@string/dummyLabel" />
- <feature android:featureId="f209" android:label="@string/dummyLabel" />
- <feature android:featureId="f210" android:label="@string/dummyLabel" />
- <feature android:featureId="f211" android:label="@string/dummyLabel" />
- <feature android:featureId="f212" android:label="@string/dummyLabel" />
- <feature android:featureId="f213" android:label="@string/dummyLabel" />
- <feature android:featureId="f214" android:label="@string/dummyLabel" />
- <feature android:featureId="f215" android:label="@string/dummyLabel" />
- <feature android:featureId="f216" android:label="@string/dummyLabel" />
- <feature android:featureId="f217" android:label="@string/dummyLabel" />
- <feature android:featureId="f218" android:label="@string/dummyLabel" />
- <feature android:featureId="f219" android:label="@string/dummyLabel" />
- <feature android:featureId="f220" android:label="@string/dummyLabel" />
- <feature android:featureId="f221" android:label="@string/dummyLabel" />
- <feature android:featureId="f222" android:label="@string/dummyLabel" />
- <feature android:featureId="f223" android:label="@string/dummyLabel" />
- <feature android:featureId="f224" android:label="@string/dummyLabel" />
- <feature android:featureId="f225" android:label="@string/dummyLabel" />
- <feature android:featureId="f226" android:label="@string/dummyLabel" />
- <feature android:featureId="f227" android:label="@string/dummyLabel" />
- <feature android:featureId="f228" android:label="@string/dummyLabel" />
- <feature android:featureId="f229" android:label="@string/dummyLabel" />
- <feature android:featureId="f230" android:label="@string/dummyLabel" />
- <feature android:featureId="f231" android:label="@string/dummyLabel" />
- <feature android:featureId="f232" android:label="@string/dummyLabel" />
- <feature android:featureId="f233" android:label="@string/dummyLabel" />
- <feature android:featureId="f234" android:label="@string/dummyLabel" />
- <feature android:featureId="f235" android:label="@string/dummyLabel" />
- <feature android:featureId="f236" android:label="@string/dummyLabel" />
- <feature android:featureId="f237" android:label="@string/dummyLabel" />
- <feature android:featureId="f238" android:label="@string/dummyLabel" />
- <feature android:featureId="f239" android:label="@string/dummyLabel" />
- <feature android:featureId="f240" android:label="@string/dummyLabel" />
- <feature android:featureId="f241" android:label="@string/dummyLabel" />
- <feature android:featureId="f242" android:label="@string/dummyLabel" />
- <feature android:featureId="f243" android:label="@string/dummyLabel" />
- <feature android:featureId="f244" android:label="@string/dummyLabel" />
- <feature android:featureId="f245" android:label="@string/dummyLabel" />
- <feature android:featureId="f246" android:label="@string/dummyLabel" />
- <feature android:featureId="f247" android:label="@string/dummyLabel" />
- <feature android:featureId="f248" android:label="@string/dummyLabel" />
- <feature android:featureId="f249" android:label="@string/dummyLabel" />
- <feature android:featureId="f250" android:label="@string/dummyLabel" />
- <feature android:featureId="f251" android:label="@string/dummyLabel" />
- <feature android:featureId="f252" android:label="@string/dummyLabel" />
- <feature android:featureId="f253" android:label="@string/dummyLabel" />
- <feature android:featureId="f254" android:label="@string/dummyLabel" />
- <feature android:featureId="f255" android:label="@string/dummyLabel" />
- <feature android:featureId="f256" android:label="@string/dummyLabel" />
- <feature android:featureId="f257" android:label="@string/dummyLabel" />
- <feature android:featureId="f258" android:label="@string/dummyLabel" />
- <feature android:featureId="f259" android:label="@string/dummyLabel" />
- <feature android:featureId="f260" android:label="@string/dummyLabel" />
- <feature android:featureId="f261" android:label="@string/dummyLabel" />
- <feature android:featureId="f262" android:label="@string/dummyLabel" />
- <feature android:featureId="f263" android:label="@string/dummyLabel" />
- <feature android:featureId="f264" android:label="@string/dummyLabel" />
- <feature android:featureId="f265" android:label="@string/dummyLabel" />
- <feature android:featureId="f266" android:label="@string/dummyLabel" />
- <feature android:featureId="f267" android:label="@string/dummyLabel" />
- <feature android:featureId="f268" android:label="@string/dummyLabel" />
- <feature android:featureId="f269" android:label="@string/dummyLabel" />
- <feature android:featureId="f270" android:label="@string/dummyLabel" />
- <feature android:featureId="f271" android:label="@string/dummyLabel" />
- <feature android:featureId="f272" android:label="@string/dummyLabel" />
- <feature android:featureId="f273" android:label="@string/dummyLabel" />
- <feature android:featureId="f274" android:label="@string/dummyLabel" />
- <feature android:featureId="f275" android:label="@string/dummyLabel" />
- <feature android:featureId="f276" android:label="@string/dummyLabel" />
- <feature android:featureId="f277" android:label="@string/dummyLabel" />
- <feature android:featureId="f278" android:label="@string/dummyLabel" />
- <feature android:featureId="f279" android:label="@string/dummyLabel" />
- <feature android:featureId="f280" android:label="@string/dummyLabel" />
- <feature android:featureId="f281" android:label="@string/dummyLabel" />
- <feature android:featureId="f282" android:label="@string/dummyLabel" />
- <feature android:featureId="f283" android:label="@string/dummyLabel" />
- <feature android:featureId="f284" android:label="@string/dummyLabel" />
- <feature android:featureId="f285" android:label="@string/dummyLabel" />
- <feature android:featureId="f286" android:label="@string/dummyLabel" />
- <feature android:featureId="f287" android:label="@string/dummyLabel" />
- <feature android:featureId="f288" android:label="@string/dummyLabel" />
- <feature android:featureId="f289" android:label="@string/dummyLabel" />
- <feature android:featureId="f290" android:label="@string/dummyLabel" />
- <feature android:featureId="f291" android:label="@string/dummyLabel" />
- <feature android:featureId="f292" android:label="@string/dummyLabel" />
- <feature android:featureId="f293" android:label="@string/dummyLabel" />
- <feature android:featureId="f294" android:label="@string/dummyLabel" />
- <feature android:featureId="f295" android:label="@string/dummyLabel" />
- <feature android:featureId="f296" android:label="@string/dummyLabel" />
- <feature android:featureId="f297" android:label="@string/dummyLabel" />
- <feature android:featureId="f298" android:label="@string/dummyLabel" />
- <feature android:featureId="f299" android:label="@string/dummyLabel" />
- <feature android:featureId="f300" android:label="@string/dummyLabel" />
- <feature android:featureId="f301" android:label="@string/dummyLabel" />
- <feature android:featureId="f302" android:label="@string/dummyLabel" />
- <feature android:featureId="f303" android:label="@string/dummyLabel" />
- <feature android:featureId="f304" android:label="@string/dummyLabel" />
- <feature android:featureId="f305" android:label="@string/dummyLabel" />
- <feature android:featureId="f306" android:label="@string/dummyLabel" />
- <feature android:featureId="f307" android:label="@string/dummyLabel" />
- <feature android:featureId="f308" android:label="@string/dummyLabel" />
- <feature android:featureId="f309" android:label="@string/dummyLabel" />
- <feature android:featureId="f310" android:label="@string/dummyLabel" />
- <feature android:featureId="f311" android:label="@string/dummyLabel" />
- <feature android:featureId="f312" android:label="@string/dummyLabel" />
- <feature android:featureId="f313" android:label="@string/dummyLabel" />
- <feature android:featureId="f314" android:label="@string/dummyLabel" />
- <feature android:featureId="f315" android:label="@string/dummyLabel" />
- <feature android:featureId="f316" android:label="@string/dummyLabel" />
- <feature android:featureId="f317" android:label="@string/dummyLabel" />
- <feature android:featureId="f318" android:label="@string/dummyLabel" />
- <feature android:featureId="f319" android:label="@string/dummyLabel" />
- <feature android:featureId="f320" android:label="@string/dummyLabel" />
- <feature android:featureId="f321" android:label="@string/dummyLabel" />
- <feature android:featureId="f322" android:label="@string/dummyLabel" />
- <feature android:featureId="f323" android:label="@string/dummyLabel" />
- <feature android:featureId="f324" android:label="@string/dummyLabel" />
- <feature android:featureId="f325" android:label="@string/dummyLabel" />
- <feature android:featureId="f326" android:label="@string/dummyLabel" />
- <feature android:featureId="f327" android:label="@string/dummyLabel" />
- <feature android:featureId="f328" android:label="@string/dummyLabel" />
- <feature android:featureId="f329" android:label="@string/dummyLabel" />
- <feature android:featureId="f330" android:label="@string/dummyLabel" />
- <feature android:featureId="f331" android:label="@string/dummyLabel" />
- <feature android:featureId="f332" android:label="@string/dummyLabel" />
- <feature android:featureId="f333" android:label="@string/dummyLabel" />
- <feature android:featureId="f334" android:label="@string/dummyLabel" />
- <feature android:featureId="f335" android:label="@string/dummyLabel" />
- <feature android:featureId="f336" android:label="@string/dummyLabel" />
- <feature android:featureId="f337" android:label="@string/dummyLabel" />
- <feature android:featureId="f338" android:label="@string/dummyLabel" />
- <feature android:featureId="f339" android:label="@string/dummyLabel" />
- <feature android:featureId="f340" android:label="@string/dummyLabel" />
- <feature android:featureId="f341" android:label="@string/dummyLabel" />
- <feature android:featureId="f342" android:label="@string/dummyLabel" />
- <feature android:featureId="f343" android:label="@string/dummyLabel" />
- <feature android:featureId="f344" android:label="@string/dummyLabel" />
- <feature android:featureId="f345" android:label="@string/dummyLabel" />
- <feature android:featureId="f346" android:label="@string/dummyLabel" />
- <feature android:featureId="f347" android:label="@string/dummyLabel" />
- <feature android:featureId="f348" android:label="@string/dummyLabel" />
- <feature android:featureId="f349" android:label="@string/dummyLabel" />
- <feature android:featureId="f350" android:label="@string/dummyLabel" />
- <feature android:featureId="f351" android:label="@string/dummyLabel" />
- <feature android:featureId="f352" android:label="@string/dummyLabel" />
- <feature android:featureId="f353" android:label="@string/dummyLabel" />
- <feature android:featureId="f354" android:label="@string/dummyLabel" />
- <feature android:featureId="f355" android:label="@string/dummyLabel" />
- <feature android:featureId="f356" android:label="@string/dummyLabel" />
- <feature android:featureId="f357" android:label="@string/dummyLabel" />
- <feature android:featureId="f358" android:label="@string/dummyLabel" />
- <feature android:featureId="f359" android:label="@string/dummyLabel" />
- <feature android:featureId="f360" android:label="@string/dummyLabel" />
- <feature android:featureId="f361" android:label="@string/dummyLabel" />
- <feature android:featureId="f362" android:label="@string/dummyLabel" />
- <feature android:featureId="f363" android:label="@string/dummyLabel" />
- <feature android:featureId="f364" android:label="@string/dummyLabel" />
- <feature android:featureId="f365" android:label="@string/dummyLabel" />
- <feature android:featureId="f366" android:label="@string/dummyLabel" />
- <feature android:featureId="f367" android:label="@string/dummyLabel" />
- <feature android:featureId="f368" android:label="@string/dummyLabel" />
- <feature android:featureId="f369" android:label="@string/dummyLabel" />
- <feature android:featureId="f370" android:label="@string/dummyLabel" />
- <feature android:featureId="f371" android:label="@string/dummyLabel" />
- <feature android:featureId="f372" android:label="@string/dummyLabel" />
- <feature android:featureId="f373" android:label="@string/dummyLabel" />
- <feature android:featureId="f374" android:label="@string/dummyLabel" />
- <feature android:featureId="f375" android:label="@string/dummyLabel" />
- <feature android:featureId="f376" android:label="@string/dummyLabel" />
- <feature android:featureId="f377" android:label="@string/dummyLabel" />
- <feature android:featureId="f378" android:label="@string/dummyLabel" />
- <feature android:featureId="f379" android:label="@string/dummyLabel" />
- <feature android:featureId="f380" android:label="@string/dummyLabel" />
- <feature android:featureId="f381" android:label="@string/dummyLabel" />
- <feature android:featureId="f382" android:label="@string/dummyLabel" />
- <feature android:featureId="f383" android:label="@string/dummyLabel" />
- <feature android:featureId="f384" android:label="@string/dummyLabel" />
- <feature android:featureId="f385" android:label="@string/dummyLabel" />
- <feature android:featureId="f386" android:label="@string/dummyLabel" />
- <feature android:featureId="f387" android:label="@string/dummyLabel" />
- <feature android:featureId="f388" android:label="@string/dummyLabel" />
- <feature android:featureId="f389" android:label="@string/dummyLabel" />
- <feature android:featureId="f390" android:label="@string/dummyLabel" />
- <feature android:featureId="f391" android:label="@string/dummyLabel" />
- <feature android:featureId="f392" android:label="@string/dummyLabel" />
- <feature android:featureId="f393" android:label="@string/dummyLabel" />
- <feature android:featureId="f394" android:label="@string/dummyLabel" />
- <feature android:featureId="f395" android:label="@string/dummyLabel" />
- <feature android:featureId="f396" android:label="@string/dummyLabel" />
- <feature android:featureId="f397" android:label="@string/dummyLabel" />
- <feature android:featureId="f398" android:label="@string/dummyLabel" />
- <feature android:featureId="f399" android:label="@string/dummyLabel" />
- <feature android:featureId="f400" android:label="@string/dummyLabel" />
- <feature android:featureId="f401" android:label="@string/dummyLabel" />
- <feature android:featureId="f402" android:label="@string/dummyLabel" />
- <feature android:featureId="f403" android:label="@string/dummyLabel" />
- <feature android:featureId="f404" android:label="@string/dummyLabel" />
- <feature android:featureId="f405" android:label="@string/dummyLabel" />
- <feature android:featureId="f406" android:label="@string/dummyLabel" />
- <feature android:featureId="f407" android:label="@string/dummyLabel" />
- <feature android:featureId="f408" android:label="@string/dummyLabel" />
- <feature android:featureId="f409" android:label="@string/dummyLabel" />
- <feature android:featureId="f410" android:label="@string/dummyLabel" />
- <feature android:featureId="f411" android:label="@string/dummyLabel" />
- <feature android:featureId="f412" android:label="@string/dummyLabel" />
- <feature android:featureId="f413" android:label="@string/dummyLabel" />
- <feature android:featureId="f414" android:label="@string/dummyLabel" />
- <feature android:featureId="f415" android:label="@string/dummyLabel" />
- <feature android:featureId="f416" android:label="@string/dummyLabel" />
- <feature android:featureId="f417" android:label="@string/dummyLabel" />
- <feature android:featureId="f418" android:label="@string/dummyLabel" />
- <feature android:featureId="f419" android:label="@string/dummyLabel" />
- <feature android:featureId="f420" android:label="@string/dummyLabel" />
- <feature android:featureId="f421" android:label="@string/dummyLabel" />
- <feature android:featureId="f422" android:label="@string/dummyLabel" />
- <feature android:featureId="f423" android:label="@string/dummyLabel" />
- <feature android:featureId="f424" android:label="@string/dummyLabel" />
- <feature android:featureId="f425" android:label="@string/dummyLabel" />
- <feature android:featureId="f426" android:label="@string/dummyLabel" />
- <feature android:featureId="f427" android:label="@string/dummyLabel" />
- <feature android:featureId="f428" android:label="@string/dummyLabel" />
- <feature android:featureId="f429" android:label="@string/dummyLabel" />
- <feature android:featureId="f430" android:label="@string/dummyLabel" />
- <feature android:featureId="f431" android:label="@string/dummyLabel" />
- <feature android:featureId="f432" android:label="@string/dummyLabel" />
- <feature android:featureId="f433" android:label="@string/dummyLabel" />
- <feature android:featureId="f434" android:label="@string/dummyLabel" />
- <feature android:featureId="f435" android:label="@string/dummyLabel" />
- <feature android:featureId="f436" android:label="@string/dummyLabel" />
- <feature android:featureId="f437" android:label="@string/dummyLabel" />
- <feature android:featureId="f438" android:label="@string/dummyLabel" />
- <feature android:featureId="f439" android:label="@string/dummyLabel" />
- <feature android:featureId="f440" android:label="@string/dummyLabel" />
- <feature android:featureId="f441" android:label="@string/dummyLabel" />
- <feature android:featureId="f442" android:label="@string/dummyLabel" />
- <feature android:featureId="f443" android:label="@string/dummyLabel" />
- <feature android:featureId="f444" android:label="@string/dummyLabel" />
- <feature android:featureId="f445" android:label="@string/dummyLabel" />
- <feature android:featureId="f446" android:label="@string/dummyLabel" />
- <feature android:featureId="f447" android:label="@string/dummyLabel" />
- <feature android:featureId="f448" android:label="@string/dummyLabel" />
- <feature android:featureId="f449" android:label="@string/dummyLabel" />
- <feature android:featureId="f450" android:label="@string/dummyLabel" />
- <feature android:featureId="f451" android:label="@string/dummyLabel" />
- <feature android:featureId="f452" android:label="@string/dummyLabel" />
- <feature android:featureId="f453" android:label="@string/dummyLabel" />
- <feature android:featureId="f454" android:label="@string/dummyLabel" />
- <feature android:featureId="f455" android:label="@string/dummyLabel" />
- <feature android:featureId="f456" android:label="@string/dummyLabel" />
- <feature android:featureId="f457" android:label="@string/dummyLabel" />
- <feature android:featureId="f458" android:label="@string/dummyLabel" />
- <feature android:featureId="f459" android:label="@string/dummyLabel" />
- <feature android:featureId="f460" android:label="@string/dummyLabel" />
- <feature android:featureId="f461" android:label="@string/dummyLabel" />
- <feature android:featureId="f462" android:label="@string/dummyLabel" />
- <feature android:featureId="f463" android:label="@string/dummyLabel" />
- <feature android:featureId="f464" android:label="@string/dummyLabel" />
- <feature android:featureId="f465" android:label="@string/dummyLabel" />
- <feature android:featureId="f466" android:label="@string/dummyLabel" />
- <feature android:featureId="f467" android:label="@string/dummyLabel" />
- <feature android:featureId="f468" android:label="@string/dummyLabel" />
- <feature android:featureId="f469" android:label="@string/dummyLabel" />
- <feature android:featureId="f470" android:label="@string/dummyLabel" />
- <feature android:featureId="f471" android:label="@string/dummyLabel" />
- <feature android:featureId="f472" android:label="@string/dummyLabel" />
- <feature android:featureId="f473" android:label="@string/dummyLabel" />
- <feature android:featureId="f474" android:label="@string/dummyLabel" />
- <feature android:featureId="f475" android:label="@string/dummyLabel" />
- <feature android:featureId="f476" android:label="@string/dummyLabel" />
- <feature android:featureId="f477" android:label="@string/dummyLabel" />
- <feature android:featureId="f478" android:label="@string/dummyLabel" />
- <feature android:featureId="f479" android:label="@string/dummyLabel" />
- <feature android:featureId="f480" android:label="@string/dummyLabel" />
- <feature android:featureId="f481" android:label="@string/dummyLabel" />
- <feature android:featureId="f482" android:label="@string/dummyLabel" />
- <feature android:featureId="f483" android:label="@string/dummyLabel" />
- <feature android:featureId="f484" android:label="@string/dummyLabel" />
- <feature android:featureId="f485" android:label="@string/dummyLabel" />
- <feature android:featureId="f486" android:label="@string/dummyLabel" />
- <feature android:featureId="f487" android:label="@string/dummyLabel" />
- <feature android:featureId="f488" android:label="@string/dummyLabel" />
- <feature android:featureId="f489" android:label="@string/dummyLabel" />
- <feature android:featureId="f490" android:label="@string/dummyLabel" />
- <feature android:featureId="f491" android:label="@string/dummyLabel" />
- <feature android:featureId="f492" android:label="@string/dummyLabel" />
- <feature android:featureId="f493" android:label="@string/dummyLabel" />
- <feature android:featureId="f494" android:label="@string/dummyLabel" />
- <feature android:featureId="f495" android:label="@string/dummyLabel" />
- <feature android:featureId="f496" android:label="@string/dummyLabel" />
- <feature android:featureId="f497" android:label="@string/dummyLabel" />
- <feature android:featureId="f498" android:label="@string/dummyLabel" />
- <feature android:featureId="f499" android:label="@string/dummyLabel" />
- <feature android:featureId="f500" android:label="@string/dummyLabel" />
- <feature android:featureId="f501" android:label="@string/dummyLabel" />
- <feature android:featureId="f502" android:label="@string/dummyLabel" />
- <feature android:featureId="f503" android:label="@string/dummyLabel" />
- <feature android:featureId="f504" android:label="@string/dummyLabel" />
- <feature android:featureId="f505" android:label="@string/dummyLabel" />
- <feature android:featureId="f506" android:label="@string/dummyLabel" />
- <feature android:featureId="f507" android:label="@string/dummyLabel" />
- <feature android:featureId="f508" android:label="@string/dummyLabel" />
- <feature android:featureId="f509" android:label="@string/dummyLabel" />
- <feature android:featureId="f510" android:label="@string/dummyLabel" />
- <feature android:featureId="f511" android:label="@string/dummyLabel" />
- <feature android:featureId="f512" android:label="@string/dummyLabel" />
- <feature android:featureId="f513" android:label="@string/dummyLabel" />
- <feature android:featureId="f514" android:label="@string/dummyLabel" />
- <feature android:featureId="f515" android:label="@string/dummyLabel" />
- <feature android:featureId="f516" android:label="@string/dummyLabel" />
- <feature android:featureId="f517" android:label="@string/dummyLabel" />
- <feature android:featureId="f518" android:label="@string/dummyLabel" />
- <feature android:featureId="f519" android:label="@string/dummyLabel" />
- <feature android:featureId="f520" android:label="@string/dummyLabel" />
- <feature android:featureId="f521" android:label="@string/dummyLabel" />
- <feature android:featureId="f522" android:label="@string/dummyLabel" />
- <feature android:featureId="f523" android:label="@string/dummyLabel" />
- <feature android:featureId="f524" android:label="@string/dummyLabel" />
- <feature android:featureId="f525" android:label="@string/dummyLabel" />
- <feature android:featureId="f526" android:label="@string/dummyLabel" />
- <feature android:featureId="f527" android:label="@string/dummyLabel" />
- <feature android:featureId="f528" android:label="@string/dummyLabel" />
- <feature android:featureId="f529" android:label="@string/dummyLabel" />
- <feature android:featureId="f530" android:label="@string/dummyLabel" />
- <feature android:featureId="f531" android:label="@string/dummyLabel" />
- <feature android:featureId="f532" android:label="@string/dummyLabel" />
- <feature android:featureId="f533" android:label="@string/dummyLabel" />
- <feature android:featureId="f534" android:label="@string/dummyLabel" />
- <feature android:featureId="f535" android:label="@string/dummyLabel" />
- <feature android:featureId="f536" android:label="@string/dummyLabel" />
- <feature android:featureId="f537" android:label="@string/dummyLabel" />
- <feature android:featureId="f538" android:label="@string/dummyLabel" />
- <feature android:featureId="f539" android:label="@string/dummyLabel" />
- <feature android:featureId="f540" android:label="@string/dummyLabel" />
- <feature android:featureId="f541" android:label="@string/dummyLabel" />
- <feature android:featureId="f542" android:label="@string/dummyLabel" />
- <feature android:featureId="f543" android:label="@string/dummyLabel" />
- <feature android:featureId="f544" android:label="@string/dummyLabel" />
- <feature android:featureId="f545" android:label="@string/dummyLabel" />
- <feature android:featureId="f546" android:label="@string/dummyLabel" />
- <feature android:featureId="f547" android:label="@string/dummyLabel" />
- <feature android:featureId="f548" android:label="@string/dummyLabel" />
- <feature android:featureId="f549" android:label="@string/dummyLabel" />
- <feature android:featureId="f550" android:label="@string/dummyLabel" />
- <feature android:featureId="f551" android:label="@string/dummyLabel" />
- <feature android:featureId="f552" android:label="@string/dummyLabel" />
- <feature android:featureId="f553" android:label="@string/dummyLabel" />
- <feature android:featureId="f554" android:label="@string/dummyLabel" />
- <feature android:featureId="f555" android:label="@string/dummyLabel" />
- <feature android:featureId="f556" android:label="@string/dummyLabel" />
- <feature android:featureId="f557" android:label="@string/dummyLabel" />
- <feature android:featureId="f558" android:label="@string/dummyLabel" />
- <feature android:featureId="f559" android:label="@string/dummyLabel" />
- <feature android:featureId="f560" android:label="@string/dummyLabel" />
- <feature android:featureId="f561" android:label="@string/dummyLabel" />
- <feature android:featureId="f562" android:label="@string/dummyLabel" />
- <feature android:featureId="f563" android:label="@string/dummyLabel" />
- <feature android:featureId="f564" android:label="@string/dummyLabel" />
- <feature android:featureId="f565" android:label="@string/dummyLabel" />
- <feature android:featureId="f566" android:label="@string/dummyLabel" />
- <feature android:featureId="f567" android:label="@string/dummyLabel" />
- <feature android:featureId="f568" android:label="@string/dummyLabel" />
- <feature android:featureId="f569" android:label="@string/dummyLabel" />
- <feature android:featureId="f570" android:label="@string/dummyLabel" />
- <feature android:featureId="f571" android:label="@string/dummyLabel" />
- <feature android:featureId="f572" android:label="@string/dummyLabel" />
- <feature android:featureId="f573" android:label="@string/dummyLabel" />
- <feature android:featureId="f574" android:label="@string/dummyLabel" />
- <feature android:featureId="f575" android:label="@string/dummyLabel" />
- <feature android:featureId="f576" android:label="@string/dummyLabel" />
- <feature android:featureId="f577" android:label="@string/dummyLabel" />
- <feature android:featureId="f578" android:label="@string/dummyLabel" />
- <feature android:featureId="f579" android:label="@string/dummyLabel" />
- <feature android:featureId="f580" android:label="@string/dummyLabel" />
- <feature android:featureId="f581" android:label="@string/dummyLabel" />
- <feature android:featureId="f582" android:label="@string/dummyLabel" />
- <feature android:featureId="f583" android:label="@string/dummyLabel" />
- <feature android:featureId="f584" android:label="@string/dummyLabel" />
- <feature android:featureId="f585" android:label="@string/dummyLabel" />
- <feature android:featureId="f586" android:label="@string/dummyLabel" />
- <feature android:featureId="f587" android:label="@string/dummyLabel" />
- <feature android:featureId="f588" android:label="@string/dummyLabel" />
- <feature android:featureId="f589" android:label="@string/dummyLabel" />
- <feature android:featureId="f590" android:label="@string/dummyLabel" />
- <feature android:featureId="f591" android:label="@string/dummyLabel" />
- <feature android:featureId="f592" android:label="@string/dummyLabel" />
- <feature android:featureId="f593" android:label="@string/dummyLabel" />
- <feature android:featureId="f594" android:label="@string/dummyLabel" />
- <feature android:featureId="f595" android:label="@string/dummyLabel" />
- <feature android:featureId="f596" android:label="@string/dummyLabel" />
- <feature android:featureId="f597" android:label="@string/dummyLabel" />
- <feature android:featureId="f598" android:label="@string/dummyLabel" />
- <feature android:featureId="f599" android:label="@string/dummyLabel" />
- <feature android:featureId="f600" android:label="@string/dummyLabel" />
- <feature android:featureId="f601" android:label="@string/dummyLabel" />
- <feature android:featureId="f602" android:label="@string/dummyLabel" />
- <feature android:featureId="f603" android:label="@string/dummyLabel" />
- <feature android:featureId="f604" android:label="@string/dummyLabel" />
- <feature android:featureId="f605" android:label="@string/dummyLabel" />
- <feature android:featureId="f606" android:label="@string/dummyLabel" />
- <feature android:featureId="f607" android:label="@string/dummyLabel" />
- <feature android:featureId="f608" android:label="@string/dummyLabel" />
- <feature android:featureId="f609" android:label="@string/dummyLabel" />
- <feature android:featureId="f610" android:label="@string/dummyLabel" />
- <feature android:featureId="f611" android:label="@string/dummyLabel" />
- <feature android:featureId="f612" android:label="@string/dummyLabel" />
- <feature android:featureId="f613" android:label="@string/dummyLabel" />
- <feature android:featureId="f614" android:label="@string/dummyLabel" />
- <feature android:featureId="f615" android:label="@string/dummyLabel" />
- <feature android:featureId="f616" android:label="@string/dummyLabel" />
- <feature android:featureId="f617" android:label="@string/dummyLabel" />
- <feature android:featureId="f618" android:label="@string/dummyLabel" />
- <feature android:featureId="f619" android:label="@string/dummyLabel" />
- <feature android:featureId="f620" android:label="@string/dummyLabel" />
- <feature android:featureId="f621" android:label="@string/dummyLabel" />
- <feature android:featureId="f622" android:label="@string/dummyLabel" />
- <feature android:featureId="f623" android:label="@string/dummyLabel" />
- <feature android:featureId="f624" android:label="@string/dummyLabel" />
- <feature android:featureId="f625" android:label="@string/dummyLabel" />
- <feature android:featureId="f626" android:label="@string/dummyLabel" />
- <feature android:featureId="f627" android:label="@string/dummyLabel" />
- <feature android:featureId="f628" android:label="@string/dummyLabel" />
- <feature android:featureId="f629" android:label="@string/dummyLabel" />
- <feature android:featureId="f630" android:label="@string/dummyLabel" />
- <feature android:featureId="f631" android:label="@string/dummyLabel" />
- <feature android:featureId="f632" android:label="@string/dummyLabel" />
- <feature android:featureId="f633" android:label="@string/dummyLabel" />
- <feature android:featureId="f634" android:label="@string/dummyLabel" />
- <feature android:featureId="f635" android:label="@string/dummyLabel" />
- <feature android:featureId="f636" android:label="@string/dummyLabel" />
- <feature android:featureId="f637" android:label="@string/dummyLabel" />
- <feature android:featureId="f638" android:label="@string/dummyLabel" />
- <feature android:featureId="f639" android:label="@string/dummyLabel" />
- <feature android:featureId="f640" android:label="@string/dummyLabel" />
- <feature android:featureId="f641" android:label="@string/dummyLabel" />
- <feature android:featureId="f642" android:label="@string/dummyLabel" />
- <feature android:featureId="f643" android:label="@string/dummyLabel" />
- <feature android:featureId="f644" android:label="@string/dummyLabel" />
- <feature android:featureId="f645" android:label="@string/dummyLabel" />
- <feature android:featureId="f646" android:label="@string/dummyLabel" />
- <feature android:featureId="f647" android:label="@string/dummyLabel" />
- <feature android:featureId="f648" android:label="@string/dummyLabel" />
- <feature android:featureId="f649" android:label="@string/dummyLabel" />
- <feature android:featureId="f650" android:label="@string/dummyLabel" />
- <feature android:featureId="f651" android:label="@string/dummyLabel" />
- <feature android:featureId="f652" android:label="@string/dummyLabel" />
- <feature android:featureId="f653" android:label="@string/dummyLabel" />
- <feature android:featureId="f654" android:label="@string/dummyLabel" />
- <feature android:featureId="f655" android:label="@string/dummyLabel" />
- <feature android:featureId="f656" android:label="@string/dummyLabel" />
- <feature android:featureId="f657" android:label="@string/dummyLabel" />
- <feature android:featureId="f658" android:label="@string/dummyLabel" />
- <feature android:featureId="f659" android:label="@string/dummyLabel" />
- <feature android:featureId="f660" android:label="@string/dummyLabel" />
- <feature android:featureId="f661" android:label="@string/dummyLabel" />
- <feature android:featureId="f662" android:label="@string/dummyLabel" />
- <feature android:featureId="f663" android:label="@string/dummyLabel" />
- <feature android:featureId="f664" android:label="@string/dummyLabel" />
- <feature android:featureId="f665" android:label="@string/dummyLabel" />
- <feature android:featureId="f666" android:label="@string/dummyLabel" />
- <feature android:featureId="f667" android:label="@string/dummyLabel" />
- <feature android:featureId="f668" android:label="@string/dummyLabel" />
- <feature android:featureId="f669" android:label="@string/dummyLabel" />
- <feature android:featureId="f670" android:label="@string/dummyLabel" />
- <feature android:featureId="f671" android:label="@string/dummyLabel" />
- <feature android:featureId="f672" android:label="@string/dummyLabel" />
- <feature android:featureId="f673" android:label="@string/dummyLabel" />
- <feature android:featureId="f674" android:label="@string/dummyLabel" />
- <feature android:featureId="f675" android:label="@string/dummyLabel" />
- <feature android:featureId="f676" android:label="@string/dummyLabel" />
- <feature android:featureId="f677" android:label="@string/dummyLabel" />
- <feature android:featureId="f678" android:label="@string/dummyLabel" />
- <feature android:featureId="f679" android:label="@string/dummyLabel" />
- <feature android:featureId="f680" android:label="@string/dummyLabel" />
- <feature android:featureId="f681" android:label="@string/dummyLabel" />
- <feature android:featureId="f682" android:label="@string/dummyLabel" />
- <feature android:featureId="f683" android:label="@string/dummyLabel" />
- <feature android:featureId="f684" android:label="@string/dummyLabel" />
- <feature android:featureId="f685" android:label="@string/dummyLabel" />
- <feature android:featureId="f686" android:label="@string/dummyLabel" />
- <feature android:featureId="f687" android:label="@string/dummyLabel" />
- <feature android:featureId="f688" android:label="@string/dummyLabel" />
- <feature android:featureId="f689" android:label="@string/dummyLabel" />
- <feature android:featureId="f690" android:label="@string/dummyLabel" />
- <feature android:featureId="f691" android:label="@string/dummyLabel" />
- <feature android:featureId="f692" android:label="@string/dummyLabel" />
- <feature android:featureId="f693" android:label="@string/dummyLabel" />
- <feature android:featureId="f694" android:label="@string/dummyLabel" />
- <feature android:featureId="f695" android:label="@string/dummyLabel" />
- <feature android:featureId="f696" android:label="@string/dummyLabel" />
- <feature android:featureId="f697" android:label="@string/dummyLabel" />
- <feature android:featureId="f698" android:label="@string/dummyLabel" />
- <feature android:featureId="f699" android:label="@string/dummyLabel" />
- <feature android:featureId="f700" android:label="@string/dummyLabel" />
- <feature android:featureId="f701" android:label="@string/dummyLabel" />
- <feature android:featureId="f702" android:label="@string/dummyLabel" />
- <feature android:featureId="f703" android:label="@string/dummyLabel" />
- <feature android:featureId="f704" android:label="@string/dummyLabel" />
- <feature android:featureId="f705" android:label="@string/dummyLabel" />
- <feature android:featureId="f706" android:label="@string/dummyLabel" />
- <feature android:featureId="f707" android:label="@string/dummyLabel" />
- <feature android:featureId="f708" android:label="@string/dummyLabel" />
- <feature android:featureId="f709" android:label="@string/dummyLabel" />
- <feature android:featureId="f710" android:label="@string/dummyLabel" />
- <feature android:featureId="f711" android:label="@string/dummyLabel" />
- <feature android:featureId="f712" android:label="@string/dummyLabel" />
- <feature android:featureId="f713" android:label="@string/dummyLabel" />
- <feature android:featureId="f714" android:label="@string/dummyLabel" />
- <feature android:featureId="f715" android:label="@string/dummyLabel" />
- <feature android:featureId="f716" android:label="@string/dummyLabel" />
- <feature android:featureId="f717" android:label="@string/dummyLabel" />
- <feature android:featureId="f718" android:label="@string/dummyLabel" />
- <feature android:featureId="f719" android:label="@string/dummyLabel" />
- <feature android:featureId="f720" android:label="@string/dummyLabel" />
- <feature android:featureId="f721" android:label="@string/dummyLabel" />
- <feature android:featureId="f722" android:label="@string/dummyLabel" />
- <feature android:featureId="f723" android:label="@string/dummyLabel" />
- <feature android:featureId="f724" android:label="@string/dummyLabel" />
- <feature android:featureId="f725" android:label="@string/dummyLabel" />
- <feature android:featureId="f726" android:label="@string/dummyLabel" />
- <feature android:featureId="f727" android:label="@string/dummyLabel" />
- <feature android:featureId="f728" android:label="@string/dummyLabel" />
- <feature android:featureId="f729" android:label="@string/dummyLabel" />
- <feature android:featureId="f730" android:label="@string/dummyLabel" />
- <feature android:featureId="f731" android:label="@string/dummyLabel" />
- <feature android:featureId="f732" android:label="@string/dummyLabel" />
- <feature android:featureId="f733" android:label="@string/dummyLabel" />
- <feature android:featureId="f734" android:label="@string/dummyLabel" />
- <feature android:featureId="f735" android:label="@string/dummyLabel" />
- <feature android:featureId="f736" android:label="@string/dummyLabel" />
- <feature android:featureId="f737" android:label="@string/dummyLabel" />
- <feature android:featureId="f738" android:label="@string/dummyLabel" />
- <feature android:featureId="f739" android:label="@string/dummyLabel" />
- <feature android:featureId="f740" android:label="@string/dummyLabel" />
- <feature android:featureId="f741" android:label="@string/dummyLabel" />
- <feature android:featureId="f742" android:label="@string/dummyLabel" />
- <feature android:featureId="f743" android:label="@string/dummyLabel" />
- <feature android:featureId="f744" android:label="@string/dummyLabel" />
- <feature android:featureId="f745" android:label="@string/dummyLabel" />
- <feature android:featureId="f746" android:label="@string/dummyLabel" />
- <feature android:featureId="f747" android:label="@string/dummyLabel" />
- <feature android:featureId="f748" android:label="@string/dummyLabel" />
- <feature android:featureId="f749" android:label="@string/dummyLabel" />
- <feature android:featureId="f750" android:label="@string/dummyLabel" />
- <feature android:featureId="f751" android:label="@string/dummyLabel" />
- <feature android:featureId="f752" android:label="@string/dummyLabel" />
- <feature android:featureId="f753" android:label="@string/dummyLabel" />
- <feature android:featureId="f754" android:label="@string/dummyLabel" />
- <feature android:featureId="f755" android:label="@string/dummyLabel" />
- <feature android:featureId="f756" android:label="@string/dummyLabel" />
- <feature android:featureId="f757" android:label="@string/dummyLabel" />
- <feature android:featureId="f758" android:label="@string/dummyLabel" />
- <feature android:featureId="f759" android:label="@string/dummyLabel" />
- <feature android:featureId="f760" android:label="@string/dummyLabel" />
- <feature android:featureId="f761" android:label="@string/dummyLabel" />
- <feature android:featureId="f762" android:label="@string/dummyLabel" />
- <feature android:featureId="f763" android:label="@string/dummyLabel" />
- <feature android:featureId="f764" android:label="@string/dummyLabel" />
- <feature android:featureId="f765" android:label="@string/dummyLabel" />
- <feature android:featureId="f766" android:label="@string/dummyLabel" />
- <feature android:featureId="f767" android:label="@string/dummyLabel" />
- <feature android:featureId="f768" android:label="@string/dummyLabel" />
- <feature android:featureId="f769" android:label="@string/dummyLabel" />
- <feature android:featureId="f770" android:label="@string/dummyLabel" />
- <feature android:featureId="f771" android:label="@string/dummyLabel" />
- <feature android:featureId="f772" android:label="@string/dummyLabel" />
- <feature android:featureId="f773" android:label="@string/dummyLabel" />
- <feature android:featureId="f774" android:label="@string/dummyLabel" />
- <feature android:featureId="f775" android:label="@string/dummyLabel" />
- <feature android:featureId="f776" android:label="@string/dummyLabel" />
- <feature android:featureId="f777" android:label="@string/dummyLabel" />
- <feature android:featureId="f778" android:label="@string/dummyLabel" />
- <feature android:featureId="f779" android:label="@string/dummyLabel" />
- <feature android:featureId="f780" android:label="@string/dummyLabel" />
- <feature android:featureId="f781" android:label="@string/dummyLabel" />
- <feature android:featureId="f782" android:label="@string/dummyLabel" />
- <feature android:featureId="f783" android:label="@string/dummyLabel" />
- <feature android:featureId="f784" android:label="@string/dummyLabel" />
- <feature android:featureId="f785" android:label="@string/dummyLabel" />
- <feature android:featureId="f786" android:label="@string/dummyLabel" />
- <feature android:featureId="f787" android:label="@string/dummyLabel" />
- <feature android:featureId="f788" android:label="@string/dummyLabel" />
- <feature android:featureId="f789" android:label="@string/dummyLabel" />
- <feature android:featureId="f790" android:label="@string/dummyLabel" />
- <feature android:featureId="f791" android:label="@string/dummyLabel" />
- <feature android:featureId="f792" android:label="@string/dummyLabel" />
- <feature android:featureId="f793" android:label="@string/dummyLabel" />
- <feature android:featureId="f794" android:label="@string/dummyLabel" />
- <feature android:featureId="f795" android:label="@string/dummyLabel" />
- <feature android:featureId="f796" android:label="@string/dummyLabel" />
- <feature android:featureId="f797" android:label="@string/dummyLabel" />
- <feature android:featureId="f798" android:label="@string/dummyLabel" />
- <feature android:featureId="f799" android:label="@string/dummyLabel" />
- <feature android:featureId="f800" android:label="@string/dummyLabel" />
- <feature android:featureId="f801" android:label="@string/dummyLabel" />
- <feature android:featureId="f802" android:label="@string/dummyLabel" />
- <feature android:featureId="f803" android:label="@string/dummyLabel" />
- <feature android:featureId="f804" android:label="@string/dummyLabel" />
- <feature android:featureId="f805" android:label="@string/dummyLabel" />
- <feature android:featureId="f806" android:label="@string/dummyLabel" />
- <feature android:featureId="f807" android:label="@string/dummyLabel" />
- <feature android:featureId="f808" android:label="@string/dummyLabel" />
- <feature android:featureId="f809" android:label="@string/dummyLabel" />
- <feature android:featureId="f810" android:label="@string/dummyLabel" />
- <feature android:featureId="f811" android:label="@string/dummyLabel" />
- <feature android:featureId="f812" android:label="@string/dummyLabel" />
- <feature android:featureId="f813" android:label="@string/dummyLabel" />
- <feature android:featureId="f814" android:label="@string/dummyLabel" />
- <feature android:featureId="f815" android:label="@string/dummyLabel" />
- <feature android:featureId="f816" android:label="@string/dummyLabel" />
- <feature android:featureId="f817" android:label="@string/dummyLabel" />
- <feature android:featureId="f818" android:label="@string/dummyLabel" />
- <feature android:featureId="f819" android:label="@string/dummyLabel" />
- <feature android:featureId="f820" android:label="@string/dummyLabel" />
- <feature android:featureId="f821" android:label="@string/dummyLabel" />
- <feature android:featureId="f822" android:label="@string/dummyLabel" />
- <feature android:featureId="f823" android:label="@string/dummyLabel" />
- <feature android:featureId="f824" android:label="@string/dummyLabel" />
- <feature android:featureId="f825" android:label="@string/dummyLabel" />
- <feature android:featureId="f826" android:label="@string/dummyLabel" />
- <feature android:featureId="f827" android:label="@string/dummyLabel" />
- <feature android:featureId="f828" android:label="@string/dummyLabel" />
- <feature android:featureId="f829" android:label="@string/dummyLabel" />
- <feature android:featureId="f830" android:label="@string/dummyLabel" />
- <feature android:featureId="f831" android:label="@string/dummyLabel" />
- <feature android:featureId="f832" android:label="@string/dummyLabel" />
- <feature android:featureId="f833" android:label="@string/dummyLabel" />
- <feature android:featureId="f834" android:label="@string/dummyLabel" />
- <feature android:featureId="f835" android:label="@string/dummyLabel" />
- <feature android:featureId="f836" android:label="@string/dummyLabel" />
- <feature android:featureId="f837" android:label="@string/dummyLabel" />
- <feature android:featureId="f838" android:label="@string/dummyLabel" />
- <feature android:featureId="f839" android:label="@string/dummyLabel" />
- <feature android:featureId="f840" android:label="@string/dummyLabel" />
- <feature android:featureId="f841" android:label="@string/dummyLabel" />
- <feature android:featureId="f842" android:label="@string/dummyLabel" />
- <feature android:featureId="f843" android:label="@string/dummyLabel" />
- <feature android:featureId="f844" android:label="@string/dummyLabel" />
- <feature android:featureId="f845" android:label="@string/dummyLabel" />
- <feature android:featureId="f846" android:label="@string/dummyLabel" />
- <feature android:featureId="f847" android:label="@string/dummyLabel" />
- <feature android:featureId="f848" android:label="@string/dummyLabel" />
- <feature android:featureId="f849" android:label="@string/dummyLabel" />
- <feature android:featureId="f850" android:label="@string/dummyLabel" />
- <feature android:featureId="f851" android:label="@string/dummyLabel" />
- <feature android:featureId="f852" android:label="@string/dummyLabel" />
- <feature android:featureId="f853" android:label="@string/dummyLabel" />
- <feature android:featureId="f854" android:label="@string/dummyLabel" />
- <feature android:featureId="f855" android:label="@string/dummyLabel" />
- <feature android:featureId="f856" android:label="@string/dummyLabel" />
- <feature android:featureId="f857" android:label="@string/dummyLabel" />
- <feature android:featureId="f858" android:label="@string/dummyLabel" />
- <feature android:featureId="f859" android:label="@string/dummyLabel" />
- <feature android:featureId="f860" android:label="@string/dummyLabel" />
- <feature android:featureId="f861" android:label="@string/dummyLabel" />
- <feature android:featureId="f862" android:label="@string/dummyLabel" />
- <feature android:featureId="f863" android:label="@string/dummyLabel" />
- <feature android:featureId="f864" android:label="@string/dummyLabel" />
- <feature android:featureId="f865" android:label="@string/dummyLabel" />
- <feature android:featureId="f866" android:label="@string/dummyLabel" />
- <feature android:featureId="f867" android:label="@string/dummyLabel" />
- <feature android:featureId="f868" android:label="@string/dummyLabel" />
- <feature android:featureId="f869" android:label="@string/dummyLabel" />
- <feature android:featureId="f870" android:label="@string/dummyLabel" />
- <feature android:featureId="f871" android:label="@string/dummyLabel" />
- <feature android:featureId="f872" android:label="@string/dummyLabel" />
- <feature android:featureId="f873" android:label="@string/dummyLabel" />
- <feature android:featureId="f874" android:label="@string/dummyLabel" />
- <feature android:featureId="f875" android:label="@string/dummyLabel" />
- <feature android:featureId="f876" android:label="@string/dummyLabel" />
- <feature android:featureId="f877" android:label="@string/dummyLabel" />
- <feature android:featureId="f878" android:label="@string/dummyLabel" />
- <feature android:featureId="f879" android:label="@string/dummyLabel" />
- <feature android:featureId="f880" android:label="@string/dummyLabel" />
- <feature android:featureId="f881" android:label="@string/dummyLabel" />
- <feature android:featureId="f882" android:label="@string/dummyLabel" />
- <feature android:featureId="f883" android:label="@string/dummyLabel" />
- <feature android:featureId="f884" android:label="@string/dummyLabel" />
- <feature android:featureId="f885" android:label="@string/dummyLabel" />
- <feature android:featureId="f886" android:label="@string/dummyLabel" />
- <feature android:featureId="f887" android:label="@string/dummyLabel" />
- <feature android:featureId="f888" android:label="@string/dummyLabel" />
- <feature android:featureId="f889" android:label="@string/dummyLabel" />
- <feature android:featureId="f890" android:label="@string/dummyLabel" />
- <feature android:featureId="f891" android:label="@string/dummyLabel" />
- <feature android:featureId="f892" android:label="@string/dummyLabel" />
- <feature android:featureId="f893" android:label="@string/dummyLabel" />
- <feature android:featureId="f894" android:label="@string/dummyLabel" />
- <feature android:featureId="f895" android:label="@string/dummyLabel" />
- <feature android:featureId="f896" android:label="@string/dummyLabel" />
- <feature android:featureId="f897" android:label="@string/dummyLabel" />
- <feature android:featureId="f898" android:label="@string/dummyLabel" />
- <feature android:featureId="f899" android:label="@string/dummyLabel" />
- <feature android:featureId="f900" android:label="@string/dummyLabel" />
- <feature android:featureId="f901" android:label="@string/dummyLabel" />
- <feature android:featureId="f902" android:label="@string/dummyLabel" />
- <feature android:featureId="f903" android:label="@string/dummyLabel" />
- <feature android:featureId="f904" android:label="@string/dummyLabel" />
- <feature android:featureId="f905" android:label="@string/dummyLabel" />
- <feature android:featureId="f906" android:label="@string/dummyLabel" />
- <feature android:featureId="f907" android:label="@string/dummyLabel" />
- <feature android:featureId="f908" android:label="@string/dummyLabel" />
- <feature android:featureId="f909" android:label="@string/dummyLabel" />
- <feature android:featureId="f910" android:label="@string/dummyLabel" />
- <feature android:featureId="f911" android:label="@string/dummyLabel" />
- <feature android:featureId="f912" android:label="@string/dummyLabel" />
- <feature android:featureId="f913" android:label="@string/dummyLabel" />
- <feature android:featureId="f914" android:label="@string/dummyLabel" />
- <feature android:featureId="f915" android:label="@string/dummyLabel" />
- <feature android:featureId="f916" android:label="@string/dummyLabel" />
- <feature android:featureId="f917" android:label="@string/dummyLabel" />
- <feature android:featureId="f918" android:label="@string/dummyLabel" />
- <feature android:featureId="f919" android:label="@string/dummyLabel" />
- <feature android:featureId="f920" android:label="@string/dummyLabel" />
- <feature android:featureId="f921" android:label="@string/dummyLabel" />
- <feature android:featureId="f922" android:label="@string/dummyLabel" />
- <feature android:featureId="f923" android:label="@string/dummyLabel" />
- <feature android:featureId="f924" android:label="@string/dummyLabel" />
- <feature android:featureId="f925" android:label="@string/dummyLabel" />
- <feature android:featureId="f926" android:label="@string/dummyLabel" />
- <feature android:featureId="f927" android:label="@string/dummyLabel" />
- <feature android:featureId="f928" android:label="@string/dummyLabel" />
- <feature android:featureId="f929" android:label="@string/dummyLabel" />
- <feature android:featureId="f930" android:label="@string/dummyLabel" />
- <feature android:featureId="f931" android:label="@string/dummyLabel" />
- <feature android:featureId="f932" android:label="@string/dummyLabel" />
- <feature android:featureId="f933" android:label="@string/dummyLabel" />
- <feature android:featureId="f934" android:label="@string/dummyLabel" />
- <feature android:featureId="f935" android:label="@string/dummyLabel" />
- <feature android:featureId="f936" android:label="@string/dummyLabel" />
- <feature android:featureId="f937" android:label="@string/dummyLabel" />
- <feature android:featureId="f938" android:label="@string/dummyLabel" />
- <feature android:featureId="f939" android:label="@string/dummyLabel" />
- <feature android:featureId="f940" android:label="@string/dummyLabel" />
- <feature android:featureId="f941" android:label="@string/dummyLabel" />
- <feature android:featureId="f942" android:label="@string/dummyLabel" />
- <feature android:featureId="f943" android:label="@string/dummyLabel" />
- <feature android:featureId="f944" android:label="@string/dummyLabel" />
- <feature android:featureId="f945" android:label="@string/dummyLabel" />
- <feature android:featureId="f946" android:label="@string/dummyLabel" />
- <feature android:featureId="f947" android:label="@string/dummyLabel" />
- <feature android:featureId="f948" android:label="@string/dummyLabel" />
- <feature android:featureId="f949" android:label="@string/dummyLabel" />
- <feature android:featureId="f950" android:label="@string/dummyLabel" />
- <feature android:featureId="f951" android:label="@string/dummyLabel" />
- <feature android:featureId="f952" android:label="@string/dummyLabel" />
- <feature android:featureId="f953" android:label="@string/dummyLabel" />
- <feature android:featureId="f954" android:label="@string/dummyLabel" />
- <feature android:featureId="f955" android:label="@string/dummyLabel" />
- <feature android:featureId="f956" android:label="@string/dummyLabel" />
- <feature android:featureId="f957" android:label="@string/dummyLabel" />
- <feature android:featureId="f958" android:label="@string/dummyLabel" />
- <feature android:featureId="f959" android:label="@string/dummyLabel" />
- <feature android:featureId="f960" android:label="@string/dummyLabel" />
- <feature android:featureId="f961" android:label="@string/dummyLabel" />
- <feature android:featureId="f962" android:label="@string/dummyLabel" />
- <feature android:featureId="f963" android:label="@string/dummyLabel" />
- <feature android:featureId="f964" android:label="@string/dummyLabel" />
- <feature android:featureId="f965" android:label="@string/dummyLabel" />
- <feature android:featureId="f966" android:label="@string/dummyLabel" />
- <feature android:featureId="f967" android:label="@string/dummyLabel" />
- <feature android:featureId="f968" android:label="@string/dummyLabel" />
- <feature android:featureId="f969" android:label="@string/dummyLabel" />
- <feature android:featureId="f970" android:label="@string/dummyLabel" />
- <feature android:featureId="f971" android:label="@string/dummyLabel" />
- <feature android:featureId="f972" android:label="@string/dummyLabel" />
- <feature android:featureId="f973" android:label="@string/dummyLabel" />
- <feature android:featureId="f974" android:label="@string/dummyLabel" />
- <feature android:featureId="f975" android:label="@string/dummyLabel" />
- <feature android:featureId="f976" android:label="@string/dummyLabel" />
- <feature android:featureId="f977" android:label="@string/dummyLabel" />
- <feature android:featureId="f978" android:label="@string/dummyLabel" />
- <feature android:featureId="f979" android:label="@string/dummyLabel" />
- <feature android:featureId="f980" android:label="@string/dummyLabel" />
- <feature android:featureId="f981" android:label="@string/dummyLabel" />
- <feature android:featureId="f982" android:label="@string/dummyLabel" />
- <feature android:featureId="f983" android:label="@string/dummyLabel" />
- <feature android:featureId="f984" android:label="@string/dummyLabel" />
- <feature android:featureId="f985" android:label="@string/dummyLabel" />
- <feature android:featureId="f986" android:label="@string/dummyLabel" />
- <feature android:featureId="f987" android:label="@string/dummyLabel" />
- <feature android:featureId="f988" android:label="@string/dummyLabel" />
- <feature android:featureId="f989" android:label="@string/dummyLabel" />
- <feature android:featureId="f990" android:label="@string/dummyLabel" />
- <feature android:featureId="f991" android:label="@string/dummyLabel" />
- <feature android:featureId="f992" android:label="@string/dummyLabel" />
- <feature android:featureId="f993" android:label="@string/dummyLabel" />
- <feature android:featureId="f994" android:label="@string/dummyLabel" />
- <feature android:featureId="f995" android:label="@string/dummyLabel" />
- <feature android:featureId="f996" android:label="@string/dummyLabel" />
- <feature android:featureId="f997" android:label="@string/dummyLabel" />
- <feature android:featureId="f998" android:label="@string/dummyLabel" />
- <feature android:featureId="f999" android:label="@string/dummyLabel" />
-
- <feature android:featureId="toomany" android:label="@string/dummyLabel" />
-
- <application />
-
-</manifest>
diff --git a/tests/tests/appop/aidl/AppOpsUserService/src/android/app/appops/cts/IAppOpsUserClient.aidl b/tests/tests/appop/aidl/AppOpsUserService/src/android/app/appops/cts/IAppOpsUserClient.aidl
index f3af855..e4125f7 100644
--- a/tests/tests/appop/aidl/AppOpsUserService/src/android/app/appops/cts/IAppOpsUserClient.aidl
+++ b/tests/tests/appop/aidl/AppOpsUserService/src/android/app/appops/cts/IAppOpsUserClient.aidl
@@ -18,7 +18,7 @@
interface IAppOpsUserClient {
void noteSyncOp();
- void noteSyncOpWithFeature(String featureId);
+ void noteSyncOpWithAttribution(String attributionTag);
void callBackIntoService();
void noteNonPermissionSyncOp();
void noteSyncOpTwice();
@@ -30,7 +30,7 @@
void noteSyncOpOtherUid();
void noteSyncOpOtherUidNative();
void noteAsyncOp();
- void noteAsyncOpWithFeature(String featureId);
+ void noteAsyncOpWithAttribution(String attributionTag);
void noteAsyncOpWithCustomMessage();
void noteAsyncOpNative();
void noteAsyncOpNativeWithCustomMessage();
diff --git a/tests/tests/appop/aidl/AppOpsUserService/src/android/app/appops/cts/IAppOpsUserService.aidl b/tests/tests/appop/aidl/AppOpsUserService/src/android/app/appops/cts/IAppOpsUserService.aidl
index a19705f..0b073fb 100644
--- a/tests/tests/appop/aidl/AppOpsUserService/src/android/app/appops/cts/IAppOpsUserService.aidl
+++ b/tests/tests/appop/aidl/AppOpsUserService/src/android/app/appops/cts/IAppOpsUserService.aidl
@@ -23,7 +23,7 @@
void disableCollectorAndCallASyncOpsWhichWillBeCollected(in IAppOpsUserClient client);
void callApiThatNotesSyncOpAndCheckLog(in IAppOpsUserClient client);
void callApiThatNotesSyncOpAndClearLog(in IAppOpsUserClient client);
- void callApiThatNotesSyncOpWithFeatureAndCheckLog(in IAppOpsUserClient client);
+ void callApiThatNotesSyncOpWithAttributionAndCheckLog(in IAppOpsUserClient client);
void callApiThatCallsBackIntoServiceAndCheckLog(in IAppOpsUserClient client);
void callApiThatNotesSyncOpFromNativeCodeAndCheckLog(in IAppOpsUserClient client);
void callApiThatNotesSyncOpFromNativeCodeAndCheckMessage(in IAppOpsUserClient client);
@@ -38,7 +38,7 @@
void callApiThatNotesSyncOpOtherUidAndCheckLog(in IAppOpsUserClient client);
void callApiThatNotesSyncOpOtherUidNativelyAndCheckLog(in IAppOpsUserClient client);
void callApiThatNotesAsyncOpAndCheckLog(in IAppOpsUserClient client);
- void callApiThatNotesAsyncOpWithFeatureAndCheckLog(in IAppOpsUserClient client);
+ void callApiThatNotesAsyncOpWithAttributionAndCheckLog(in IAppOpsUserClient client);
void callApiThatNotesAsyncOpAndCheckDefaultMessage(in IAppOpsUserClient client);
void callApiThatNotesAsyncOpAndCheckCustomMessage(in IAppOpsUserClient client);
void callApiThatNotesAsyncOpNativelyAndCheckCustomMessage(in IAppOpsUserClient client);
diff --git a/tests/tests/appop/appopsTestUtilLib/src/android/app/appops/cts/AppOpsUtils.kt b/tests/tests/appop/appopsTestUtilLib/src/android/app/appops/cts/AppOpsUtils.kt
index da8f8d2..b1588d5 100644
--- a/tests/tests/appop/appopsTestUtilLib/src/android/app/appops/cts/AppOpsUtils.kt
+++ b/tests/tests/appop/appopsTestUtilLib/src/android/app/appops/cts/AppOpsUtils.kt
@@ -29,7 +29,7 @@
private const val LOG_TAG = "AppOpsUtils"
private const val TIMEOUT_MILLIS = 10000L
-const val TEST_FEATURE_ID = "testFeature"
+const val TEST_ATTRIBUTION_TAG = "testAttribution"
/**
* Resets a package's app ops configuration to the device default. See AppOpsManager for the
diff --git a/tests/tests/appop/jni/android/app/appops/cts/AppOpsLoggingTest.cpp b/tests/tests/appop/jni/android/app/appops/cts/AppOpsLoggingTest.cpp
index 0b47701..a403163 100644
--- a/tests/tests/appop/jni/android/app/appops/cts/AppOpsLoggingTest.cpp
+++ b/tests/tests/appop/jni/android/app/appops/cts/AppOpsLoggingTest.cpp
@@ -29,17 +29,17 @@
// Note op from native code
extern "C" JNIEXPORT void JNICALL
Java_android_app_appops_cts_AppOpsLoggingTestKt_nativeNoteOp(JNIEnv* env, jobject obj,
- jint op, jint uid, jstring jCallingPackageName, jstring jFeatureId, jstring jMessage) {
+ jint op, jint uid, jstring jCallingPackageName, jstring jAttributionTag, jstring jMessage) {
AppOpsManager appOpsManager;
const char *nativeCallingPackageName = env->GetStringUTFChars(jCallingPackageName, 0);
String16 callingPackageName(nativeCallingPackageName);
- const char *nativeFeatureId;
- std::unique_ptr<String16> featureId;
- if (jFeatureId != nullptr) {
- nativeFeatureId = env->GetStringUTFChars(jFeatureId, 0);
- featureId = std::unique_ptr<String16>(new String16(nativeFeatureId));
+ const char *nativeAttributionTag;
+ std::unique_ptr<String16> attributionTag;
+ if (jAttributionTag != nullptr) {
+ nativeAttributionTag = env->GetStringUTFChars(jAttributionTag, 0);
+ attributionTag = std::unique_ptr<String16>(new String16(nativeAttributionTag));
}
const char *nativeMessage;
@@ -51,12 +51,12 @@
message = new String16();
}
- appOpsManager.noteOp(op, uid, callingPackageName, featureId, *message);
+ appOpsManager.noteOp(op, uid, callingPackageName, attributionTag, *message);
env->ReleaseStringUTFChars(jCallingPackageName, nativeCallingPackageName);
- if (jFeatureId != nullptr) {
- env->ReleaseStringUTFChars(jFeatureId, nativeFeatureId);
+ if (jAttributionTag != nullptr) {
+ env->ReleaseStringUTFChars(jAttributionTag, nativeAttributionTag);
}
if (jMessage != nullptr) {
diff --git a/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt b/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt
index 51bad70..103a4b2 100644
--- a/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt
@@ -96,36 +96,36 @@
}
@Test
- fun noteWithFeatureAndCheckOpEntries() {
+ fun noteWithAttributionAndCheckOpEntries() {
val before = System.currentTimeMillis()
- appOpsManager.noteOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_FEATURE_ID, null)
+ appOpsManager.noteOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_ATTRIBUTION_TAG, null)
val after = System.currentTimeMillis()
val opEntry = getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!
- val featureOpEntry = opEntry.features[TEST_FEATURE_ID]!!
+ val attributionOpEntry = opEntry.attributedOpEntries[TEST_ATTRIBUTION_TAG]!!
- assertThat(featureOpEntry.getLastAccessForegroundTime(OP_FLAG_SELF)).isIn(before..after)
+ assertThat(attributionOpEntry.getLastAccessForegroundTime(OP_FLAG_SELF)).isIn(before..after)
// Access should should also show up in the combined state for all op-flags
- assertThat(featureOpEntry.getLastAccessForegroundTime(OP_FLAGS_ALL)).isIn(before..after)
+ assertThat(attributionOpEntry.getLastAccessForegroundTime(OP_FLAGS_ALL)).isIn(before..after)
assertThat(opEntry.getLastAccessTime(OP_FLAGS_ALL)).isIn(before..after)
// Foreground access should should also show up in the combined state for fg and bg
- assertThat(featureOpEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(before..after)
+ assertThat(attributionOpEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(before..after)
assertThat(opEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(before..after)
// The access was in foreground, hence there is no background access
- assertThat(featureOpEntry.getLastBackgroundDuration(OP_FLAG_SELF)).isLessThan(before)
+ assertThat(attributionOpEntry.getLastBackgroundDuration(OP_FLAG_SELF)).isLessThan(before)
assertThat(opEntry.getLastBackgroundDuration(OP_FLAG_SELF)).isLessThan(before)
- // The access was for a feature, hence there is no access for the default feature
- if (null in opEntry.features) {
- assertThat(opEntry.features[null]!!.getLastAccessForegroundTime(OP_FLAG_SELF))
- .isLessThan(before)
+ // The access was for a attribution, hence there is no access for the default attribution
+ if (null in opEntry.attributedOpEntries) {
+ assertThat(opEntry.attributedOpEntries[null]!!
+ .getLastAccessForegroundTime(OP_FLAG_SELF)).isLessThan(before)
}
// The access does not show up for other op-flags
- assertThat(featureOpEntry.getLastAccessForegroundTime(
+ assertThat(attributionOpEntry.getLastAccessForegroundTime(
OP_FLAGS_ALL and OP_FLAG_SELF.inv())).isLessThan(before)
assertThat(opEntry.getLastAccessForegroundTime(
OP_FLAGS_ALL and OP_FLAG_SELF.inv())).isLessThan(before)
@@ -149,40 +149,40 @@
val after = System.currentTimeMillis()
val opEntry = getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!
- val featureOpEntry = opEntry.features[null]!!
+ val attributionOpEntry = opEntry.attributedOpEntries[null]!!
- assertThat(featureOpEntry.getLastAccessTime(OP_FLAG_TRUSTED_PROXY))
+ assertThat(attributionOpEntry.getLastAccessTime(OP_FLAG_TRUSTED_PROXY))
.isIn(before..afterTrusted)
- assertThat(featureOpEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(afterTrusted..after)
+ assertThat(attributionOpEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(afterTrusted..after)
assertThat(opEntry.getLastAccessTime(OP_FLAG_TRUSTED_PROXY)).isIn(before..afterTrusted)
assertThat(opEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(afterTrusted..after)
// When asked for any flags, the second access overrides the first
- assertThat(featureOpEntry.getLastAccessTime(OP_FLAGS_ALL)).isIn(afterTrusted..after)
+ assertThat(attributionOpEntry.getLastAccessTime(OP_FLAGS_ALL)).isIn(afterTrusted..after)
assertThat(opEntry.getLastAccessTime(OP_FLAGS_ALL)).isIn(afterTrusted..after)
}
@Test
- fun noteForTwoFeaturesCheckOpEntries() {
+ fun noteForTwoAttributionsCheckOpEntries() {
val before = System.currentTimeMillis()
- appOpsManager.noteOp(OPSTR_WIFI_SCAN, myUid, myPackage, "firstFeature", null)
+ appOpsManager.noteOp(OPSTR_WIFI_SCAN, myUid, myPackage, "firstAttribution", null)
val afterFirst = System.currentTimeMillis()
// Make sure timestamps are distinct
sleep(1)
// self note
- appOpsManager.noteOp(OPSTR_WIFI_SCAN, myUid, myPackage, "secondFeature", null)
+ appOpsManager.noteOp(OPSTR_WIFI_SCAN, myUid, myPackage, "secondAttribution", null)
val after = System.currentTimeMillis()
val opEntry = getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!
- val firstFeatureOpEntry = opEntry.features["firstFeature"]!!
- val secondFeatureOpEntry = opEntry.features["secondFeature"]!!
+ val firstAttributionOpEntry = opEntry.attributedOpEntries["firstAttribution"]!!
+ val secondAttributionOpEntry = opEntry.attributedOpEntries["secondAttribution"]!!
- assertThat(firstFeatureOpEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(before..afterFirst)
- assertThat(secondFeatureOpEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(afterFirst..after)
+ assertThat(firstAttributionOpEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(before..afterFirst)
+ assertThat(secondAttributionOpEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(afterFirst..after)
- // When asked for any feature, the second access overrides the first
+ // When asked for any attribution, the second access overrides the first
assertThat(opEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(afterFirst..after)
}
@@ -198,7 +198,7 @@
// Using the shell identity causes a trusted proxy note
runWithShellPermissionIdentity {
- context.createFeatureContext("firstProxyFeature")
+ context.createAttributionContext("firstProxyAttribution")
.getSystemService(AppOpsManager::class.java)
.noteProxyOp(OPSTR_WIFI_SCAN, otherPkg, otherUid, null, null)
}
@@ -207,35 +207,37 @@
sleep(1)
// untrusted proxy note
- context.createFeatureContext("secondProxyFeature")
+ context.createAttributionContext("secondProxyAttribution")
.getSystemService(AppOpsManager::class.java)
.noteProxyOp(OPSTR_WIFI_SCAN, otherPkg, otherUid, null, null)
val opEntry = getOpEntry(otherUid, otherPkg, OPSTR_WIFI_SCAN)!!
- val featureOpEntry = opEntry.features[null]!!
+ val attributionOpEntry = opEntry.attributedOpEntries[null]!!
- assertThat(featureOpEntry.getLastProxyInfo(OP_FLAG_TRUSTED_PROXIED)?.packageName)
+ assertThat(attributionOpEntry.getLastProxyInfo(OP_FLAG_TRUSTED_PROXIED)?.packageName)
.isEqualTo(myPackage)
assertThat(opEntry.getLastProxyInfo(OP_FLAG_TRUSTED_PROXIED)?.packageName)
.isEqualTo(myPackage)
- assertThat(featureOpEntry.getLastProxyInfo(OP_FLAG_TRUSTED_PROXIED)?.uid).isEqualTo(myUid)
+ assertThat(attributionOpEntry.getLastProxyInfo(OP_FLAG_TRUSTED_PROXIED)?.uid)
+ .isEqualTo(myUid)
assertThat(opEntry.getLastProxyInfo(OP_FLAG_TRUSTED_PROXIED)?.uid).isEqualTo(myUid)
- assertThat(featureOpEntry.getLastProxyInfo(OP_FLAG_UNTRUSTED_PROXIED)?.packageName)
+ assertThat(attributionOpEntry.getLastProxyInfo(OP_FLAG_UNTRUSTED_PROXIED)?.packageName)
.isEqualTo(myPackage)
assertThat(opEntry.getLastProxyInfo(OP_FLAG_UNTRUSTED_PROXIED)?.packageName)
.isEqualTo(myPackage)
- assertThat(featureOpEntry.getLastProxyInfo(OP_FLAG_UNTRUSTED_PROXIED)?.uid).isEqualTo(myUid)
+ assertThat(attributionOpEntry.getLastProxyInfo(OP_FLAG_UNTRUSTED_PROXIED)?.uid)
+ .isEqualTo(myUid)
assertThat(opEntry.getLastProxyInfo(OP_FLAG_UNTRUSTED_PROXIED)?.uid).isEqualTo(myUid)
- assertThat(featureOpEntry.getLastProxyInfo(OP_FLAG_TRUSTED_PROXIED)?.featureId)
- .isEqualTo("firstProxyFeature")
- assertThat(featureOpEntry.getLastProxyInfo(OP_FLAG_UNTRUSTED_PROXIED)?.featureId)
- .isEqualTo("secondProxyFeature")
+ assertThat(attributionOpEntry.getLastProxyInfo(OP_FLAG_TRUSTED_PROXIED)?.attributionTag)
+ .isEqualTo("firstProxyAttribution")
+ assertThat(attributionOpEntry.getLastProxyInfo(OP_FLAG_UNTRUSTED_PROXIED)?.attributionTag)
+ .isEqualTo("secondProxyAttribution")
- // If asked for all op-flags the second feature overrides the first
- assertThat(featureOpEntry.getLastProxyInfo(OP_FLAGS_ALL)?.featureId)
- .isEqualTo("secondProxyFeature")
+ // If asked for all op-flags the second attribution overrides the first
+ assertThat(attributionOpEntry.getLastProxyInfo(OP_FLAGS_ALL)?.attributionTag)
+ .isEqualTo("secondProxyAttribution")
}
@Test
@@ -243,140 +245,141 @@
appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, null, null)
with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!) {
- assertThat(features[null]!!.isRunning).isTrue()
- features[TEST_FEATURE_ID]?.let { assertThat(it.isRunning).isFalse() }
+ assertThat(attributedOpEntries[null]!!.isRunning).isTrue()
+ attributedOpEntries[TEST_ATTRIBUTION_TAG]?.let { assertThat(it.isRunning).isFalse() }
assertThat(isRunning).isTrue()
}
- appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_FEATURE_ID, null)
+ appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_ATTRIBUTION_TAG, null)
with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!) {
- assertThat(features[null]!!.isRunning).isTrue()
- assertThat(features[TEST_FEATURE_ID]!!.isRunning).isTrue()
+ assertThat(attributedOpEntries[null]!!.isRunning).isTrue()
+ assertThat(attributedOpEntries[TEST_ATTRIBUTION_TAG]!!.isRunning).isTrue()
assertThat(isRunning).isTrue()
}
- appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_FEATURE_ID, null)
+ appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_ATTRIBUTION_TAG, null)
with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!) {
- assertThat(features[null]!!.isRunning).isTrue()
- assertThat(features[TEST_FEATURE_ID]!!.isRunning).isTrue()
+ assertThat(attributedOpEntries[null]!!.isRunning).isTrue()
+ assertThat(attributedOpEntries[TEST_ATTRIBUTION_TAG]!!.isRunning).isTrue()
assertThat(isRunning).isTrue()
}
- appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_FEATURE_ID)
+ appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_ATTRIBUTION_TAG)
with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!) {
- assertThat(features[null]!!.isRunning).isTrue()
- assertThat(features[TEST_FEATURE_ID]!!.isRunning).isTrue()
+ assertThat(attributedOpEntries[null]!!.isRunning).isTrue()
+ assertThat(attributedOpEntries[TEST_ATTRIBUTION_TAG]!!.isRunning).isTrue()
assertThat(isRunning).isTrue()
}
- appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_FEATURE_ID)
+ appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_ATTRIBUTION_TAG)
with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!) {
- assertThat(features[null]!!.isRunning).isTrue()
- assertThat(features[TEST_FEATURE_ID]!!.isRunning).isFalse()
+ assertThat(attributedOpEntries[null]!!.isRunning).isTrue()
+ assertThat(attributedOpEntries[TEST_ATTRIBUTION_TAG]!!.isRunning).isFalse()
assertThat(isRunning).isTrue()
}
appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, null)
with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!) {
- assertThat(features[null]!!.isRunning).isFalse()
- assertThat(features[TEST_FEATURE_ID]!!.isRunning).isFalse()
+ assertThat(attributedOpEntries[null]!!.isRunning).isFalse()
+ assertThat(attributedOpEntries[TEST_ATTRIBUTION_TAG]!!.isRunning).isFalse()
assertThat(isRunning).isFalse()
}
}
@Test
fun startStopMultipleOpsAndVerifyLastAccess() {
- val beforeNullFeatureStart = System.currentTimeMillis()
+ val beforeNullAttributionStart = System.currentTimeMillis()
appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, null, null)
- val afterNullFeatureStart = System.currentTimeMillis()
+ val afterNullAttributionStart = System.currentTimeMillis()
with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!) {
- assertThat(features[null]!!.getLastAccessTime(OP_FLAGS_ALL))
- .isIn(beforeNullFeatureStart..afterNullFeatureStart)
- features[TEST_FEATURE_ID]?.let {
- assertThat(it.getLastAccessTime(OP_FLAGS_ALL)).isAtMost(beforeNullFeatureStart)
+ assertThat(attributedOpEntries[null]!!.getLastAccessTime(OP_FLAGS_ALL))
+ .isIn(beforeNullAttributionStart..afterNullAttributionStart)
+ attributedOpEntries[TEST_ATTRIBUTION_TAG]?.let {
+ assertThat(it.getLastAccessTime(OP_FLAGS_ALL)).isAtMost(beforeNullAttributionStart)
}
assertThat(getLastAccessTime(OP_FLAGS_ALL))
- .isIn(beforeNullFeatureStart..afterNullFeatureStart)
+ .isIn(beforeNullAttributionStart..afterNullAttributionStart)
}
- val beforeFirstFeatureStart = System.currentTimeMillis()
- appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_FEATURE_ID, null)
- val afterFirstFeatureStart = System.currentTimeMillis()
+ val beforeFirstAttributionStart = System.currentTimeMillis()
+ appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_ATTRIBUTION_TAG, null)
+ val afterFirstAttributionStart = System.currentTimeMillis()
with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!) {
- assertThat(features[null]!!.getLastAccessTime(OP_FLAGS_ALL))
- .isIn(beforeNullFeatureStart..afterNullFeatureStart)
- assertThat(features[TEST_FEATURE_ID]!!.getLastAccessTime(OP_FLAGS_ALL))
- .isIn(beforeFirstFeatureStart..afterFirstFeatureStart)
+ assertThat(attributedOpEntries[null]!!.getLastAccessTime(OP_FLAGS_ALL))
+ .isIn(beforeNullAttributionStart..afterNullAttributionStart)
+ assertThat(attributedOpEntries[TEST_ATTRIBUTION_TAG]!!.getLastAccessTime(OP_FLAGS_ALL))
+ .isIn(beforeFirstAttributionStart..afterFirstAttributionStart)
assertThat(getLastAccessTime(OP_FLAGS_ALL))
- .isIn(beforeFirstFeatureStart..afterFirstFeatureStart)
+ .isIn(beforeFirstAttributionStart..afterFirstAttributionStart)
}
- appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_FEATURE_ID, null)
+ appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_ATTRIBUTION_TAG, null)
// Nested startOps do _not_ count as another access
with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!) {
- assertThat(features[null]!!.getLastAccessTime(OP_FLAGS_ALL))
- .isIn(beforeNullFeatureStart..afterNullFeatureStart)
- assertThat(features[TEST_FEATURE_ID]!!.getLastAccessTime(OP_FLAGS_ALL))
- .isIn(beforeFirstFeatureStart..afterFirstFeatureStart)
+ assertThat(attributedOpEntries[null]!!.getLastAccessTime(OP_FLAGS_ALL))
+ .isIn(beforeNullAttributionStart..afterNullAttributionStart)
+ assertThat(attributedOpEntries[TEST_ATTRIBUTION_TAG]!!.getLastAccessTime(OP_FLAGS_ALL))
+ .isIn(beforeFirstAttributionStart..afterFirstAttributionStart)
assertThat(getLastAccessTime(OP_FLAGS_ALL))
- .isIn(beforeFirstFeatureStart..afterFirstFeatureStart)
+ .isIn(beforeFirstAttributionStart..afterFirstAttributionStart)
}
- appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_FEATURE_ID)
- appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_FEATURE_ID)
+ appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_ATTRIBUTION_TAG)
+ appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_ATTRIBUTION_TAG)
appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, null)
}
@Test
fun startStopMultipleOpsAndVerifyDuration() {
- val beforeNullFeatureStart = SystemClock.elapsedRealtime()
+ val beforeNullAttributionStart = SystemClock.elapsedRealtime()
appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, null, null)
- val afterNullFeatureStart = SystemClock.elapsedRealtime()
+ val afterNullAttributionStart = SystemClock.elapsedRealtime()
run {
val beforeGetOp = SystemClock.elapsedRealtime()
with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!) {
val afterGetOp = SystemClock.elapsedRealtime()
- assertThat(features[null]!!.getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeGetOp - afterNullFeatureStart
- ..afterGetOp - beforeNullFeatureStart)
+ assertThat(attributedOpEntries[null]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterNullAttributionStart
+ ..afterGetOp - beforeNullAttributionStart)
assertThat(getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeGetOp - afterNullFeatureStart
- ..afterGetOp - beforeNullFeatureStart)
+ .isIn(beforeGetOp - afterNullAttributionStart
+ ..afterGetOp - beforeNullAttributionStart)
}
}
- val beforeFeatureStart = SystemClock.elapsedRealtime()
- appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_FEATURE_ID, null)
- val afterFeatureStart = SystemClock.elapsedRealtime()
+ val beforeAttributionStart = SystemClock.elapsedRealtime()
+ appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_ATTRIBUTION_TAG, null)
+ val afterAttributionStart = SystemClock.elapsedRealtime()
run {
val beforeGetOp = SystemClock.elapsedRealtime()
with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!) {
val afterGetOp = SystemClock.elapsedRealtime()
- assertThat(features[null]!!.getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeGetOp - afterNullFeatureStart
- ..afterGetOp - beforeNullFeatureStart)
- assertThat(features[TEST_FEATURE_ID]!!.getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeGetOp - afterFeatureStart..afterGetOp - beforeFeatureStart)
+ assertThat(attributedOpEntries[null]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterNullAttributionStart
+ ..afterGetOp - beforeNullAttributionStart)
+ assertThat(attributedOpEntries[TEST_ATTRIBUTION_TAG]!!
+ .getLastDuration(OP_FLAGS_ALL)).isIn(beforeGetOp -
+ afterAttributionStart..afterGetOp - beforeAttributionStart)
- // The last duration is the duration of the last started feature
- assertThat(getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeGetOp - afterFeatureStart..afterGetOp - beforeFeatureStart)
+ // The last duration is the duration of the last started attribution
+ assertThat(getLastDuration(OP_FLAGS_ALL)).isIn(beforeGetOp -
+ afterAttributionStart..afterGetOp - beforeAttributionStart)
}
}
- appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_FEATURE_ID, null)
+ appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_ATTRIBUTION_TAG, null)
// Nested startOps do _not_ start another duration counting, hence the nested
// startOp and finishOp calls have no affect
@@ -385,68 +388,72 @@
with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!) {
val afterGetOp = SystemClock.elapsedRealtime()
- assertThat(features[null]!!.getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeGetOp - afterNullFeatureStart
- ..afterGetOp - beforeNullFeatureStart)
- assertThat(features[TEST_FEATURE_ID]!!.getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeGetOp - afterFeatureStart..afterGetOp - beforeFeatureStart)
+ assertThat(attributedOpEntries[null]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterNullAttributionStart
+ ..afterGetOp - beforeNullAttributionStart)
+ assertThat(attributedOpEntries[TEST_ATTRIBUTION_TAG]!!
+ .getLastDuration(OP_FLAGS_ALL)).isIn(beforeGetOp -
+ afterAttributionStart..afterGetOp - beforeAttributionStart)
assertThat(getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeGetOp - afterFeatureStart..afterGetOp - beforeFeatureStart)
+ .isIn(beforeGetOp -
+ afterAttributionStart..afterGetOp - beforeAttributionStart)
}
}
- appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_FEATURE_ID)
+ appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_ATTRIBUTION_TAG)
run {
val beforeGetOp = SystemClock.elapsedRealtime()
with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!) {
val afterGetOp = SystemClock.elapsedRealtime()
- assertThat(features[null]!!.getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeGetOp - afterNullFeatureStart
- ..afterGetOp - beforeNullFeatureStart)
- assertThat(features[TEST_FEATURE_ID]!!.getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeGetOp - afterFeatureStart..afterGetOp - beforeFeatureStart)
- assertThat(getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeGetOp - afterFeatureStart..afterGetOp - beforeFeatureStart)
+ assertThat(attributedOpEntries[null]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterNullAttributionStart
+ ..afterGetOp - beforeNullAttributionStart)
+ assertThat(attributedOpEntries[TEST_ATTRIBUTION_TAG]!!
+ .getLastDuration(OP_FLAGS_ALL)).isIn(beforeGetOp -
+ afterAttributionStart..afterGetOp - beforeAttributionStart)
+ assertThat(getLastDuration(OP_FLAGS_ALL)).isIn(beforeGetOp -
+ afterAttributionStart..afterGetOp - beforeAttributionStart)
}
}
- val beforeFeatureStop = SystemClock.elapsedRealtime()
- appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_FEATURE_ID)
- val afterFeatureStop = SystemClock.elapsedRealtime()
+ val beforeAttributionStop = SystemClock.elapsedRealtime()
+ appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, TEST_ATTRIBUTION_TAG)
+ val afterAttributionStop = SystemClock.elapsedRealtime()
run {
val beforeGetOp = SystemClock.elapsedRealtime()
with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!) {
val afterGetOp = SystemClock.elapsedRealtime()
- assertThat(features[null]!!.getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeGetOp - afterNullFeatureStart
- ..afterGetOp - beforeNullFeatureStart)
- assertThat(features[TEST_FEATURE_ID]!!.getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeFeatureStop - afterFeatureStart
- ..afterFeatureStop - beforeFeatureStart)
+ assertThat(attributedOpEntries[null]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterNullAttributionStart
+ ..afterGetOp - beforeNullAttributionStart)
+ assertThat(attributedOpEntries[TEST_ATTRIBUTION_TAG]!!
+ .getLastDuration(OP_FLAGS_ALL)).isIn(
+ beforeAttributionStop - afterAttributionStart
+ ..afterAttributionStop - beforeAttributionStart)
assertThat(getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeFeatureStop - afterFeatureStart
- ..afterFeatureStop - beforeFeatureStart)
+ .isIn(beforeAttributionStop - afterAttributionStart
+ ..afterAttributionStop - beforeAttributionStart)
}
}
- val beforeNullFeatureStop = SystemClock.elapsedRealtime()
+ val beforeNullAttributionStop = SystemClock.elapsedRealtime()
appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, null)
- val afterNullFeatureStop = SystemClock.elapsedRealtime()
+ val afterNullAttributionStop = SystemClock.elapsedRealtime()
with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)!!) {
- assertThat(features[null]!!.getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeNullFeatureStop - afterNullFeatureStart
- ..afterNullFeatureStop - beforeNullFeatureStart)
- assertThat(features[TEST_FEATURE_ID]!!.getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeFeatureStop - afterFeatureStart
- ..afterFeatureStop - beforeFeatureStart)
+ assertThat(attributedOpEntries[null]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeNullAttributionStop - afterNullAttributionStart
+ ..afterNullAttributionStop - beforeNullAttributionStart)
+ assertThat(attributedOpEntries[TEST_ATTRIBUTION_TAG]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeAttributionStop - afterAttributionStart
+ ..afterAttributionStop - beforeAttributionStart)
assertThat(getLastDuration(OP_FLAGS_ALL))
- .isIn(beforeFeatureStop - afterFeatureStart
- ..afterFeatureStop - beforeFeatureStart)
+ .isIn(beforeAttributionStop - afterAttributionStart
+ ..afterAttributionStop - beforeAttributionStart)
}
}
}
diff --git a/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt b/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt
index 2b92c7f..74fa394 100644
--- a/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt
@@ -25,7 +25,6 @@
import android.app.AppOpsManager.OPSTR_GET_ACCOUNTS
import android.app.AppOpsManager.OPSTR_READ_CONTACTS
import android.app.AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE
-import android.app.AppOpsManager.OPSTR_READ_PHONE_STATE
import android.app.AppOpsManager.OPSTR_WRITE_CONTACTS
import android.app.AppOpsManager.strOpToOp
import android.app.AsyncNotedAppOp
@@ -57,7 +56,6 @@
import android.os.Looper
import android.platform.test.annotations.AppModeFull
import android.provider.ContactsContract
-import android.telecom.TelecomManager
import android.telephony.TelephonyManager
import androidx.test.platform.app.InstrumentationRegistry
import com.google.common.truth.Truth.assertThat
@@ -78,7 +76,7 @@
op: Int,
uid: Int,
packageName: String,
- featureId: String? = null,
+ attributionTag: String? = null,
message: String? = null
)
@@ -168,15 +166,16 @@
assertThat(noted).isEmpty()
assertThat(asyncNoted).isEmpty()
- assertThat(selfNoted.map { it.first.featureId to it.first.op })
+ assertThat(selfNoted.map { it.first.attributionTag to it.first.op })
.containsExactly(null to OPSTR_COARSE_LOCATION)
}
@Test
- fun selfNoteAndCheckFeature() {
- appOpsManager.noteOpNoThrow(OPSTR_COARSE_LOCATION, myUid, myPackage, TEST_FEATURE_ID, null)
+ fun selfNoteAndCheckAttribution() {
+ appOpsManager.noteOpNoThrow(OPSTR_COARSE_LOCATION, myUid, myPackage, TEST_ATTRIBUTION_TAG,
+ null)
- assertThat(selfNoted.map { it.first.featureId }).containsExactly(TEST_FEATURE_ID)
+ assertThat(selfNoted.map { it.first.attributionTag }).containsExactly(TEST_ATTRIBUTION_TAG)
}
@Test
@@ -188,7 +187,7 @@
// All native notes will be reported as async notes
eventually {
- assertThat(asyncNoted[0].featureId).isEqualTo(null)
+ assertThat(asyncNoted[0].attributionTag).isEqualTo(null)
// There is always a message.
assertThat(asyncNoted[0].message).isNotEqualTo(null)
assertThat(asyncNoted[0].op).isEqualTo(OPSTR_COARSE_LOCATION)
@@ -197,13 +196,13 @@
}
@Test
- fun nativeSelfNoteWithFeatureAndMsgAndCheckLog() {
+ fun nativeSelfNoteWithAttributionAndMsgAndCheckLog() {
nativeNoteOp(strOpToOp(OPSTR_COARSE_LOCATION), myUid, myPackage,
- featureId = TEST_FEATURE_ID, message = "testMsg")
+ attributionTag = TEST_ATTRIBUTION_TAG, message = "testMsg")
// All native notes will be reported as async notes
eventually {
- assertThat(asyncNoted[0].featureId).isEqualTo(TEST_FEATURE_ID)
+ assertThat(asyncNoted[0].attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
assertThat(asyncNoted[0].message).isEqualTo("testMsg")
}
}
@@ -232,9 +231,9 @@
}
@Test
- fun noteSyncWithFeatureOpAndCheckLog() {
+ fun noteSyncWithAttributionOpAndCheckLog() {
rethrowThrowableFrom {
- testService.callApiThatNotesSyncOpWithFeatureAndCheckLog(AppOpsUserClient(context))
+ testService.callApiThatNotesSyncOpWithAttributionAndCheckLog(AppOpsUserClient(context))
}
}
@@ -341,9 +340,9 @@
}
@Test
- fun noteAsyncOpWithFeatureAndCheckLog() {
+ fun noteAsyncOpWithAttributionAndCheckLog() {
rethrowThrowableFrom {
- testService.callApiThatNotesAsyncOpWithFeatureAndCheckLog(AppOpsUserClient(context))
+ testService.callApiThatNotesAsyncOpWithAttributionAndCheckLog(AppOpsUserClient(context))
}
}
@@ -381,13 +380,13 @@
*/
@Test
fun getWifiScanResults() {
- val wifiManager = context.createFeatureContext(TEST_FEATURE_ID)
+ val wifiManager = context.createAttributionContext(TEST_ATTRIBUTION_TAG)
.getSystemService(WifiManager::class.java)
val results = wifiManager.scanResults
assertThat(noted[0].first.op).isEqualTo(OPSTR_FINE_LOCATION)
- assertThat(noted[0].first.featureId).isEqualTo(TEST_FEATURE_ID)
+ assertThat(noted[0].first.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
assertThat(noted[0].second.map { it.methodName }).contains("getWifiScanResults")
}
@@ -399,13 +398,13 @@
assumeTrue("Device does not support bluetooth",
context.packageManager.hasSystemFeature(FEATURE_BLUETOOTH))
- val btManager = context.createFeatureContext(TEST_FEATURE_ID)
+ val btManager = context.createAttributionContext(TEST_ATTRIBUTION_TAG)
.getSystemService(BluetoothManager::class.java)
btManager.adapter.startDiscovery()
try {
assertThat(noted[0].first.op).isEqualTo(OPSTR_FINE_LOCATION)
- assertThat(noted[0].first.featureId).isEqualTo(TEST_FEATURE_ID)
+ assertThat(noted[0].first.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
assertThat(noted[0].second.map { it.methodName }).contains("getBTScanResults")
} finally {
btManager.adapter.cancelDiscovery()
@@ -417,7 +416,7 @@
*/
@Test
fun getLastKnownLocation() {
- val locationManager = context.createFeatureContext(TEST_FEATURE_ID)
+ val locationManager = context.createAttributionContext(TEST_ATTRIBUTION_TAG)
.getSystemService(LocationManager::class.java)
assumeTrue("Device does not have a network provider",
@@ -428,7 +427,7 @@
assertThat(noted.map { it.first.op }).containsAnyOf(OPSTR_COARSE_LOCATION,
OPSTR_FINE_LOCATION)
- assertThat(noted[0].first.featureId).isEqualTo(TEST_FEATURE_ID)
+ assertThat(noted[0].first.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
assertThat(noted[0].second.map { it.methodName }).contains("getLastKnownLocation")
}
@@ -437,7 +436,7 @@
*/
@Test
fun getAsyncLocation() {
- val locationManager = context.createFeatureContext(TEST_FEATURE_ID)
+ val locationManager = context.createAttributionContext(TEST_ATTRIBUTION_TAG)
.getSystemService(LocationManager::class.java)
assumeTrue("Device does not have a network provider",
@@ -467,7 +466,7 @@
eventually {
assertThat(asyncNoted.map { it.op }).containsAnyOf(OPSTR_COARSE_LOCATION,
OPSTR_FINE_LOCATION)
- assertThat(asyncNoted[0].featureId).isEqualTo(TEST_FEATURE_ID)
+ assertThat(asyncNoted[0].attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
assertThat(asyncNoted[0].message).contains(locationListener::class.java.name)
assertThat(asyncNoted[0].message).contains(
@@ -484,7 +483,7 @@
val gotProximityAlert = CompletableFuture<Unit>()
- val locationManager = context.createFeatureContext(TEST_FEATURE_ID)
+ val locationManager = context.createAttributionContext(TEST_ATTRIBUTION_TAG)
.getSystemService(LocationManager::class.java)!!
val proximityAlertReceiver = object : BroadcastReceiver() {
@@ -511,7 +510,7 @@
eventually {
assertThat(asyncNoted.map { it.op }).contains(OPSTR_FINE_LOCATION)
- assertThat(asyncNoted[0].featureId).isEqualTo(TEST_FEATURE_ID)
+ assertThat(asyncNoted[0].attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
assertThat(asyncNoted[0].message).contains(
proximityAlertReceiverPendingIntent::class.java.name)
@@ -532,11 +531,11 @@
*/
@Test
fun readFromContactsProvider() {
- context.createFeatureContext(TEST_FEATURE_ID).contentResolver
+ context.createAttributionContext(TEST_ATTRIBUTION_TAG).contentResolver
.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null)
assertThat(noted.map { it.first.op }).containsExactly(OPSTR_READ_CONTACTS)
- assertThat(noted[0].first.featureId).isEqualTo(TEST_FEATURE_ID)
+ assertThat(noted[0].first.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
assertThat(noted[0].second.map { it.methodName }).contains("readFromContactsProvider")
}
@@ -545,11 +544,11 @@
*/
@Test
fun writeToContactsProvider() {
- context.createFeatureContext(TEST_FEATURE_ID).contentResolver
+ context.createAttributionContext(TEST_ATTRIBUTION_TAG).contentResolver
.insert(ContactsContract.RawContacts.CONTENT_URI, ContentValues())
assertThat(noted.map { it.first.op }).containsExactly(OPSTR_WRITE_CONTACTS)
- assertThat(noted[0].first.featureId).isEqualTo(TEST_FEATURE_ID)
+ assertThat(noted[0].first.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
assertThat(noted[0].second.map { it.methodName }).contains("writeToContactsProvider")
}
@@ -560,13 +559,13 @@
fun getCellInfo() {
assumeTrue(context.packageManager.hasSystemFeature(FEATURE_TELEPHONY))
- val telephonyManager = context.createFeatureContext(TEST_FEATURE_ID)
+ val telephonyManager = context.createAttributionContext(TEST_ATTRIBUTION_TAG)
.getSystemService(TelephonyManager::class.java)
telephonyManager.allCellInfo
assertThat(noted[0].first.op).isEqualTo(OPSTR_FINE_LOCATION)
- assertThat(noted[0].first.featureId).isEqualTo(TEST_FEATURE_ID)
+ assertThat(noted[0].first.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
assertThat(noted[0].second.map { it.methodName }).contains("getCellInfo")
}
@@ -591,7 +590,7 @@
eventually {
assertThat(asyncNoted[0].op).isEqualTo(OPSTR_CAMERA)
- assertThat(asyncNoted[0].featureId).isEqualTo(context.featureId)
+ assertThat(asyncNoted[0].attributionTag).isEqualTo(context.attributionTag)
assertThat(asyncNoted[0].message).contains(cameraManager.cameraIdList[0])
}
}
@@ -600,34 +599,17 @@
* Realistic end-to-end test for opening camera
*/
@Test
- fun openCameraWithFeature() {
- openCamera(context.createFeatureContext(TEST_FEATURE_ID))
+ fun openCameraWithAttribution() {
+ openCamera(context.createAttributionContext(TEST_ATTRIBUTION_TAG))
}
/**
- * Realistic end-to-end test for opening camera. This uses the default (==null) feature. This
- * is interesting as null feature handling is more complex in native code.
+ * Realistic end-to-end test for opening camera. This uses the default (==null) attribution.
+ * This is interesting as null attribution handling is more complex in native code.
*/
@Test
- fun openCameraWithDefaultFeature() {
- openCamera(context.createFeatureContext(null))
- }
-
- /**
- * Realistic end-to-end test for getting cell info
- */
- @Test
- fun getMultiSimSupport() {
- assumeTrue(context.packageManager.hasSystemFeature(FEATURE_TELEPHONY))
-
- val telephonyManager = context.createFeatureContext(TEST_FEATURE_ID)
- .getSystemService(TelephonyManager::class.java)
-
- telephonyManager.isMultiSimSupported
-
- assertThat(noted[0].first.op).isEqualTo(OPSTR_READ_PHONE_STATE)
- assertThat(noted[0].first.featureId).isEqualTo(TEST_FEATURE_ID)
- assertThat(noted[0].second.map { it.methodName }).contains("getMultiSimSupport")
+ fun openCameraWithDefaultAttribution() {
+ openCamera(context.createAttributionContext(null))
}
/**
@@ -635,43 +617,28 @@
*/
@Test
fun getWallpaper() {
- val wallpaperManager = context.createFeatureContext(TEST_FEATURE_ID)
+ val wallpaperManager = context.createAttributionContext(TEST_ATTRIBUTION_TAG)
.getSystemService(WallpaperManager::class.java)
wallpaperManager.getWallpaperFile(FLAG_SYSTEM)
assertThat(noted[0].first.op).isEqualTo(OPSTR_READ_EXTERNAL_STORAGE)
- assertThat(noted[0].first.featureId).isEqualTo(TEST_FEATURE_ID)
+ assertThat(noted[0].first.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
assertThat(noted[0].second.map { it.methodName }).contains("getWallpaper")
}
/**
- * Realistic end-to-end test for checking if currently in call
- */
- @Test
- fun isInCall() {
- val telecomManager = context.createFeatureContext(TEST_FEATURE_ID)
- .getSystemService(TelecomManager::class.java)
-
- telecomManager.isInCall()
-
- assertThat(noted[0].first.op).isEqualTo(OPSTR_READ_PHONE_STATE)
- assertThat(noted[0].first.featureId).isEqualTo(TEST_FEATURE_ID)
- assertThat(noted[0].second.map { it.methodName }).contains("isInCall")
- }
-
- /**
* Realistic end-to-end test for starting a permission protected activity
*/
@Test
fun startActivity() {
- context.createFeatureContext(TEST_FEATURE_ID).startActivity(
+ context.createAttributionContext(TEST_ATTRIBUTION_TAG).startActivity(
Intent().setComponent(ComponentName(TEST_SERVICE_PKG,
TEST_SERVICE_PKG + ".AutoClosingActivity"))
.setFlags(FLAG_ACTIVITY_NEW_TASK))
assertThat(noted[0].first.op).isEqualTo(OPSTR_FINE_LOCATION)
- assertThat(noted[0].first.featureId).isEqualTo(TEST_FEATURE_ID)
+ assertThat(noted[0].first.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
assertThat(noted[0].second.map { it.methodName }).contains("startActivity")
}
@@ -706,10 +673,10 @@
}
}
- override fun noteSyncOpWithFeature(featureId: String) {
+ override fun noteSyncOpWithAttribution(attributionTag: String) {
runWithShellPermissionIdentity {
appOpsManager.noteOpNoThrow(OPSTR_COARSE_LOCATION, getCallingUid(),
- TEST_SERVICE_PKG, featureId, null)
+ TEST_SERVICE_PKG, attributionTag, null)
}
}
@@ -789,13 +756,13 @@
}
}
- override fun noteAsyncOpWithFeature(featureId: String) {
+ override fun noteAsyncOpWithAttribution(attributionTag: String) {
val callingUid = getCallingUid()
handler.post {
runWithShellPermissionIdentity {
appOpsManager.noteOpNoThrow(OPSTR_COARSE_LOCATION, callingUid, TEST_SERVICE_PKG,
- featureId, null)
+ attributionTag, null)
}
}
}
diff --git a/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt b/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt
index f9f8d47..3b4dda1 100644
--- a/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt
@@ -228,7 +228,7 @@
}
@Test
- fun overlappingActiveFeatureOps() {
+ fun overlappingActiveAttributionOps() {
runWithShellPermissionIdentity {
val gotActive = CompletableFuture<Unit>()
val gotInActive = CompletableFuture<Unit>()
@@ -249,17 +249,17 @@
mAppOps.startWatchingActive(arrayOf(OPSTR_WRITE_CALENDAR), Executor { it.run() },
activeWatcher)
try {
- mAppOps.startOp(OPSTR_WRITE_CALENDAR, mMyUid, mOpPackageName, "feature1", null)
+ mAppOps.startOp(OPSTR_WRITE_CALENDAR, mMyUid, mOpPackageName, "attribution1", null)
assertTrue(mAppOps.isOpActive(OPSTR_WRITE_CALENDAR, mMyUid, mOpPackageName))
gotActive.get(TIMEOUT_MS, TimeUnit.MILLISECONDS)
mAppOps.startOp(OPSTR_WRITE_CALENDAR, Process.myUid(), mOpPackageName,
- "feature2", null)
+ "attribution2", null)
assertTrue(mAppOps.isOpActive(OPSTR_WRITE_CALENDAR, mMyUid, mOpPackageName))
assertFalse(gotInActive.isDone)
mAppOps.finishOp(OPSTR_WRITE_CALENDAR, Process.myUid(), mOpPackageName,
- "feature1")
+ "attribution1")
// Allow some time for premature "watchingActive" callbacks to arrive
Thread.sleep(500)
@@ -268,7 +268,7 @@
assertFalse(gotInActive.isDone)
mAppOps.finishOp(OPSTR_WRITE_CALENDAR, Process.myUid(), mOpPackageName,
- "feature2")
+ "attribution2")
assertFalse(mAppOps.isOpActive(OPSTR_WRITE_CALENDAR, mMyUid, mOpPackageName))
gotInActive.get(TIMEOUT_MS, TimeUnit.MILLISECONDS)
} finally {
diff --git a/tests/tests/appop/src/android/app/appops/cts/AttributionTest.kt b/tests/tests/appop/src/android/app/appops/cts/AttributionTest.kt
new file mode 100644
index 0000000..0bdf312
--- /dev/null
+++ b/tests/tests/appop/src/android/app/appops/cts/AttributionTest.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appops.cts
+
+import android.app.AppOpsManager
+import android.app.AppOpsManager.OPSTR_WIFI_SCAN
+import android.app.AppOpsManager.OP_FLAGS_ALL
+import android.platform.test.annotations.AppModeFull
+import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import java.lang.AssertionError
+import java.lang.Thread.sleep
+
+private const val APK_PATH = "/data/local/tmp/cts/appops/"
+
+private const val APP_PKG = "android.app.appops.cts.apptoblame"
+
+private const val ATTRIBUTION_1 = "attribution1"
+private const val ATTRIBUTION_2 = "attribution2"
+private const val ATTRIBUTION_3 = "attribution3"
+private const val ATTRIBUTION_4 = "attribution4"
+private const val ATTRIBUTION_5 = "attribution5"
+private const val ATTRIBUTION_6 = "attribution6"
+private const val ATTRIBUTION_7 = "attribution7"
+
+@AppModeFull(reason = "Test relies on seeing other apps. Instant apps can't see other apps")
+class AttributionTest {
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val context = instrumentation.targetContext
+ private val appOpsManager = context.getSystemService(AppOpsManager::class.java)
+ private val appUid by lazy { context.packageManager.getPackageUid(APP_PKG, 0) }
+
+ private fun installApk(apk: String) {
+ val result = runCommand("pm install -r --force-queryable $APK_PATH$apk")
+ assertThat(result.trim()).isEqualTo("Success")
+ }
+
+ @Before
+ fun resetTestApp() {
+ runCommand("pm uninstall $APP_PKG")
+ installApk("CtsAppToBlame1.apk")
+ }
+
+ private fun noteForAttribution(attribution: String) {
+ // Make sure note times as distinct
+ sleep(1)
+
+ runWithShellPermissionIdentity {
+ appOpsManager.noteOpNoThrow(OPSTR_WIFI_SCAN, appUid, APP_PKG, attribution, null)
+ }
+ }
+
+ @Test
+ fun inheritNotedAppOpsOnUpgrade() {
+ noteForAttribution(ATTRIBUTION_1)
+ noteForAttribution(ATTRIBUTION_2)
+ noteForAttribution(ATTRIBUTION_3)
+ noteForAttribution(ATTRIBUTION_4)
+ noteForAttribution(ATTRIBUTION_5)
+
+ val beforeUpdate = getOpEntry(appUid, APP_PKG, OPSTR_WIFI_SCAN)!!
+ installApk("CtsAppToBlame2.apk")
+
+ eventually {
+ val afterUpdate = getOpEntry(appUid, APP_PKG, OPSTR_WIFI_SCAN)!!
+
+ // Attribution 1 is unchanged
+ assertThat(afterUpdate.attributedOpEntries[ATTRIBUTION_1]!!
+ .getLastAccessTime(OP_FLAGS_ALL))
+ .isEqualTo(beforeUpdate.attributedOpEntries[ATTRIBUTION_1]!!
+ .getLastAccessTime(OP_FLAGS_ALL))
+
+ // Attribution 3 disappeared (i.e. was added into "null" attribution)
+ assertThat(afterUpdate.attributedOpEntries[null]!!.getLastAccessTime(OP_FLAGS_ALL))
+ .isEqualTo(beforeUpdate.attributedOpEntries[ATTRIBUTION_3]!!
+ .getLastAccessTime(OP_FLAGS_ALL))
+
+ // Attribution 6 inherits from attribution 2
+ assertThat(afterUpdate.attributedOpEntries[ATTRIBUTION_6]!!
+ .getLastAccessTime(OP_FLAGS_ALL))
+ .isEqualTo(beforeUpdate.attributedOpEntries[ATTRIBUTION_2]!!
+ .getLastAccessTime(OP_FLAGS_ALL))
+
+ // Attribution 7 inherits from attribution 4 and 5. 5 was noted after 4, hence 4 is
+ // removed
+ assertThat(afterUpdate.attributedOpEntries[ATTRIBUTION_7]!!
+ .getLastAccessTime(OP_FLAGS_ALL))
+ .isEqualTo(beforeUpdate.attributedOpEntries[ATTRIBUTION_5]!!
+ .getLastAccessTime(OP_FLAGS_ALL))
+ }
+ }
+
+ @Test(expected = AssertionError::class)
+ fun cannotInheritFromSelf() {
+ installApk("AppWithAttributionInheritingFromSelf.apk")
+ }
+
+ @Test(expected = AssertionError::class)
+ fun noDuplicateAttributions() {
+ installApk("AppWithDuplicateAttribution.apk")
+ }
+
+ @Test(expected = AssertionError::class)
+ fun cannotInheritFromExisting() {
+ installApk("AppWithAttributionInheritingFromExisting.apk")
+ }
+
+ @Test(expected = AssertionError::class)
+ fun cannotInheritFromSameAsOther() {
+ installApk("AppWithAttributionInheritingFromSameAsOther.apk")
+ }
+
+ @Test(expected = AssertionError::class)
+ fun cannotUseVeryLongAttributionTags() {
+ installApk("AppWithLongAttributionTag.apk")
+ }
+
+ @Test(expected = AssertionError::class)
+ fun cannotUseTooManyAttributions() {
+ installApk("AppWithTooManyAttributions.apk")
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/appop/src/android/app/appops/cts/FeatureTest.kt b/tests/tests/appop/src/android/app/appops/cts/FeatureTest.kt
deleted file mode 100644
index d199055..0000000
--- a/tests/tests/appop/src/android/app/appops/cts/FeatureTest.kt
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appops.cts
-
-import android.app.AppOpsManager
-import android.app.AppOpsManager.OPSTR_WIFI_SCAN
-import android.app.AppOpsManager.OP_FLAGS_ALL
-import android.platform.test.annotations.AppModeFull
-import androidx.test.platform.app.InstrumentationRegistry
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import java.lang.AssertionError
-import java.lang.Thread.sleep
-
-private const val APK_PATH = "/data/local/tmp/cts/appops/"
-
-private const val APP_PKG = "android.app.appops.cts.apptoblame"
-
-private const val FEATURE_1 = "feature1"
-private const val FEATURE_2 = "feature2"
-private const val FEATURE_3 = "feature3"
-private const val FEATURE_4 = "feature4"
-private const val FEATURE_5 = "feature5"
-private const val FEATURE_6 = "feature6"
-private const val FEATURE_7 = "feature7"
-
-@AppModeFull(reason = "Test relies on seeing other apps. Instant apps can't see other apps")
-class FeatureTest {
- private val instrumentation = InstrumentationRegistry.getInstrumentation()
- private val context = instrumentation.targetContext
- private val appOpsManager = context.getSystemService(AppOpsManager::class.java)
- private val appUid by lazy { context.packageManager.getPackageUid(APP_PKG, 0) }
-
- private fun installApk(apk: String) {
- val result = runCommand("pm install -r --force-queryable $APK_PATH$apk")
- assertThat(result.trim()).isEqualTo("Success")
- }
-
- @Before
- fun resetTestApp() {
- runCommand("pm uninstall $APP_PKG")
- installApk("CtsAppToBlame1.apk")
- }
-
- private fun noteForFeature(feature: String) {
- // Make sure note times as distinct
- sleep(1)
-
- runWithShellPermissionIdentity {
- appOpsManager.noteOpNoThrow(OPSTR_WIFI_SCAN, appUid, APP_PKG, feature, null)
- }
- }
-
- @Test
- fun inheritNotedAppOpsOnUpgrade() {
- noteForFeature(FEATURE_1)
- noteForFeature(FEATURE_2)
- noteForFeature(FEATURE_3)
- noteForFeature(FEATURE_4)
- noteForFeature(FEATURE_5)
-
- val beforeUpdate = getOpEntry(appUid, APP_PKG, OPSTR_WIFI_SCAN)!!
- installApk("CtsAppToBlame2.apk")
-
- eventually {
- val afterUpdate = getOpEntry(appUid, APP_PKG, OPSTR_WIFI_SCAN)!!
-
- // Feature 1 is unchanged
- assertThat(afterUpdate.features[FEATURE_1]!!.getLastAccessTime(OP_FLAGS_ALL))
- .isEqualTo(beforeUpdate.features[FEATURE_1]!!.getLastAccessTime(OP_FLAGS_ALL))
-
- // Feature 3 disappeared (i.e. was added into "null" feature)
- assertThat(afterUpdate.features[null]!!.getLastAccessTime(OP_FLAGS_ALL))
- .isEqualTo(beforeUpdate.features[FEATURE_3]!!.getLastAccessTime(OP_FLAGS_ALL))
-
- // Feature 6 inherits from feature 2
- assertThat(afterUpdate.features[FEATURE_6]!!.getLastAccessTime(OP_FLAGS_ALL))
- .isEqualTo(beforeUpdate.features[FEATURE_2]!!.getLastAccessTime(OP_FLAGS_ALL))
-
- // Feature 7 inherits from feature 4 and 5. 5 was noted after 4, hence 4 is removed
- assertThat(afterUpdate.features[FEATURE_7]!!.getLastAccessTime(OP_FLAGS_ALL))
- .isEqualTo(beforeUpdate.features[FEATURE_5]!!.getLastAccessTime(OP_FLAGS_ALL))
- }
- }
-
- @Test(expected = AssertionError::class)
- fun cannotInheritFromSelf() {
- installApk("AppWithFeatureInheritingFromSelf.apk")
- }
-
- @Test(expected = AssertionError::class)
- fun noDuplicateFeatures() {
- installApk("AppWithDuplicateFeature.apk")
- }
-
- @Test(expected = AssertionError::class)
- fun cannotInheritFromExisting() {
- installApk("AppWithFeatureInheritingFromExisting.apk")
- }
-
- @Test(expected = AssertionError::class)
- fun cannotInheritFromSameAsOther() {
- installApk("AppWithFeatureInheritingFromSameAsOther.apk")
- }
-
- @Test(expected = AssertionError::class)
- fun cannotUseVeryLongFeatureIDs() {
- installApk("AppWithLongFeatureIdFeature.apk")
- }
-
- @Test(expected = AssertionError::class)
- fun cannotUseTooManyFeatures() {
- installApk("AppWithTooManyFeatures.apk")
- }
-}
\ No newline at end of file
diff --git a/tests/tests/appop/src/android/app/appops/cts/HistoricalAppopsTest.kt b/tests/tests/appop/src/android/app/appops/cts/HistoricalAppopsTest.kt
index 28ebc26..eaef444 100644
--- a/tests/tests/appop/src/android/app/appops/cts/HistoricalAppopsTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/HistoricalAppopsTest.kt
@@ -201,7 +201,7 @@
}
@Test
- fun testGetHistoricalAggregationOverFeatures() {
+ fun testGetHistoricalAggregationOverAttributions() {
// Configure historical registry behavior.
appOpsManager.setHistoryParameters(
AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE,
@@ -212,17 +212,19 @@
UidStateForceActivity.waitForResumed()
- appOpsManager.noteOp(OPSTR_REQUEST_DELETE_PACKAGES, uid, packageName, "firstFeature", null)
- appOpsManager.noteOp(OPSTR_REQUEST_DELETE_PACKAGES, uid, packageName, "secondFeature", null)
+ appOpsManager.noteOp(OPSTR_REQUEST_DELETE_PACKAGES, uid, packageName, "firstAttribution",
+ null)
+ appOpsManager.noteOp(OPSTR_REQUEST_DELETE_PACKAGES, uid, packageName, "secondAttribution",
+ null)
val memOps = getHistoricalOps(appOpsManager, uid = uid)!!
assertThat(memOps.getUidOpsAt(0).getPackageOpsAt(0).getOp(OPSTR_REQUEST_DELETE_PACKAGES)!!
.getForegroundAccessCount(OP_FLAGS_ALL)).isEqualTo(2)
- assertThat(memOps.getUidOpsAt(0).getPackageOpsAt(0).getFeatureOps("firstFeature")!!
+ assertThat(memOps.getUidOpsAt(0).getPackageOpsAt(0).getAttributedOps("firstAttribution")!!
.getOp(OPSTR_REQUEST_DELETE_PACKAGES)!!.getForegroundAccessCount(OP_FLAGS_ALL))
.isEqualTo(1)
- assertThat(memOps.getUidOpsAt(0).getPackageOpsAt(0).getFeatureOps("secondFeature")!!
+ assertThat(memOps.getUidOpsAt(0).getPackageOpsAt(0).getAttributedOps("secondAttribution")!!
.getOp(OPSTR_REQUEST_DELETE_PACKAGES)!!.getForegroundAccessCount(OP_FLAGS_ALL))
.isEqualTo(1)
diff --git a/tests/tests/appop/src/android/app/appops/cts/RuntimeMessageCollectionTest.kt b/tests/tests/appop/src/android/app/appops/cts/RuntimeMessageCollectionTest.kt
index e6730c1..d5e8748 100644
--- a/tests/tests/appop/src/android/app/appops/cts/RuntimeMessageCollectionTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/RuntimeMessageCollectionTest.kt
@@ -58,7 +58,7 @@
val start = System.currentTimeMillis()
runWithShellPermissionIdentity {
appOpsManager.noteOp(AppOpsManager.OPSTR_READ_CONTACTS, appUid, APP_PKG,
- TEST_FEATURE_ID, MESSAGE)
+ TEST_ATTRIBUTION_TAG, MESSAGE)
}
while (System.currentTimeMillis() - start < TIMEOUT_MILLIS) {
sleep(200)
@@ -68,7 +68,7 @@
if (message != null && message.packageName.equals(APP_PKG)) {
assertThat(message.op).isEqualTo(AppOpsManager.OPSTR_READ_CONTACTS)
assertThat(message.uid).isEqualTo(appUid)
- assertThat(message.featureId).isEqualTo(TEST_FEATURE_ID)
+ assertThat(message.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
assertThat(message.message).isEqualTo(MESSAGE)
assertThat(message.samplingStrategy)
.isEqualTo(RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED)
diff --git a/tests/tests/batterysaving/AndroidManifest.xml b/tests/tests/batterysaving/AndroidManifest.xml
index 9f326e0..55e9050 100755
--- a/tests/tests/batterysaving/AndroidManifest.xml
+++ b/tests/tests/batterysaving/AndroidManifest.xml
@@ -21,6 +21,7 @@
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
<!-- Needed to whitelist package to be able to avoid request throttling. -->
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<application>
<uses-library android:name="android.test.runner" />
@@ -33,4 +34,4 @@
android:value="com.android.cts.runner.CtsTestRunListener" />
</instrumentation>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java b/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java
index afae17e..56fce94 100644
--- a/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java
+++ b/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java
@@ -17,6 +17,7 @@
import static com.android.compatibility.common.util.BatteryUtils.enableBatterySaver;
import static com.android.compatibility.common.util.BatteryUtils.runDumpsysBatteryUnplug;
+import static com.android.compatibility.common.util.TestUtils.waitUntil;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -112,36 +113,38 @@
enableBatterySaver(true);
- // Allow time for UI change.
- Thread.sleep(1000);
assertTrue(powerManager.isPowerSaveMode());
assertEquals(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF,
powerManager.getLocationPowerSaveMode());
- assertEquals(Configuration.UI_MODE_NIGHT_YES,
- getContext().getResources().getConfiguration().uiMode
- & Configuration.UI_MODE_NIGHT_MASK);
+ // UI change can take a while to propagate, so need to wait for this check.
+ waitUntil("UI mode didn't change to " + Configuration.UI_MODE_NIGHT_YES,
+ () -> Configuration.UI_MODE_NIGHT_YES ==
+ (getContext().getResources().getConfiguration().uiMode
+ & Configuration.UI_MODE_NIGHT_MASK));
uiModeManager.enableCarMode(0);
- // Allow time for UI change.
- Thread.sleep(1000);
+ // Wait for UI change first before checking location mode since we can then be
+ // confident that the broadcast has been processed.
+ waitUntil("UI mode didn't change to " + Configuration.UI_MODE_NIGHT_NO,
+ () -> Configuration.UI_MODE_NIGHT_NO ==
+ (getContext().getResources().getConfiguration().uiMode
+ & Configuration.UI_MODE_NIGHT_MASK));
final int locationPowerSaveMode = powerManager.getLocationPowerSaveMode();
assertTrue("Location power save mode didn't change from " + locationPowerSaveMode,
locationPowerSaveMode == PowerManager.LOCATION_MODE_FOREGROUND_ONLY
|| locationPowerSaveMode == PowerManager.LOCATION_MODE_NO_CHANGE);
- assertEquals(Configuration.UI_MODE_NIGHT_NO,
- getContext().getResources().getConfiguration().uiMode
- & Configuration.UI_MODE_NIGHT_MASK);
uiModeManager.disableCarMode(0);
- // Allow time for UI change.
- Thread.sleep(1000);
+ // Wait for UI change first before checking location mode since we can then be
+ // confident that the broadcast has been processed.
+ waitUntil("UI mode didn't change to " + Configuration.UI_MODE_NIGHT_YES,
+ () -> Configuration.UI_MODE_NIGHT_YES ==
+ (getContext().getResources().getConfiguration().uiMode
+ & Configuration.UI_MODE_NIGHT_MASK));
assertEquals(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF,
powerManager.getLocationPowerSaveMode());
- assertEquals(Configuration.UI_MODE_NIGHT_YES,
- getContext().getResources().getConfiguration().uiMode
- & Configuration.UI_MODE_NIGHT_MASK);
} finally {
uiModeManager.disableCarMode(0);
SettingsUtils.delete(SettingsUtils.NAMESPACE_GLOBAL, "battery_saver_constants");
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/.hash b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/.hash
index 9c76fef..425104b 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/.hash
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/.hash
@@ -1 +1 @@
-8d903ce236a40b41624907c4d1d7a651eca9f763 -
+d755ae773aaabd1c48d22b823e29501ee387aff1
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/.hash b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/.hash
index ad2b69c3..fce7d03 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/.hash
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/.hash
@@ -1 +1 @@
-8359746d4317c0ef0f014821d362c4cfe96e2166 -
+3589e207cd708912b7551fb40b7fb263ef3e81b4
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
index cee0944..f4aa698 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
@@ -808,7 +808,7 @@
EXPECT_OK(iface->getInterfaceHash(&res));
if (GetParam().shouldBeOld) {
// aidl_api/libbinder_ndk_test_interface/1/.hash
- EXPECT_EQ("8d903ce236a40b41624907c4d1d7a651eca9f763", res);
+ EXPECT_EQ("d755ae773aaabd1c48d22b823e29501ee387aff1", res);
} else {
EXPECT_EQ("notfrozen", res);
}
diff --git a/tests/tests/car/AndroidManifest.xml b/tests/tests/car/AndroidManifest.xml
index d146b32..3894b0b 100644
--- a/tests/tests/car/AndroidManifest.xml
+++ b/tests/tests/car/AndroidManifest.xml
@@ -29,6 +29,8 @@
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <!-- Allow query of any normal app on the device -->
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/tests/tests/car/res/values/minimum_required_packages.xml b/tests/tests/car/res/values/minimum_required_packages.xml
new file mode 100644
index 0000000..b730bbf
--- /dev/null
+++ b/tests/tests/car/res/values/minimum_required_packages.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array translatable="false" name="installed_system_and_full">
+ <item>android</item>
+ <item>com.android.car</item>
+ <item>com.android.car.frameworkpackagestubs</item>
+ </string-array>
+
+ <string-array translatable="false" name="installed_full_only">
+ <item>com.google.android.carassistant</item>
+ </string-array>
+</resources>
\ No newline at end of file
diff --git a/tests/tests/car/src/android/car/cts/CarInfoManagerTest.java b/tests/tests/car/src/android/car/cts/CarInfoManagerTest.java
index f901a4a..d7135da 100644
--- a/tests/tests/car/src/android/car/cts/CarInfoManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarInfoManagerTest.java
@@ -15,7 +15,7 @@
*/
package android.car.cts;
-import static org.junit.Assert.assertNotNull;
+import static com.google.common.truth.Truth.assertThat;
import android.car.Car;
import android.car.CarInfoManager;
@@ -26,15 +26,15 @@
import android.platform.test.annotations.RequiresDevice;
import android.test.suitebuilder.annotation.SmallTest;
-import static com.google.common.truth.Truth.assertThat;
import androidx.test.runner.AndroidJUnit4;
-import java.util.Arrays;
-import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
+import java.util.List;
+
@SmallTest
@RequiresDevice
@RunWith(AndroidJUnit4.class)
@@ -54,22 +54,24 @@
@Test
public void testVehicleId() throws Exception {
- assertNotNull(mCarInfoManager.getVehicleId());
+ // Not support to get vehicle Id.
+ assertThat(mCarInfoManager.getVehicleId()).isEmpty();
}
@Test
public void testGetManufacturer() throws Exception {
- assertNotNull(mCarInfoManager.getManufacturer());
+ assertThat(mCarInfoManager.getManufacturer()).isNotNull();;
}
@Test
public void testGetModel() throws Exception {
- assertNotNull(mCarInfoManager.getModel());
+ assertThat(mCarInfoManager.getModel()).isNotNull();
}
@Test
public void testGetModelYear() throws Exception {
- assertNotNull(mCarInfoManager.getModelYear());
+ assertThat(mCarInfoManager.getModelYear()).isNotNull();
+ assertThat(mCarInfoManager.getModelYearInInteger()).isAtLeast(0);
}
@Test
@@ -83,7 +85,7 @@
*/
@Test
public void testGetFuelTypes() throws Exception {
- assertNotNull(mCarInfoManager.getFuelTypes());
+ assertThat(mCarInfoManager.getFuelTypes()).isNotNull();
int[] actualResults = mCarInfoManager.getFuelTypes();
for (int result : actualResults) {
assertThat(result).isIn(EXPECTED_FUEL_TYPES);
@@ -103,7 +105,7 @@
*/
@Test
public void testGetEvConnectorTypes() throws Exception {
- assertNotNull(mCarInfoManager.getEvConnectorTypes());
+ assertThat(mCarInfoManager.getEvConnectorTypes()).isNotNull();
int[] actualResults = mCarInfoManager.getEvConnectorTypes();
List<Integer> expectedResults =
diff --git a/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java b/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
index 8f2057d..8a2cc19 100644
--- a/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
@@ -15,16 +15,10 @@
*/
package android.car.cts;
-import static org.testng.Assert.assertThrows;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import static java.lang.Integer.toHexString;
+import static org.testng.Assert.assertThrows;
import android.car.Car;
import android.car.VehicleAreaSeat;
@@ -37,7 +31,6 @@
import android.platform.test.annotations.RequiresDevice;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
-import android.util.Log;
import android.util.SparseArray;
import androidx.annotation.GuardedBy;
@@ -60,6 +53,7 @@
private static final String TAG = CarPropertyManagerTest.class.getSimpleName();
private static final long WAIT_CALLBACK = 1500L;
+ private static final int NO_EVENTS = 0;
private CarPropertyManager mCarPropertyManager;
/** contains property Ids for the properties required by CDD*/
private ArraySet<Integer> mPropertyIds = new ArraySet<>();
@@ -123,7 +117,7 @@
@Test
public void testGetPropertyList() {
List<CarPropertyConfig> allConfigs = mCarPropertyManager.getPropertyList();
- assertNotNull(allConfigs);
+ assertThat(allConfigs).isNotNull();
}
/**
@@ -133,7 +127,7 @@
public void testGetPropertyListWithArraySet() {
List<CarPropertyConfig> requiredConfigs = mCarPropertyManager.getPropertyList(mPropertyIds);
// Vehicles need to implement all of those properties
- assertEquals(mPropertyIds.size(), requiredConfigs.size());
+ assertThat(requiredConfigs.size()).isEqualTo(mPropertyIds.size());
}
/**
@@ -143,7 +137,7 @@
public void testGetPropertyConfig() {
List<CarPropertyConfig> allConfigs = mCarPropertyManager.getPropertyList();
for (CarPropertyConfig cfg : allConfigs) {
- assertNotNull(mCarPropertyManager.getCarPropertyConfig(cfg.getPropertyId()));
+ assertThat(mCarPropertyManager.getCarPropertyConfig(cfg.getPropertyId())).isNotNull();
}
}
@@ -156,8 +150,9 @@
List<CarPropertyConfig> allConfigs = mCarPropertyManager.getPropertyList();
for (CarPropertyConfig cfg : allConfigs) {
if (cfg.isGlobalProperty()) {
- assertEquals(0, mCarPropertyManager.getAreaId(cfg.getPropertyId(),
- VehicleAreaSeat.SEAT_ROW_1_LEFT));
+ assertThat(mCarPropertyManager.getAreaId(cfg.getPropertyId(),
+ VehicleAreaSeat.SEAT_ROW_1_LEFT))
+ .isEqualTo(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL);
} else {
int[] areaIds = cfg.getAreaIds();
// Because areaId in propConfig must not be overlapped with each other.
@@ -165,7 +160,7 @@
for (int areaIdInConfig : areaIds) {
int areaIdByCarPropertyManager =
mCarPropertyManager.getAreaId(cfg.getPropertyId(), areaIdInConfig);
- assertEquals(areaIdInConfig, areaIdByCarPropertyManager);
+ assertThat(areaIdByCarPropertyManager).isEqualTo(areaIdInConfig);
}
}
}
@@ -174,33 +169,34 @@
@CddTest(requirement="2.5.1")
@Test
public void testMustSupportGearSelection() throws Exception {
- assertTrue("Must support GEAR_SELECTION",
- mCarPropertyManager.getPropertyList().stream().anyMatch(cfg -> cfg.getPropertyId() ==
- VehiclePropertyIds.GEAR_SELECTION));
+ assertWithMessage("Must support GEAR_SELECTION")
+ .that(mCarPropertyManager.getCarPropertyConfig(VehiclePropertyIds.GEAR_SELECTION))
+ .isNotNull();
}
@CddTest(requirement="2.5.1")
@Test
public void testMustSupportNightMode() {
- assertTrue("Must support NIGHT_MODE",
- mCarPropertyManager.getPropertyList().stream().anyMatch(cfg -> cfg.getPropertyId() ==
- VehiclePropertyIds.NIGHT_MODE));
+ assertWithMessage("Must support NIGHT_MODE")
+ .that(mCarPropertyManager.getCarPropertyConfig(VehiclePropertyIds.NIGHT_MODE))
+ .isNotNull();
}
@CddTest(requirement="2.5.1")
@Test
public void testMustSupportPerfVehicleSpeed() throws Exception {
- assertTrue("Must support PERF_VEHICLE_SPEED",
- mCarPropertyManager.getPropertyList().stream().anyMatch(cfg -> cfg.getPropertyId() ==
- VehiclePropertyIds.PERF_VEHICLE_SPEED));
+ assertWithMessage("Must support PERF_VEHICLE_SPEED")
+ .that(mCarPropertyManager.getCarPropertyConfig(
+ VehiclePropertyIds.PERF_VEHICLE_SPEED)).isNotNull();
}
@CddTest(requirement = "2.5.1")
@Test
public void testMustSupportParkingBrakeOn() throws Exception {
- assertTrue("Must support PARKING_BRAKE_ON",
- mCarPropertyManager.getPropertyList().stream().anyMatch(cfg -> cfg.getPropertyId() ==
- VehiclePropertyIds.PARKING_BRAKE_ON));
+ assertWithMessage("Must support PARKING_BRAKE_ON")
+ .that(mCarPropertyManager.getCarPropertyConfig(VehiclePropertyIds.PARKING_BRAKE_ON))
+ .isNotNull();
+
}
@SuppressWarnings("unchecked")
@@ -286,7 +282,8 @@
for (CarPropertyConfig cfg : configs) {
int[] areaIds = getAreaIdsHelper(cfg);
for (int areaId : areaIds) {
- assertTrue(mCarPropertyManager.isPropertyAvailable(cfg.getPropertyId(), areaId));
+ assertThat(mCarPropertyManager.isPropertyAvailable(cfg.getPropertyId(), areaId))
+ .isTrue();
}
}
}
@@ -313,17 +310,17 @@
int invalidPropertyId = -1;
boolean isRegistered = mCarPropertyManager.registerCallback(
new CarPropertyEventCounter(), invalidPropertyId, 0);
- assertFalse(isRegistered);
+ assertThat(isRegistered).isFalse();
// Test for continuous properties
int vehicleSpeed = VehiclePropertyIds.PERF_VEHICLE_SPEED;
CarPropertyEventCounter speedListenerNormal = new CarPropertyEventCounter();
CarPropertyEventCounter speedListenerUI = new CarPropertyEventCounter();
- assertEquals(0, speedListenerNormal.receivedEvent(vehicleSpeed));
- assertEquals(0, speedListenerNormal.receivedError(vehicleSpeed));
- assertEquals(0, speedListenerUI.receivedEvent(vehicleSpeed));
- assertEquals(0, speedListenerUI.receivedError(vehicleSpeed));
+ assertThat(speedListenerNormal.receivedEvent(vehicleSpeed)).isEqualTo(NO_EVENTS);
+ assertThat(speedListenerNormal.receivedError(vehicleSpeed)).isEqualTo(NO_EVENTS);
+ assertThat(speedListenerUI.receivedEvent(vehicleSpeed)).isEqualTo(NO_EVENTS);
+ assertThat(speedListenerUI.receivedError(vehicleSpeed)).isEqualTo(NO_EVENTS);
mCarPropertyManager.registerCallback(speedListenerNormal, vehicleSpeed,
CarPropertyManager.SENSOR_RATE_NORMAL);
@@ -331,9 +328,8 @@
CarPropertyManager.SENSOR_RATE_FASTEST);
// TODO(b/149778976): Use CountDownLatch in listener instead of waitingTime
Thread.sleep(WAIT_CALLBACK);
- assertNotEquals(0, speedListenerNormal.receivedEvent(vehicleSpeed));
- assertNotEquals(0, speedListenerUI.receivedEvent(vehicleSpeed));
- assertTrue(speedListenerUI.receivedEvent(vehicleSpeed) >
+ assertThat(speedListenerNormal.receivedEvent(vehicleSpeed)).isGreaterThan(NO_EVENTS);
+ assertThat(speedListenerUI.receivedEvent(vehicleSpeed)).isGreaterThan(
speedListenerNormal.receivedEvent(vehicleSpeed));
mCarPropertyManager.unregisterCallback(speedListenerUI);
@@ -344,8 +340,7 @@
CarPropertyEventCounter nightModeListener = new CarPropertyEventCounter();
mCarPropertyManager.registerCallback(nightModeListener, nightMode, 0);
Thread.sleep(WAIT_CALLBACK);
- assertEquals(1, nightModeListener.receivedEvent(nightMode));
-
+ assertThat(nightModeListener.receivedEvent(nightMode)).isEqualTo(1);
mCarPropertyManager.unregisterCallback(nightModeListener);
}
@@ -378,15 +373,15 @@
int currentEventUI = speedListenerUI.receivedEvent(vehicleSpeed);
Thread.sleep(WAIT_CALLBACK);
- assertEquals(currentEventNormal, speedListenerNormal.receivedEvent(vehicleSpeed));
- assertNotEquals(currentEventUI, speedListenerUI.receivedEvent(vehicleSpeed));
+ assertThat(speedListenerNormal.receivedEvent(vehicleSpeed)).isEqualTo(currentEventNormal);
+ assertThat(speedListenerUI.receivedEvent(vehicleSpeed)).isNotEqualTo(currentEventUI);
mCarPropertyManager.unregisterCallback(speedListenerUI);
Thread.sleep(WAIT_CALLBACK);
currentEventUI = speedListenerUI.receivedEvent(vehicleSpeed);
Thread.sleep(WAIT_CALLBACK);
- assertEquals(currentEventUI, speedListenerUI.receivedEvent(vehicleSpeed));
+ assertThat(speedListenerUI.receivedEvent(vehicleSpeed)).isEqualTo(currentEventUI);
}
@Test
diff --git a/tests/tests/car/src/android/car/cts/CarUserManagerTest.java b/tests/tests/car/src/android/car/cts/CarUserManagerTest.java
index 622fa28..bf76d3d 100644
--- a/tests/tests/car/src/android/car/cts/CarUserManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarUserManagerTest.java
@@ -16,13 +16,16 @@
package android.car.cts;
import static android.os.Process.myUid;
+import static android.os.UserHandle.USER_SYSTEM;
import static com.android.compatibility.common.util.ShellIdentityUtils.invokeMethodWithShellPermissions;
import static com.android.compatibility.common.util.ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn;
import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
-
+import static com.android.compatibility.common.util.TestUtils.BooleanSupplierWithThrow;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.testng.Assert.assertThrows;
@@ -32,7 +35,9 @@
import android.car.Car;
import android.car.user.CarUserManager;
import android.car.user.CarUserManager.UserLifecycleListener;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;
@@ -45,6 +50,7 @@
import org.junit.Test;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
@@ -59,7 +65,7 @@
/**
* Constant used to wait for a condition that is triggered by checking a condition.
*/
- private static final int SWITCH_TIMEOUT_USING_CHECK_MS = 30_000;
+ private static final int SWITCH_TIMEOUT_USING_CHECK_MS = 40_000;
/**
* Constant used to wait blindly, when there is no condition that can be checked.
@@ -67,12 +73,19 @@
private static final int SWITCH_TIMEOUT_WITHOUT_CHECK_MS = 10_000;
/**
+ * Constant used to wait blindly, when there is no condition that can be checked.
+ */
+ private static final int SUSPEND_TIMEOUT_MS = 5_000;
+
+ /**
* How long to sleep (multiple times) while waiting for a condition.
*/
- private static final int SMALL_NAP_MS = 500;
+ private static final int SMALL_NAP_MS = 100;
private static CarUserManager sCarUserManager;
+ private PackageManager mPackageManager;
+
private static int sInitialUserId = UserHandle.myUserId();
private static int sNewUserId = UserHandle.USER_NULL;
@@ -91,9 +104,11 @@
}
sCarUserManager = (CarUserManager) getCar().getCarManager(Car.CAR_USER_SERVICE);
- sNewUserId = createNewUser("CarUserManagerTest");
+ sNewUserId = createNewUser("CarUserManagerTest", /* isGuestUser= */ false);
Log.i(TAG, "setUp(): myUid=" + myUid() + ", currentUser=" + sInitialUserId
+ ", newUser=" + sNewUserId);
+
+ mPackageManager = sContext.getPackageManager();
}
@AfterClass
@@ -180,7 +195,6 @@
};
Log.d(TAG, "registering listener: " + listener);
-
AtomicBoolean executedRef = new AtomicBoolean();
sCarUserManager.addListener((r) -> {
executedRef.set(true);
@@ -216,10 +230,49 @@
}
}
+
+ /**
+ * Tests resume behabior when current user is ephemeral guest, a new guest user should be
+ * created and switched to.
+ */
+ @Test
+ public void testGuestUserResumeToNewGuestUser() throws Exception {
+ // Create new guest user
+ int guestUserId = createNewUser("TestGuest", /* isGuestUser= */ true);
+
+ // Wait for this user to be active
+ switchUser(guestUserId);
+ waitForCurrentUser(guestUserId, SWITCH_TIMEOUT_USING_CHECK_MS);
+ waitUntil("Timeout: current user is not initialized: " + guestUserId,
+ SWITCH_TIMEOUT_USING_CHECK_MS, () -> isCurrentUserInitialized());
+
+ // Emulate suspend to RAM
+ suspendToRamAndResume();
+
+ // Wait for current user to be valid guest user, otherwise
+ assertWithMessage("not resumed to new guest user and current user is: %s", getCurrentUser())
+ .that(waitUntil("Timeout: current user is not valid guest user",
+ SWITCH_TIMEOUT_USING_CHECK_MS,
+ () -> (isCurrentUserValidGuestUser() && getCurrentUser() != guestUserId)))
+ .isTrue();
+ }
+
+ /**
+ * Tests resume behavior when current user is persistent user
+ */
+ @Test
+ public void testPersistentUserResumeToUser() throws Exception {
+ switchUser(sNewUserId);
+ suspendToRamAndResume();
+
+ assertWithMessage("not resumed to previous user: %s", sNewUserId)
+ .that(getCurrentUser()).isEqualTo(sNewUserId);
+ }
+
/**
* Used to temporarily revoke the permission.
*/
- private void toggleInteractAcrossUsersPermission(boolean enabled) {
+ private static void toggleInteractAcrossUsersPermission(boolean enabled) {
String permission = "android.permission.INTERACT_ACROSS_USERS";
String pkgName = sContext.getPackageName();
UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
@@ -234,13 +287,44 @@
}
}
+ @Test
+ public void testPackageInstalledForSystemAndFullUser() throws Exception {
+ String[] packages = sContext.getResources()
+ .getStringArray(R.array.installed_system_and_full);
+ for (String pkg : packages) {
+ assertWithMessage(pkg + " should be installed for system user.")
+ .that(isInstalled(pkg, USER_SYSTEM)).isTrue();
+ assertWithMessage(pkg + " should be installed for system user.")
+ .that(isInstalled(pkg, sNewUserId)).isTrue();
+ }
+ }
+
+ @Test
+ public void testPackageInstalledForFullUserOnly() throws Exception {
+ String[] packages = sContext.getResources()
+ .getStringArray(R.array.installed_full_only);
+ for (String pkg : packages) {
+ assertWithMessage(pkg + " should not be installed for system user.")
+ .that(isInstalled(pkg, USER_SYSTEM)).isFalse();
+ assertWithMessage(pkg + " should be installed for full user")
+ .that(isInstalled(pkg, sNewUserId)).isTrue();
+ }
+ }
+
+ private boolean isInstalled(String packageName, int userId) {
+ List<PackageInfo> packages = new ArrayList<PackageInfo>();
+ packages = mPackageManager.getInstalledPackagesAsUser(/*PackageInfoFlags = */ 0, userId);
+ return packages.stream().filter(pkg -> pkg.packageName.equals(packageName))
+ .findAny().orElse(null) != null;
+ }
+
/**
- * Creates a new Android user.
+ * Creates a new Android user, returning its id.
*/
- private int createNewUser(String name) {
+ private int createNewUser(String name, boolean isGuestUser) {
Log.i(TAG, "Creating new user " + name);
int newUserId = invokeMethodWithShellPermissions(sCarUserManager,
- (um) -> um.createUser(name));
+ (um) -> um.createUser(name, isGuestUser));
Log.i(TAG, "New user created with id " + newUserId);
return newUserId;
}
@@ -267,25 +351,66 @@
}
/**
- * Waits until the current Android user is {@code userId}, or fail if it times out.
+ * Wait until the current Android user is {@code userId}, or fail if it times out.
*/
private static void waitForCurrentUser(int userId, long timeoutMs) {
- Log.i(TAG, "Waiting until current user is " + userId);
- long deadline = System.currentTimeMillis() + timeoutMs;
- do {
- int actualUserId = getCurrentUser();
- if (actualUserId == userId) {
- Log.d(TAG, "the wait is over!");
- return;
- }
- Log.d(TAG, "still on " + actualUserId + "; sleeping " + SMALL_NAP_MS + "ms");
- SystemClock.sleep(SMALL_NAP_MS);
- } while (System.currentTimeMillis() < deadline);
- fail("didn't switch to user " + userId + " in " + timeoutMs + " ms");
+ waitUntil("didn't switch to user" + userId + " in " + timeoutMs + " ms",
+ timeoutMs, () -> (getCurrentUser() == userId));
}
private static int getCurrentUser() {
// TODO: should use Activity.getCurrentUser(), but that's a @SystemApi (not @TestApi)
return Integer.parseInt(runShellCommand("am get-current-user"));
}
+
+ private static void suspendToRamAndResume() throws Exception {
+ Log.d(TAG, "Emulate suspend to RAM and resume");
+ PowerManager powerManager = sContext.getSystemService(PowerManager.class);
+ runShellCommand("cmd car_service suspend");
+ // Check for suspend success
+ waitUntil("Suspsend is not successful",
+ SUSPEND_TIMEOUT_MS, () -> !powerManager.isScreenOn());
+ // Force turn off garage mode
+ runShellCommand("cmd car_service garage-mode off");
+ runShellCommand("cmd car_service resume");
+ }
+
+ private static boolean isCurrentUserValidGuestUser() {
+ Log.d(TAG, "checking isCurrentUserValidGuestUser");
+ for (String msg : runShellCommand("cmd user list -v").split("\\r?\\n")) {
+ if (msg.contains("(current)") && !msg.contains("DISABLED")) {
+ // If current user is valid, check before exit
+ return msg.contains("GUEST");
+ }
+ }
+ return false;
+ }
+
+ private static boolean isCurrentUserInitialized() {
+ for (String msg : runShellCommand("cmd user list -v").split("\\r?\\n")) {
+ if (msg.contains("(current)")) {
+ return msg.contains("INITIALIZED");
+ }
+ }
+ return false;
+ }
+
+ private static boolean waitUntil(String msg, long timeoutMs,
+ BooleanSupplierWithThrow condition) {
+ long deadline = SystemClock.elapsedRealtime() + timeoutMs;
+ do {
+ try {
+ if (condition.getAsBoolean()) {
+ return true;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Exception in waitUntil: " + msg);
+ throw new RuntimeException(e);
+ }
+ SystemClock.sleep(SMALL_NAP_MS);
+ } while (SystemClock.elapsedRealtime() < deadline);
+
+ fail(msg + " after: " + timeoutMs + "ms");
+ return false;
+ }
}
diff --git a/tests/tests/contactsproviderwipe/src/android/provider/cts/contactsproviderwipe/ContactsContract_Wipe.java b/tests/tests/contactsproviderwipe/src/android/provider/cts/contactsproviderwipe/ContactsContract_Wipe.java
index 8bc8134..d1bd895 100644
--- a/tests/tests/contactsproviderwipe/src/android/provider/cts/contactsproviderwipe/ContactsContract_Wipe.java
+++ b/tests/tests/contactsproviderwipe/src/android/provider/cts/contactsproviderwipe/ContactsContract_Wipe.java
@@ -185,6 +185,9 @@
@Override
public void onChange(boolean selfChange, Uri uri) {
Log.i(TAG, "Received notification on " + uri);
+ if (uri == null || !uri.equals(ProviderStatus.CONTENT_URI)) {
+ return; // we only care about a change to ProviderStatus.CONTENT_URI
+ }
notifiedUri.set(uri);
latch.countDown();
}
diff --git a/tests/tests/content/Android.bp b/tests/tests/content/Android.bp
index fa04cba..311974b 100644
--- a/tests/tests/content/Android.bp
+++ b/tests/tests/content/Android.bp
@@ -41,6 +41,7 @@
// TODO: remove once Android migrates to JUnit 4.12, which provides assertThrows:
"testng",
"androidx.legacy_legacy-support-v4",
+ "androidx.test.core",
],
// Use multi-dex as the compatibility-common-util-devicesidelib dependency
// on compatibility-device-util-axt pushes us beyond 64k methods.
diff --git a/tests/tests/content/data/v4-only-original.apk.idsig b/tests/tests/content/data/v4-only-original.apk.idsig
index 3ac4c80..c6ea405 100644
--- a/tests/tests/content/data/v4-only-original.apk.idsig
+++ b/tests/tests/content/data/v4-only-original.apk.idsig
Binary files differ
diff --git a/tests/tests/content/src/android/content/cts/ContextAccessTest.java b/tests/tests/content/src/android/content/cts/ContextAccessTest.java
new file mode 100644
index 0000000..9abd8d9
--- /dev/null
+++ b/tests/tests/content/src/android/content/cts/ContextAccessTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2020 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.content.cts;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.app.Activity;
+import android.app.Service;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+import android.view.Display;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.rule.ServiceTestRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Test for {@link Context#getDisplay()}.
+ * <p>Test context type listed below:</p>
+ * <ul>
+ * <li>{@link android.app.Application} - throw exception</li>
+ * <li>{@link Service} - throw exception</li>
+ * <li>{@link Activity} - get {@link Display} entity</li>
+ * <li>Context via {@link Context#createWindowContext(int, Bundle)}
+ * - get {@link Display} entity</li>
+ * <li>Context via {@link Context#createDisplayContext(Display)}
+ * - get {@link Display} entity</li>
+ * <li>{@link ContextWrapper} with base display-associated {@link Context}
+ * - get {@link Display} entity</li>
+ * <li>{@link ContextWrapper} with base non-display-associated {@link Context}
+ * - get {@link Display} entity</li>
+ * </ul>
+ *
+ * <p>Build/Install/Run:
+ * atest CtsContentTestCases:ContextAccessTest
+ */
+@Presubmit
+@SmallTest
+public class ContextAccessTest {
+ private Context mContext = ApplicationProvider.getApplicationContext();
+
+ @Rule
+ public final ActivityTestRule<MockActivity> mActivityRule =
+ new ActivityTestRule<>(MockActivity.class);
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testGetDisplayFromApplication() {
+ mContext.getDisplay();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testGetDisplayFromService() throws TimeoutException {
+ getTestService().getDisplay();
+ }
+
+ @Test
+ public void testGetDisplayFromActivity() throws Throwable {
+ final Display d = getTestActivity().getDisplay();
+
+ assertNotNull("Display must be accessible from visual components", d);
+ }
+
+ @Test
+ public void testGetDisplayFromDisplayContext() {
+ final Display display = mContext.getSystemService(DisplayManager.class)
+ .getDisplay(DEFAULT_DISPLAY);
+ Context displayContext = mContext.createDisplayContext(display);
+
+ assertEquals(display, displayContext.getDisplay());
+ }
+
+ @Test
+ public void testGetDisplayFromWindowContext() {
+ final Display display = mContext.getSystemService(DisplayManager.class)
+ .getDisplay(DEFAULT_DISPLAY);
+ Context windowContext = mContext.createDisplayContext(display)
+ .createWindowContext(TYPE_APPLICATION_OVERLAY, null /* options */);
+ assertEquals(display, windowContext.getDisplay());
+ }
+
+ @Test
+ public void testGetDisplayFromVisualWrapper() throws Throwable {
+ final Display d = new ContextWrapper(getTestActivity()).getDisplay();
+
+ assertNotNull("Display must be accessible from visual components", d);
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testGetDisplayFromNonVisualWrapper() {
+ ContextWrapper wrapper = new ContextWrapper(mContext);
+ wrapper.getDisplay();
+ }
+
+ private Activity getTestActivity() throws Throwable {
+ MockActivity[] activity = new MockActivity[1];
+ mActivityRule.runOnUiThread(() -> {
+ activity[0] = mActivityRule.getActivity();
+ });
+ return activity[0];
+ }
+
+ private Service getTestService() throws TimeoutException {
+ final Intent intent = new Intent(mContext.getApplicationContext(), MockService.class);
+ final ServiceTestRule serviceRule = new ServiceTestRule();
+ IBinder serviceToken;
+ serviceToken = serviceRule.bindService(intent);
+ return ((MockService.MockBinder) serviceToken).getService();
+ }
+}
diff --git a/tests/tests/content/src/android/content/cts/ContextTest.java b/tests/tests/content/src/android/content/cts/ContextTest.java
index 5a41584..f6f7cf5 100644
--- a/tests/tests/content/src/android/content/cts/ContextTest.java
+++ b/tests/tests/content/src/android/content/cts/ContextTest.java
@@ -1414,6 +1414,64 @@
}.run();
}
+ /** The receiver should get the broadcast if it has all the permissions. */
+ public void testSendBroadcastWithMultiplePermissions_receiverHasAllPermissions()
+ throws Exception {
+ final ResultReceiver receiver = new ResultReceiver();
+
+ registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION));
+
+ mContext.sendBroadcastWithMultiplePermissions(
+ new Intent(ResultReceiver.MOCK_ACTION),
+ new String[] { // this test APK has both these permissions
+ android.Manifest.permission.ACCESS_WIFI_STATE,
+ android.Manifest.permission.ACCESS_NETWORK_STATE,
+ });
+
+ new PollingCheck(BROADCAST_TIMEOUT) {
+ @Override
+ protected boolean check() {
+ return receiver.hasReceivedBroadCast();
+ }
+ }.run();
+ }
+
+ /** The receiver should not get the broadcast if it does not have all the permissions. */
+ public void testSendBroadcastWithMultiplePermissions_receiverHasSomePermissions()
+ throws Exception {
+ final ResultReceiver receiver = new ResultReceiver();
+
+ registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION));
+
+ mContext.sendBroadcastWithMultiplePermissions(
+ new Intent(ResultReceiver.MOCK_ACTION),
+ new String[] { // this test APK only has ACCESS_WIFI_STATE
+ android.Manifest.permission.ACCESS_WIFI_STATE,
+ android.Manifest.permission.NETWORK_STACK,
+ });
+
+ Thread.sleep(BROADCAST_TIMEOUT);
+ assertFalse(receiver.hasReceivedBroadCast());
+ }
+
+ /** The receiver should not get the broadcast if it has none of the permissions. */
+ public void testSendBroadcastWithMultiplePermissions_receiverHasNoPermissions()
+ throws Exception {
+ final ResultReceiver receiver = new ResultReceiver();
+
+ registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION));
+
+ mContext.sendBroadcastWithMultiplePermissions(
+ new Intent(ResultReceiver.MOCK_ACTION),
+ new String[] { // this test APK has neither of these permissions
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_STACK,
+ });
+
+ Thread.sleep(BROADCAST_TIMEOUT);
+ assertFalse(receiver.hasReceivedBroadCast());
+ }
+
public void testEnforceCallingOrSelfUriPermission() {
try {
Uri uri = Uri.parse("content://ctstest");
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
index 1467cba..41c5d07 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
@@ -51,7 +51,7 @@
import java.util.stream.Collectors;
@RunWith(Parameterized.class)
-@AppModeFull // TODO(Instant) Figure out which APIs should work.
+@AppModeFull
public class PackageManagerShellCommandTest {
private static final String TEST_APP_PACKAGE = "com.example.helloworld";
@@ -377,6 +377,18 @@
assertEquals("base, config.mdpi, config.xxhdpi", getSplits(TEST_APP_PACKAGE));
}
+ @Test
+ public void testAppInstallErrDuplicate() throws Exception {
+ if (!mStreaming) {
+ return;
+ }
+ String split = createApkPath(TEST_HW5);
+ String commandResult = executeShellCommand(
+ "pm " + mInstall + " -t -g " + split + " " + split);
+ assertEquals("Failure [failed to add file(s)]\n", commandResult);
+ assertFalse(isAppInstalled(TEST_APP_PACKAGE));
+ }
+
private String createUpdateSession(String packageName) throws IOException {
return createSession("-p " + packageName);
}
diff --git a/tests/tests/gwp-asan/OWNERS b/tests/tests/gwp-asan/OWNERS
new file mode 100644
index 0000000..9686261
--- /dev/null
+++ b/tests/tests/gwp-asan/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 14890
+eugenis@google.com
+pcc@google.com
+mitchp@google.com
+
diff --git a/tests/tests/gwp-asan/TEST_MAPPING b/tests/tests/gwp-asan/TEST_MAPPING
new file mode 100644
index 0000000..1976d66
--- /dev/null
+++ b/tests/tests/gwp-asan/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsGwpAsanTestCases"
+ }
+ ]
+}
diff --git a/tests/tests/gwp-asan/enabled/Android.bp b/tests/tests/gwp-asan/enabled/Android.bp
new file mode 100644
index 0000000..533330a
--- /dev/null
+++ b/tests/tests/gwp-asan/enabled/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2020 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.
+
+android_test {
+ name: "CtsGwpAsanTestCases",
+ defaults: ["cts_defaults"],
+ compile_multilib: "both",
+ // When built, explicitly put it in the data partition.
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+ libs: [
+ "android.test.runner.stubs",
+ "android.test.base.stubs",
+ ],
+ static_libs: [
+ "ctstestrunner-axt",
+ "androidx.test.rules",
+ "androidx.test.core",
+ "androidx.test.ext.junit",
+ ],
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+ use_embedded_native_libs: false,
+}
diff --git a/tests/tests/gwp-asan/enabled/AndroidManifest.xml b/tests/tests/gwp-asan/enabled/AndroidManifest.xml
new file mode 100644
index 0000000..acded16
--- /dev/null
+++ b/tests/tests/gwp-asan/enabled/AndroidManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.gwpasan.cts"
+ android:targetSandboxVersion="2">
+
+ <application android:extractNativeLibs="true"
+ android:gwpAsanMode="always">
+ <processes>
+ <process />
+ <process android:process=":gwp_asan_enabled"
+ android:gwpAsanMode="always" />
+ <process android:process=":gwp_asan_disabled"
+ android:gwpAsanMode="never" />
+ <process android:process=":gwp_asan_default" />
+ </processes>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.gwpasan.GwpAsanTestActivity" />
+ <activity android:name="android.gwpasan.GwpAsanEnabledActivity"
+ android:process=":gwp_asan_enabled" />
+ <activity android:name="android.gwpasan.GwpAsanDisabledActivity"
+ android:process=":gwp_asan_disabled" />
+ <activity android:name="android.gwpasan.GwpAsanDefaultActivity"
+ android:process=":gwp_asan_default" />
+ <service android:name="android.gwpasan.GwpAsanEnabledService"
+ android:process=":gwp_asan_enabled" />
+ <service android:name="android.gwpasan.GwpAsanDisabledService"
+ android:process=":gwp_asan_disabled" />
+ <service android:name="android.gwpasan.GwpAsanDefaultService"
+ android:process=":gwp_asan_default" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.gwpasan.cts"
+ android:label="CTS tests of GWP-ASan">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+</manifest>
diff --git a/tests/tests/gwp-asan/enabled/AndroidTest.xml b/tests/tests/gwp-asan/enabled/AndroidTest.xml
new file mode 100644
index 0000000..61580ca
--- /dev/null
+++ b/tests/tests/gwp-asan/enabled/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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 GWP-ASan test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="art" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsGwpAsanTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.gwpasan.cts" />
+ </test>
+</configuration>
diff --git a/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanDefaultActivity.java b/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanDefaultActivity.java
new file mode 100644
index 0000000..9643fa2
--- /dev/null
+++ b/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanDefaultActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 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.gwpasan;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.lang.Override;
+
+import android.gwpasan.Utils;
+
+public class GwpAsanDefaultActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ try {
+ boolean enabled = Utils.isGwpAsanEnabled();
+ setResult(RESULT_FIRST_USER + (enabled ? 1 : 0));
+ } catch (Exception e) {
+ setResult(RESULT_OK);
+ }
+ finish();
+ }
+
+}
diff --git a/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanDefaultService.java b/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanDefaultService.java
new file mode 100644
index 0000000..d7e9ccf
--- /dev/null
+++ b/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanDefaultService.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 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.gwpasan;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import java.lang.Override;
+
+import android.gwpasan.Utils;
+
+public class GwpAsanDefaultService extends Service {
+
+ private final IBinder mBinder = new LocalBinder();
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ public class LocalBinder extends Binder {
+
+ @Override
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
+ if (code == 42) {
+ try {
+ reply.writeInt(Utils.isGwpAsanEnabled() ? 1 : 0);
+ } catch (Exception e) {
+ reply.writeInt(-1);
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanDisabledActivity.java b/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanDisabledActivity.java
new file mode 100644
index 0000000..4245820
--- /dev/null
+++ b/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanDisabledActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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.gwpasan;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+
+import java.lang.Override;
+
+import android.gwpasan.Utils;
+
+public class GwpAsanDisabledActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ try {
+ boolean enabled = Utils.isGwpAsanEnabled();
+ setResult(RESULT_FIRST_USER + (enabled ? 1 : 0));
+ } catch (Exception e) {
+ setResult(RESULT_OK);
+ }
+ finish();
+ }
+
+}
diff --git a/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanDisabledService.java b/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanDisabledService.java
new file mode 100644
index 0000000..acc3c47
--- /dev/null
+++ b/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanDisabledService.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 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.gwpasan;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import java.lang.Override;
+
+import android.gwpasan.Utils;
+
+public class GwpAsanDisabledService extends Service {
+
+ private final IBinder mBinder = new LocalBinder();
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ public class LocalBinder extends Binder {
+
+ @Override
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
+ if (code == 42) {
+ try {
+ reply.writeInt(Utils.isGwpAsanEnabled() ? 1 : 0);
+ } catch (Exception e) {
+ reply.writeInt(-1);
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanEnabledActivity.java b/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanEnabledActivity.java
new file mode 100644
index 0000000..93d49ad
--- /dev/null
+++ b/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanEnabledActivity.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 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.gwpasan;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+
+import java.lang.Override;
+
+import android.gwpasan.Utils;
+
+public class GwpAsanEnabledActivity extends Activity {
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ try {
+ boolean enabled = Utils.isGwpAsanEnabled();
+ setResult(RESULT_FIRST_USER + (enabled ? 1 : 0));
+ } catch (Exception e) {
+ setResult(RESULT_OK);
+ }
+ finish();
+ }
+}
diff --git a/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanEnabledService.java b/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanEnabledService.java
new file mode 100644
index 0000000..489081f
--- /dev/null
+++ b/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanEnabledService.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 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.gwpasan;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import java.lang.Override;
+
+import android.gwpasan.Utils;
+
+public class GwpAsanEnabledService extends Service {
+
+ private final IBinder mBinder = new LocalBinder();
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ public class LocalBinder extends Binder {
+
+ @Override
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
+ if (code == 42) {
+ try {
+ reply.writeInt(Utils.isGwpAsanEnabled() ? 1 : 0);
+ } catch (Exception e) {
+ reply.writeInt(-1);
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanTestActivity.java b/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanTestActivity.java
new file mode 100644
index 0000000..6cc1d43
--- /dev/null
+++ b/tests/tests/gwp-asan/enabled/src/android/gwpasan/GwpAsanTestActivity.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 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.gwpasan;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+import java.lang.Override;
+
+import android.gwpasan.Utils;
+
+public class GwpAsanTestActivity extends Activity {
+ static final String TAG = "GwpAsanTestActivity";
+
+ private int mResult;
+ private final Object mFinishEvent = new Object();
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ mResult = resultCode;
+ synchronized (mFinishEvent) {
+ mFinishEvent.notify();
+ }
+ }
+
+ protected boolean callActivity(Class<?> cls) throws Exception {
+ Thread thread = new Thread() {
+ @Override
+ public void run() {
+ try {
+ Context context = getApplicationContext();
+ Intent intent = new Intent(context, cls);
+ startActivityForResult(intent, 0);
+
+ synchronized (mFinishEvent) {
+ mFinishEvent.wait();
+ }
+ } catch(Exception e) {
+ Log.d(TAG, "callActivity got an exception " + e.toString());
+ }
+ }
+ };
+ thread.start();
+ thread.join(20000 /* millis */);
+
+ if (mResult == RESULT_OK) {
+ throw new Exception();
+ }
+ return (mResult - RESULT_FIRST_USER) == 1;
+ }
+
+ public void testGwpAsanEnabledActivity() throws Exception {
+ assertTrue(callActivity(GwpAsanEnabledActivity.class));
+ }
+
+ public void testGwpAsanDisabledActivity() throws Exception {
+ assertFalse(callActivity(GwpAsanDisabledActivity.class));
+ }
+
+ public void testGwpAsanDefaultActivity() throws Exception {
+ // GwpAsanDefaultActivity inherits the application attribute.
+ assertTrue(callActivity(GwpAsanDefaultActivity.class));
+ }
+}
diff --git a/tests/tests/gwp-asan/enabled/src/android/gwpasan/Utils.java b/tests/tests/gwp-asan/enabled/src/android/gwpasan/Utils.java
new file mode 100644
index 0000000..395eea4
--- /dev/null
+++ b/tests/tests/gwp-asan/enabled/src/android/gwpasan/Utils.java
@@ -0,0 +1,19 @@
+package android.gwpasan;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+public class Utils {
+
+ public static boolean isGwpAsanEnabled() throws IOException {
+ BufferedReader reader = new BufferedReader(new FileReader("proc/self/maps"));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (line.contains("GWP-ASan Guard Page")) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/tests/tests/gwp-asan/enabled/src/android/gwpasan/cts/GwpAsanActivityTest.java b/tests/tests/gwp-asan/enabled/src/android/gwpasan/cts/GwpAsanActivityTest.java
new file mode 100644
index 0000000..3d6d834
--- /dev/null
+++ b/tests/tests/gwp-asan/enabled/src/android/gwpasan/cts/GwpAsanActivityTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 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.gwpasan.cts;
+
+import android.test.ActivityInstrumentationTestCase2;
+import static org.junit.Assert.assertTrue;
+import android.util.Log;
+import android.gwpasan.GwpAsanTestActivity;
+import android.gwpasan.Utils;
+
+public class GwpAsanActivityTest extends ActivityInstrumentationTestCase2<GwpAsanTestActivity> {
+
+ private GwpAsanTestActivity mActivity;
+
+ public GwpAsanActivityTest() {
+ super(GwpAsanTestActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ }
+
+ public void testGwpAsanEnabledApplication() throws Exception {
+ assertTrue(Utils.isGwpAsanEnabled());
+ }
+
+ public void testGwpAsanEnabledActivity() throws Exception {
+ mActivity.testGwpAsanEnabledActivity();
+ }
+
+ public void testGwpAsanDisabledActivity() throws Exception {
+ mActivity.testGwpAsanDisabledActivity();
+ }
+
+ public void testGwpAsanDefaultActivity() throws Exception {
+ mActivity.testGwpAsanDefaultActivity();
+ }
+}
diff --git a/tests/tests/gwp-asan/enabled/src/android/gwpasan/cts/GwpAsanServiceTest.java b/tests/tests/gwp-asan/enabled/src/android/gwpasan/cts/GwpAsanServiceTest.java
new file mode 100644
index 0000000..a7beaa4
--- /dev/null
+++ b/tests/tests/gwp-asan/enabled/src/android/gwpasan/cts/GwpAsanServiceTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 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.gwpasan.cts;
+
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Parcel;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.rule.ServiceTestRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeoutException;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+import android.gwpasan.GwpAsanEnabledService;
+import android.gwpasan.GwpAsanDisabledService;
+import android.gwpasan.GwpAsanDefaultService;
+
+@RunWith(AndroidJUnit4.class)
+public class GwpAsanServiceTest {
+ @Rule
+ public final ServiceTestRule mServiceRule = new ServiceTestRule();
+
+ private boolean isGwpAsanEnabledInService(Class<?> cls) throws Exception {
+ Intent serviceIntent = new Intent(getApplicationContext(), cls);
+ IBinder binder = mServiceRule.bindService(serviceIntent);
+ final Parcel request = Parcel.obtain();
+ final Parcel reply = Parcel.obtain();
+ if (!binder.transact(42, request, reply, 0)) {
+ throw new Exception();
+ }
+ int res = reply.readInt();
+ if (res < 0) {
+ throw new Exception();
+ }
+ return res != 0;
+ }
+
+ @Test
+ public void testEnabledService() throws Exception {
+ assertTrue(isGwpAsanEnabledInService(GwpAsanEnabledService.class));
+ }
+
+ @Test
+ public void testDisabledService() throws Exception {
+ assertFalse(isGwpAsanEnabledInService(GwpAsanDisabledService.class));
+ }
+
+ @Test
+ public void testDefaultService() throws Exception {
+ // GwpAsanDefaultService inherits the application attribute.
+ assertTrue(isGwpAsanEnabledInService(GwpAsanDefaultService.class));
+ }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 46592ca..5cb08a1 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -53,6 +53,7 @@
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.hasItems;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.SystemProperties;
@@ -164,6 +165,10 @@
KM_PURPOSE_SIGN, KM_PURPOSE_VERIFY, KM_PURPOSE_SIGN | KM_PURPOSE_VERIFY
};
+ // Skip the test if there is no secure lock screen
+ if (!hasSecureLockScreen()) {
+ return;
+ }
for (int curveIndex = 0; curveIndex < curves.length; ++curveIndex) {
for (int challengeIndex = 0; challengeIndex < challenges.length; ++challengeIndex) {
for (int purposeIndex = 0; purposeIndex < purposes.length; ++purposeIndex) {
@@ -326,6 +331,10 @@
},
};
+ // Skip the test if there is no secure lock screen
+ if (!hasSecureLockScreen()) {
+ return;
+ }
for (int keySize : keySizes) {
for (byte[] challenge : challenges) {
for (int purpose : purposes) {
@@ -1145,4 +1154,15 @@
}
}
}
+ /*
+ * Device that don't report android.software.device_admin doesn't have secure lock screen
+ * because device with secure lock screen MUST report android.software.device_admin .
+ *
+ * https://source.android.com/compatibility/7.0/android-7.0-cdd.html#3_9_device_administration
+ *
+ */
+ private boolean hasSecureLockScreen() {
+ PackageManager pm = getContext().getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
+ }
}
diff --git a/tests/tests/media/Android.bp b/tests/tests/media/Android.bp
index 83d6aef..0414e7d 100644
--- a/tests/tests/media/Android.bp
+++ b/tests/tests/media/Android.bp
@@ -59,6 +59,7 @@
"-0 .ts",
"-0 .heic",
"-0 .trp",
+ "-0 .ota",
],
srcs: ["src/**/*.java"],
// This test uses private APIs
diff --git a/tests/tests/media/libmediandkjni/native_media_encoder_jni.cpp b/tests/tests/media/libmediandkjni/native_media_encoder_jni.cpp
index fd7ddc5..2333ddd 100644
--- a/tests/tests/media/libmediandkjni/native_media_encoder_jni.cpp
+++ b/tests/tests/media/libmediandkjni/native_media_encoder_jni.cpp
@@ -213,7 +213,6 @@
int32_t nFrameCount = 0;
while (nFrameCount < framesToEncode) {
-
// apply frame-specific settings
for (;paramItr != dynamicParams.end()
&& (*paramItr)->frameNum() <= nFrameCount; ++paramItr) {
@@ -228,7 +227,7 @@
}
AMediaCodecBufferInfo info;
- int status = AMediaCodec_dequeueOutputBuffer(mEnc.get(), &info, 5000);
+ int status = AMediaCodec_dequeueOutputBuffer(mEnc.get(), &info, 5000000);
if (status >= 0) {
ALOGV("got encoded buffer[%d] of size=%d @%lld us flags=%x",
nFrameCount, info.size, (long long)info.presentationTimeUs, info.flags);
@@ -248,6 +247,8 @@
mStats.setOutputFormat(format);
ALOGV("format changed: %s", AMediaFormat_toString(format.get()));
} else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
+ ALOGE("no frame in 5 seconds, assume stuck");
+ break;
} else {
ALOGV("Invalid status : %d", status);
}
diff --git a/tests/tests/media/res/raw/testimy.imy b/tests/tests/media/res/raw/testimy.imy
new file mode 100644
index 0000000..d837815
--- /dev/null
+++ b/tests/tests/media/res/raw/testimy.imy
@@ -0,0 +1,10 @@
+BEGIN:IMELODY
+VERSION:1.2
+FORMAT:CLASS1.0
+NAME:Test
+COMPOSER:Android
+BEAT:120
+STYLE:S1
+VOLUME:V7
+MELODY:a1b2c3backoffa3.backon*4d3a3backoffg3.backon*5c4c1*5#f2*5#f2
+END:IMELODY
diff --git a/tests/tests/media/res/raw/testota.ota b/tests/tests/media/res/raw/testota.ota
new file mode 100644
index 0000000..7aa5f996
--- /dev/null
+++ b/tests/tests/media/res/raw/testota.ota
Binary files differ
diff --git a/tests/tests/media/res/raw/testrtttl.rtttl b/tests/tests/media/res/raw/testrtttl.rtttl
new file mode 100644
index 0000000..1f7e270
--- /dev/null
+++ b/tests/tests/media/res/raw/testrtttl.rtttl
@@ -0,0 +1 @@
+Test:d=2,o=6,b=120,l=2,s=n:a,b,c,d,e,4a,4b#,4c,4d,a4,b4,c4,d4
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index 7e475d1..6268466 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -617,6 +617,11 @@
int maxMusicVolume = mAudioManager.getStreamMaxVolume(STREAM_MUSIC);
for (int stream : streams) {
+
+ if (mIsSingleVolume && stream != AudioManager.STREAM_MUSIC) {
+ continue;
+ }
+
// set ringer mode to back normal to not interfere with volume tests
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
diff --git a/tests/tests/media/src/android/media/cts/AudioMetadataTest.java b/tests/tests/media/src/android/media/cts/AudioMetadataTest.java
index 4272363..8fa4eaa 100755
--- a/tests/tests/media/src/android/media/cts/AudioMetadataTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioMetadataTest.java
@@ -112,6 +112,63 @@
);
}
+ // Vendor keys created by direct override of the AudioMetadata interface.
+ private static final AudioMetadata.Key<Integer>
+ KEY_VENDOR_INTEGER = new AudioMetadata.Key<Integer>() {
+ @Override
+ public String getName() {
+ return "vendor.integerData";
+ }
+
+ @Override
+ public Class<Integer> getValueClass() {
+ return Integer.class; // matches Class<Integer>
+ }
+ };
+
+ private static final AudioMetadata.Key<Double>
+ KEY_VENDOR_DOUBLE = new AudioMetadata.Key<Double>() {
+ @Override
+ public String getName() {
+ return "vendor.doubleData";
+ }
+
+ @Override
+ public Class<Double> getValueClass() {
+ return Double.class; // matches Class<Double>
+ }
+ };
+
+ private static final AudioMetadata.Key<String>
+ KEY_VENDOR_STRING = new AudioMetadata.Key<String>() {
+ @Override
+ public String getName() {
+ return "vendor.stringData";
+ }
+
+ @Override
+ public Class<String> getValueClass() {
+ return String.class; // matches Class<String>
+ }
+ };
+
+ @Test
+ public void testVendorKeys() {
+ final AudioMetadata.Map audioMetadata = AudioMetadata.createMap();
+
+ audioMetadata.set(KEY_VENDOR_INTEGER, 10);
+ final int ivalue = audioMetadata.get(KEY_VENDOR_INTEGER);
+ assertEquals(10, ivalue);
+
+ audioMetadata.set(KEY_VENDOR_DOUBLE, 11.5);
+ final double dvalue = audioMetadata.get(KEY_VENDOR_DOUBLE);
+ assertEquals(11.5, dvalue, 0. /* epsilon */);
+
+ audioMetadata.set(KEY_VENDOR_STRING, "alphabet");
+ final String svalue = audioMetadata.get(KEY_VENDOR_STRING);
+ assertEquals("alphabet", svalue);
+ }
+
// The byte buffer here is generated by audio_utils::metadata::byteStringFromData(Data).
// Data data = {
// "integer": (int32_t) 1,
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index 05f7f37..f270d33 100644
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -1123,8 +1123,7 @@
@Override
public void onError(MediaCodec codec, MediaCodec.CodecException e) {
- Log.i(TAG, "got codec exception", e);
- fail("received codec error during decode" + e);
+ Log.e(TAG, "got codec exception", e);
}
@Override
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecBlockModelTest.java b/tests/tests/media/src/android/media/cts/MediaCodecBlockModelTest.java
index 7123d9c..be69243 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecBlockModelTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecBlockModelTest.java
@@ -207,8 +207,8 @@
MediaCodec.OutputFrame frame = codec.getOutputFrame(index);
boolean eos = (frame.getFlags() & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
- if (mGraphic && frame.getGraphicBlock() != null) {
- frame.getGraphicBlock().recycle();
+ if (mGraphic && frame.getHardwareBuffer() != null) {
+ frame.getHardwareBuffer().close();
}
if (!mGraphic && frame.getLinearBlock() != null) {
frame.getLinearBlock().recycle();
@@ -232,8 +232,8 @@
boolean eos = (frame.getFlags() & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
boolean render = false;
- if (frame.getGraphicBlock() != null) {
- frame.getGraphicBlock().recycle();
+ if (frame.getHardwareBuffer() != null) {
+ frame.getHardwareBuffer().close();
render = true;
}
codec.releaseOutputBuffer(index, render);
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index 3e547bb..57cb6e0 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -403,8 +403,13 @@
}
public void testPlayMidi() throws Exception {
- final int resid = R.raw.midi8sec;
- final int midiDuration = 8000;
+ runMidiTest(R.raw.midi8sec, 8000 /* duration */);
+ runMidiTest(R.raw.testrtttl, 30000 /* duration */);
+ runMidiTest(R.raw.testimy, 5125 /* duration */);
+ runMidiTest(R.raw.testota, 5906 /* duration */);
+ }
+
+ private void runMidiTest(int resid, int midiDuration) throws Exception {
final int tolerance = 70;
final int seekDuration = 1000;
diff --git a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
index 73fc811..b135f89 100644
--- a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
@@ -50,6 +50,7 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.HashMap;
@@ -81,6 +82,7 @@
private int mMediaBuffersEnqueuedCount;
// Media buffers decoded.
private int mMediaBuffersDecodedCount;
+ private final AtomicReference<String> errorMsg = new AtomicReference(null);
public VideoStorage() {
mStream = new LinkedList<Pair<ByteBuffer, BufferInfo>>();
@@ -141,7 +143,10 @@
}
public void onError(MediaCodec codec, MediaCodec.CodecException e) {
Log.i(TAG, "got codec exception", e);
- fail("received codec error during decode" + e);
+ errorMsg.set("received codec error during decode" + e);
+ synchronized (condition) {
+ condition.notifyAll();
+ }
}
public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
Log.i(TAG, "got output format " + format);
@@ -158,6 +163,7 @@
}
}
decoder.stop();
+ assertNull(errorMsg.get(), errorMsg.get());
// All enqueued media data buffers should have got decoded.
if (mMediaBuffersEnqueuedCount != mMediaBuffersDecodedCount) {
Log.i(TAG, "mMediaBuffersEnqueuedCount:" + mMediaBuffersEnqueuedCount);
@@ -473,6 +479,7 @@
private LinkedList<Integer> mEncInputBuffers = new LinkedList<Integer>();
private int mEncInputBufferSize = -1;
+ private final AtomicReference<String> errorMsg = new AtomicReference(null);
@Override
public boolean processLoop(
@@ -495,7 +502,7 @@
mEncoder.start();
// main loop - process GL ops as only main thread has GL context
- while (!mCompleted) {
+ while (!mCompleted && errorMsg.get() == null) {
Pair<Integer, BufferInfo> decBuffer = null;
int encBuffer = -1;
synchronized (mCondition) {
@@ -546,6 +553,7 @@
} finally {
close();
}
+ assertNull(errorMsg.get(), errorMsg.get());
return !skipped;
}
@@ -635,7 +643,13 @@
@Override
public void onError(MediaCodec mediaCodec, MediaCodec.CodecException e) {
- fail("received error on " + mediaCodec.getName() + ": " + e);
+ String codecName = null;
+ try {
+ codecName = mediaCodec.getName();
+ } catch (Exception ex) {
+ codecName = "(error getting codec name)";
+ }
+ errorMsg.set("received error on " + codecName + ": " + e);
}
@Override
@@ -690,6 +704,8 @@
private LinkedList<Pair<Integer, BufferInfo>> mBuffersToRender =
new LinkedList<Pair<Integer, BufferInfo>>();
+ private final AtomicReference<String> errorMsg = new AtomicReference(null);
+
@Override
public boolean processLoop(
String path, String outMime, String videoEncName,
@@ -716,7 +732,7 @@
mEncoder.start();
// main loop - process GL ops as only main thread has GL context
- while (!mCompleted) {
+ while (!mCompleted && errorMsg.get() == null) {
BufferInfo info = null;
synchronized (mCondition) {
try {
@@ -784,6 +800,7 @@
mDecSurface = null;
}
}
+ assertNull(errorMsg.get(), errorMsg.get());
return !skipped;
}
@@ -867,7 +884,13 @@
@Override
public void onError(MediaCodec mediaCodec, MediaCodec.CodecException e) {
- fail("received error on " + mediaCodec.getName() + ": " + e);
+ String codecName = null;
+ try {
+ codecName = mediaCodec.getName();
+ } catch (Exception ex) {
+ codecName = "(error getting codec name)";
+ }
+ errorMsg.set("received error on " + codecName + ": " + e);
}
@Override
diff --git a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java
index 73abb28..8daaed0 100644
--- a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java
+++ b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java
@@ -37,6 +37,30 @@
@RunWith(AndroidJUnit4.class)
public class MediaParserTest {
+ @Test
+ public void testCreationByName() {
+ testCreationByName("exo.MatroskaParser");
+ testCreationByName("exo.FragmentedMp4Parser");
+ testCreationByName("exo.Mp4Parser");
+ testCreationByName("exo.Mp3Parser");
+ testCreationByName("exo.AdtsParser");
+ testCreationByName("exo.Ac3Parser");
+ testCreationByName("exo.TsParser");
+ testCreationByName("exo.FlvParser");
+ testCreationByName("exo.OggParser");
+ testCreationByName("exo.PsParser");
+ testCreationByName("exo.WavParser");
+ testCreationByName("exo.AmrParser");
+ testCreationByName("exo.Ac4Parser");
+ testCreationByName("exo.FlacParser");
+ try {
+ testCreationByName("exo.ExtractorThatDoesNotExist");
+ Assert.fail();
+ } catch (IllegalArgumentException e) {
+ // Expected.
+ }
+ }
+
// OGG.
@Test
@@ -340,6 +364,11 @@
testExtractAsset("mp4/sample_fragmented.mp4");
}
+ private static void testCreationByName(String name) {
+ MediaParser.createByName(
+ name, new MockMediaParserOutputConsumer(new FakeExtractorOutput()));
+ }
+
private static void testSniffAsset(String assetPath, String expectedParserName)
throws IOException, InterruptedException {
extractAsset(assetPath, expectedParserName);
@@ -358,8 +387,9 @@
MockMediaParserInputReader mockInput =
new MockMediaParserInputReader(
new FakeExtractorInput.Builder().setData(assetBytes).build());
- MediaParser mediaParser =
- MediaParser.create(new MockMediaParserOutputConsumer(new FakeExtractorOutput()));
+ MockMediaParserOutputConsumer outputConsumer =
+ new MockMediaParserOutputConsumer(new FakeExtractorOutput());
+ MediaParser mediaParser = MediaParser.create(outputConsumer);
mediaParser.advance(mockInput);
if (expectedParserName != null) {
@@ -371,5 +401,29 @@
while (mediaParser.advance(mockInput)) {
// Do nothing.
}
+
+ // If the SeekMap is seekable, test seeking in the stream.
+ MediaParser.SeekMap seekMap = outputConsumer.getSeekMap();
+ assertThat(seekMap).isNotNull();
+ if (seekMap.isSeekable()) {
+ long durationUs = seekMap.getDurationMicros();
+ for (int j = 0; j < 4; j++) {
+ outputConsumer.clearTrackOutputs();
+ long timeUs =
+ durationUs == MediaParser.SeekMap.UNKNOWN_DURATION
+ ? 0
+ : (durationUs * j) / 3;
+ MediaParser.SeekPoint seekPoint = seekMap.getSeekPoints(timeUs).first;
+ mockInput.reset();
+ mockInput.setPosition((int) seekPoint.position);
+ mediaParser.seek(seekPoint);
+ while (mediaParser.advance(mockInput)) {
+ // Do nothing.
+ }
+ if (durationUs == MediaParser.SeekMap.UNKNOWN_DURATION) {
+ break;
+ }
+ }
+ }
}
}
diff --git a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserInputReader.java b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserInputReader.java
index c906020..e9d7d11 100644
--- a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserInputReader.java
+++ b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserInputReader.java
@@ -30,6 +30,16 @@
mFakeExtractorInput = fakeExtractorInput;
}
+ public void reset() {
+ mFakeExtractorInput.reset();
+ }
+
+ public void setPosition(int position) {
+ mFakeExtractorInput.setPosition(position);
+ }
+
+ // SeekableInputReader implementation.
+
@Override
public int read(byte[] buffer, int offset, int readLength) throws IOException {
return mFakeExtractorInput.read(buffer, offset, readLength);
diff --git a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserOutputConsumer.java b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserOutputConsumer.java
index 6728c78..a20e327 100644
--- a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserOutputConsumer.java
+++ b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserOutputConsumer.java
@@ -41,13 +41,22 @@
private final FakeExtractorOutput mFakeExtractorOutput;
private final ArrayList<TrackOutput> mTrackOutputs;
+ private MediaParser.SeekMap mSeekMap;
+
public MockMediaParserOutputConsumer(FakeExtractorOutput fakeExtractorOutput) {
mFakeExtractorOutput = fakeExtractorOutput;
mTrackOutputs = new ArrayList<>();
}
+ public void clearTrackOutputs() {
+ mFakeExtractorOutput.clearTrackOutputs();
+ }
+
+ // OutputConsumer implementation.
+
@Override
- public void onSeekMap(MediaParser.SeekMap seekMap) {
+ public void onSeekMapFound(MediaParser.SeekMap seekMap) {
+ mSeekMap = seekMap;
mFakeExtractorOutput.seekMap(
new SeekMap() {
@Override
@@ -57,7 +66,7 @@
@Override
public long getDurationUs() {
- return seekMap.getDurationUs();
+ return seekMap.getDurationMicros();
}
@Override
@@ -68,12 +77,12 @@
}
@Override
- public void onTracksFound(int numberOfTracks) {
+ public void onTrackCountFound(int numberOfTracks) {
// Do nothing.
}
@Override
- public void onTrackData(int trackIndex, MediaParser.TrackData trackData) {
+ public void onTrackDataFound(int trackIndex, MediaParser.TrackData trackData) {
while (mTrackOutputs.size() <= trackIndex) {
mTrackOutputs.add(mFakeExtractorOutput.track(trackIndex, C.TRACK_TYPE_UNKNOWN));
}
@@ -81,7 +90,7 @@
}
@Override
- public void onSampleData(int trackIndex, MediaParser.InputReader inputReader)
+ public void onSampleDataFound(int trackIndex, MediaParser.InputReader inputReader)
throws IOException {
try {
mFakeExtractorOutput
@@ -115,7 +124,7 @@
}
private static SeekPoint toExoPlayerSeekPoint(MediaParser.SeekPoint seekPoint) {
- return new SeekPoint(seekPoint.timeUs, seekPoint.position);
+ return new SeekPoint(seekPoint.timeMicros, seekPoint.position);
}
private static Format toExoPlayerFormat(MediaParser.TrackData trackData) {
@@ -306,6 +315,10 @@
}
}
+ public MediaParser.SeekMap getSeekMap() {
+ return mSeekMap;
+ }
+
// Internal classes.
private class ExtractorInputAdapter implements ExtractorInput {
diff --git a/tests/tests/net/ipsec/OWNERS b/tests/tests/net/ipsec/OWNERS
new file mode 100644
index 0000000..26407ff
--- /dev/null
+++ b/tests/tests/net/ipsec/OWNERS
@@ -0,0 +1,3 @@
+lorenzo@google.com
+nharold@google.com
+satk@google.com
diff --git a/tests/tests/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/tests/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java
index 5eb3e36..29f091b 100644
--- a/tests/tests/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java
+++ b/tests/tests/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java
@@ -64,6 +64,9 @@
// wait for Wi-Fi Aware state changes & network requests callbacks
static private final int WAIT_FOR_AWARE_CHANGE_SECS = 10; // 10 seconds
+ private static final int MIN_DISTANCE_MM = 1 * 1000;
+ private static final int MAX_DISTANCE_MM = 3 * 1000;
+ private static final byte[] PMK_VALID = "01234567890123456789012345678901".getBytes();
private final Object mLock = new Object();
private final HandlerThread mHandlerThread = new HandlerThread("SingleDeviceTest");
@@ -615,7 +618,8 @@
// 2. update-subscribe
subscribeConfig = new SubscribeConfig.Builder().setServiceName(
- serviceName).setServiceSpecificInfo("extras".getBytes()).build();
+ serviceName).setServiceSpecificInfo("extras".getBytes())
+ .setMinDistanceMm(MIN_DISTANCE_MM).build();
discoverySession.updateSubscribe(subscribeConfig);
assertTrue("Subscribe update", discoveryCb.waitForCallback(
DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED));
@@ -741,7 +745,8 @@
}
/**
- * Request an Aware data-path (encrypted) as a Responder with an arbitrary peer MAC address.
+ * Request an Aware data-path (encrypted with Passphrase) as a Responder with an arbitrary peer
+ * MAC address.
* Validate that receive an onUnavailable() callback.
*/
public void testDataPathPassphraseOutOfBandFail() {
@@ -773,6 +778,40 @@
session.close();
}
+ /**
+ * Request an Aware data-path (encrypted with PMK) as a Responder with an arbitrary peer MAC
+ * address.
+ * Validate that receive an onUnavailable() callback.
+ */
+ public void testDataPathPmkOutOfBandFail() {
+ if (!TestUtils.shouldTestWifiAware(getContext())) {
+ return;
+ }
+ MacAddress mac = MacAddress.fromString("00:01:02:03:04:05");
+
+ // 1. initialize Aware: only purpose is to make sure it is available for OOB data-path
+ WifiAwareSession session = attachAndGetSession();
+
+ PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(
+ "ValidName").build();
+ DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest();
+ session.publish(publishConfig, discoveryCb, mHandler);
+ assertTrue("Publish started",
+ discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED));
+
+ // 2. request an AWARE network
+ NetworkCallbackTest networkCb = new NetworkCallbackTest();
+ NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+ NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
+ session.createNetworkSpecifierPmk(
+ WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, mac.toByteArray(),
+ PMK_VALID)).build();
+ mConnectivityManager.requestNetwork(nr, networkCb);
+ assertTrue("OnUnavailable not received", networkCb.waitForOnUnavailable());
+
+ session.close();
+ }
+
// local utilities
private WifiAwareSession attachAndGetSession() {
diff --git a/tests/tests/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java b/tests/tests/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java
new file mode 100644
index 0000000..ce5bb81
--- /dev/null
+++ b/tests/tests/net/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2020 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.net.wifi.cts;
+
+import static android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE;
+import static android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE;
+import static android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS;
+import static android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_UNKNOWN;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.UiAutomation;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiUsabilityStatsEntry;
+import android.support.test.uiautomator.UiDevice;
+import android.telephony.TelephonyManager;
+import android.test.AndroidTestCase;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.ShellIdentityUtils;
+import com.android.compatibility.common.util.SystemUtil;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+public class ConnectedNetworkScorerTest extends AndroidTestCase {
+ private WifiManager mWifiManager;
+ private UiDevice mUiDevice;
+ private boolean mWasVerboseLoggingEnabled;
+
+ private static final int DURATION = 10_000;
+ private static final int DURATION_SCREEN_TOGGLE = 2000;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ mWifiManager = getContext().getSystemService(WifiManager.class);
+ assertThat(mWifiManager).isNotNull();
+
+ // turn on verbose logging for tests
+ mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions(
+ () -> mWifiManager.isVerboseLoggingEnabled());
+ ShellIdentityUtils.invokeWithShellPermissions(
+ () -> mWifiManager.setVerboseLoggingEnabled(true));
+
+ if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true);
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ turnScreenOn();
+ PollingCheck.check("Wifi not enabled", DURATION, () -> mWifiManager.isWifiEnabled());
+ List<WifiConfiguration> savedNetworks = ShellIdentityUtils.invokeWithShellPermissions(
+ () -> mWifiManager.getConfiguredNetworks());
+ assertFalse("Need at least one saved network", savedNetworks.isEmpty());
+ // Wait for wifi is to be connected
+ PollingCheck.check(
+ "Wifi not connected",
+ DURATION,
+ () -> mWifiManager.getConnectionInfo().getNetworkId() != -1);
+ assertThat(mWifiManager.getConnectionInfo().getNetworkId()).isNotEqualTo(-1);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ super.tearDown();
+ return;
+ }
+ if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true);
+ turnScreenOff();
+ ShellIdentityUtils.invokeWithShellPermissions(
+ () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled));
+ super.tearDown();
+ }
+
+ private void setWifiEnabled(boolean enable) throws Exception {
+ // now trigger the change using shell commands.
+ SystemUtil.runShellCommand("svc wifi " + (enable ? "enable" : "disable"));
+ }
+
+ private void turnScreenOn() throws Exception {
+ mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+ mUiDevice.executeShellCommand("wm dismiss-keyguard");
+ // Since the screen on/off intent is ordered, they will not be sent right now.
+ Thread.sleep(DURATION_SCREEN_TOGGLE);
+ }
+
+ private void turnScreenOff() throws Exception {
+ mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP");
+ }
+
+ private static class TestUsabilityStatsListener implements
+ WifiManager.OnWifiUsabilityStatsListener {
+ private final CountDownLatch mCountDownLatch;
+ public int seqNum;
+ public boolean isSameBssidAndFre;
+ public WifiUsabilityStatsEntry statsEntry;
+
+ TestUsabilityStatsListener(CountDownLatch countDownLatch) {
+ mCountDownLatch = countDownLatch;
+ }
+
+ @Override
+ public void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
+ WifiUsabilityStatsEntry statsEntry) {
+ this.seqNum = seqNum;
+ this.isSameBssidAndFre = isSameBssidAndFreq;
+ this.statsEntry = statsEntry;
+ mCountDownLatch.countDown();
+ }
+ }
+
+ /**
+ * Tests the {@link android.net.wifi.WifiUsabilityStatsEntry} retrieved from
+ * {@link WifiManager.OnWifiUsabilityStatsListener}.
+ */
+ public void testWifiUsabilityStatsEntry() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ TestUsabilityStatsListener usabilityStatsListener =
+ new TestUsabilityStatsListener(countDownLatch);
+ try {
+ uiAutomation.adoptShellPermissionIdentity();
+ mWifiManager.addOnWifiUsabilityStatsListener(
+ Executors.newSingleThreadExecutor(), usabilityStatsListener);
+ // Wait for new usability stats (while connected & screen on this is triggered
+ // by platform periodically).
+ assertThat(countDownLatch.await(DURATION, TimeUnit.MILLISECONDS)).isTrue();
+
+ assertThat(usabilityStatsListener.statsEntry).isNotNull();
+ WifiUsabilityStatsEntry statsEntry = usabilityStatsListener.statsEntry;
+
+ assertThat(statsEntry.getTimeStampMillis()).isGreaterThan(0L);
+ assertThat(statsEntry.getRssi()).isLessThan(0);
+ assertThat(statsEntry.getLinkSpeedMbps()).isGreaterThan(0);
+ assertThat(statsEntry.getTotalTxSuccess()).isGreaterThan(0L);
+ assertThat(statsEntry.getTotalTxRetries()).isAtLeast(0L);
+ assertThat(statsEntry.getTotalTxBad()).isAtLeast(0L);
+ assertThat(statsEntry.getTotalRxSuccess()).isAtLeast(0L);
+ assertThat(statsEntry.getTotalRadioOnTimeMillis()).isGreaterThan(0L);
+ assertThat(statsEntry.getTotalRadioTxTimeMillis()).isGreaterThan(0L);
+ assertThat(statsEntry.getTotalRadioRxTimeMillis()).isGreaterThan(0L);
+ assertThat(statsEntry.getTotalScanTimeMillis()).isGreaterThan(0L);
+ assertThat(statsEntry.getTotalNanScanTimeMillis()).isAtLeast(0L);
+ assertThat(statsEntry.getTotalBackgroundScanTimeMillis()).isAtLeast(0L);
+ assertThat(statsEntry.getTotalRoamScanTimeMillis()).isAtLeast(0L);
+ assertThat(statsEntry.getTotalPnoScanTimeMillis()).isAtLeast(0L);
+ assertThat(statsEntry.getTotalHotspot2ScanTimeMillis()).isAtLeast(0L);
+ assertThat(statsEntry.getTotalCcaBusyFreqTimeMillis()).isAtLeast(0L);
+ assertThat(statsEntry.getTotalRadioOnTimeMillis()).isGreaterThan(0L);
+ assertThat(statsEntry.getTotalBeaconRx()).isGreaterThan(0L);
+ assertThat(statsEntry.getProbeStatusSinceLastUpdate())
+ .isAnyOf(PROBE_STATUS_SUCCESS,
+ PROBE_STATUS_FAILURE,
+ PROBE_STATUS_NO_PROBE,
+ PROBE_STATUS_UNKNOWN);
+ // -1 is default value for some of these fields if they're not available.
+ assertThat(statsEntry.getProbeElapsedTimeSinceLastUpdateMillis()).isAtLeast(-1);
+ assertThat(statsEntry.getProbeMcsRateSinceLastUpdate()).isAtLeast(-1);
+ assertThat(statsEntry.getRxLinkSpeedMbps()).isAtLeast(-1);
+ // no longer populated, return default value.
+ assertThat(statsEntry.getCellularDataNetworkType())
+ .isAnyOf(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ TelephonyManager.NETWORK_TYPE_GPRS,
+ TelephonyManager.NETWORK_TYPE_EDGE,
+ TelephonyManager.NETWORK_TYPE_UMTS,
+ TelephonyManager.NETWORK_TYPE_CDMA,
+ TelephonyManager.NETWORK_TYPE_EVDO_0,
+ TelephonyManager.NETWORK_TYPE_EVDO_A,
+ TelephonyManager.NETWORK_TYPE_1xRTT,
+ TelephonyManager.NETWORK_TYPE_HSDPA,
+ TelephonyManager.NETWORK_TYPE_HSUPA,
+ TelephonyManager.NETWORK_TYPE_HSPA,
+ TelephonyManager.NETWORK_TYPE_IDEN,
+ TelephonyManager.NETWORK_TYPE_EVDO_B,
+ TelephonyManager.NETWORK_TYPE_LTE,
+ TelephonyManager.NETWORK_TYPE_EHRPD,
+ TelephonyManager.NETWORK_TYPE_HSPAP,
+ TelephonyManager.NETWORK_TYPE_GSM,
+ TelephonyManager.NETWORK_TYPE_TD_SCDMA,
+ TelephonyManager.NETWORK_TYPE_IWLAN,
+ TelephonyManager.NETWORK_TYPE_NR);
+ assertThat(statsEntry.getCellularSignalStrengthDbm()).isAtMost(0);
+ assertThat(statsEntry.getCellularSignalStrengthDb()).isAtMost(0);
+ assertThat(statsEntry.isSameRegisteredCell()).isFalse();
+ } finally {
+ mWifiManager.removeOnWifiUsabilityStatsListener(usabilityStatsListener);
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
+ * Tests the {@link android.net.wifi.WifiManager#updateWifiUsabilityScore(int, int, int)}
+ */
+ public void testUpdateWifiUsabilityScore() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ try {
+ uiAutomation.adoptShellPermissionIdentity();
+ // update scoring with dummy values.
+ mWifiManager.updateWifiUsabilityScore(0, 50, 50);
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
+ private static class TestConnectedNetworkScorer implements
+ WifiManager.WifiConnectedNetworkScorer {
+ private CountDownLatch mCountDownLatch;
+ public int startSessionId;
+ public int stopSessionId;
+ public WifiManager.ScoreUpdateObserver scoreUpdateObserver;
+
+ TestConnectedNetworkScorer(CountDownLatch countDownLatch) {
+ mCountDownLatch = countDownLatch;
+ }
+
+ @Override
+ public void onStart(int sessionId) {
+ synchronized (mCountDownLatch) {
+ this.startSessionId = sessionId;
+ mCountDownLatch.countDown();
+ }
+ }
+
+ @Override
+ public void onStop(int sessionId) {
+ synchronized (mCountDownLatch) {
+ this.stopSessionId = sessionId;
+ mCountDownLatch.countDown();
+ }
+ }
+
+ @Override
+ public void onSetScoreUpdateObserver(WifiManager.ScoreUpdateObserver observerImpl) {
+ this.scoreUpdateObserver = observerImpl;
+ }
+
+ public void resetCountDownLatch(CountDownLatch countDownLatch) {
+ synchronized (mCountDownLatch) {
+ mCountDownLatch = countDownLatch;
+ }
+ }
+ }
+
+ /**
+ * Tests the {@link android.net.wifi.WifiConnectedNetworkScorer} interface.
+ *
+ * Note: We could write more interesting test cases (if the device has a mobile connection), but
+ * that would make the test flaky. The default network/route selection on the device is not just
+ * controlled by the wifi scorer input, but also based on params which are controlled by
+ * other parts of the platform (likely in connectivity service) and hence will behave
+ * differently on OEM devices.
+ */
+ public void testSetWifiConnectedNetworkScorer() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ CountDownLatch countDownLatchScorer = new CountDownLatch(1);
+ CountDownLatch countDownLatchUsabilityStats = new CountDownLatch(1);
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ TestConnectedNetworkScorer connectedNetworkScorer =
+ new TestConnectedNetworkScorer(countDownLatchScorer);
+ TestUsabilityStatsListener usabilityStatsListener =
+ new TestUsabilityStatsListener(countDownLatchUsabilityStats);
+ try {
+ uiAutomation.adoptShellPermissionIdentity();
+ mWifiManager.setWifiConnectedNetworkScorer(
+ Executors.newSingleThreadExecutor(), connectedNetworkScorer);
+ // Since we're already connected, wait for onStart to be invoked.
+ assertThat(countDownLatchScorer.await(DURATION, TimeUnit.MILLISECONDS)).isTrue();
+
+ assertThat(connectedNetworkScorer.startSessionId).isAtLeast(0);
+ assertThat(connectedNetworkScorer.scoreUpdateObserver).isNotNull();
+ WifiManager.ScoreUpdateObserver scoreUpdateObserver =
+ connectedNetworkScorer.scoreUpdateObserver;
+
+ // Now trigger a dummy score update.
+ scoreUpdateObserver.notifyScoreUpdate(connectedNetworkScorer.startSessionId, 50);
+
+ // Register the usability listener
+ mWifiManager.addOnWifiUsabilityStatsListener(
+ Executors.newSingleThreadExecutor(), usabilityStatsListener);
+ // Trigger a usability stats update.
+ scoreUpdateObserver.triggerUpdateOfWifiUsabilityStats(
+ connectedNetworkScorer.startSessionId);
+ // Ensure that we got the stats update callback.
+ assertThat(countDownLatchUsabilityStats.await(DURATION, TimeUnit.MILLISECONDS))
+ .isTrue();
+ assertThat(usabilityStatsListener.seqNum).isAtLeast(0);
+
+ // Reset the scorer countdown latch for onStop
+ countDownLatchScorer = new CountDownLatch(1);
+ connectedNetworkScorer.resetCountDownLatch(countDownLatchScorer);
+ // Now disconnect from the network.
+ mWifiManager.disconnect();
+ // Wait for it to be disconnected.
+ PollingCheck.check(
+ "Wifi not disconnected",
+ DURATION,
+ () -> mWifiManager.getConnectionInfo().getNetworkId() == -1);
+ assertThat(mWifiManager.getConnectionInfo().getNetworkId()).isEqualTo(-1);
+
+ // Wait for stop to be invoked and ensure that the session id matches.
+ assertThat(countDownLatchScorer.await(DURATION, TimeUnit.MILLISECONDS)).isTrue();
+ assertThat(connectedNetworkScorer.stopSessionId)
+ .isEqualTo(connectedNetworkScorer.startSessionId);
+ } finally {
+ mWifiManager.removeOnWifiUsabilityStatsListener(usabilityStatsListener);
+ mWifiManager.clearWifiConnectedNetworkScorer();
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ }
+}
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiFeature.java b/tests/tests/net/src/android/net/wifi/cts/WifiFeature.java
index 63fa1dd..3e9fef4 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiFeature.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiFeature.java
@@ -20,12 +20,12 @@
import android.content.pm.PackageManager;
public class WifiFeature {
- static boolean isWifiSupported(Context context) {
+ public static boolean isWifiSupported(Context context) {
PackageManager packageManager = context.getPackageManager();
return packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI);
}
- static boolean isP2pSupported(Context context) {
+ public static boolean isP2pSupported(Context context) {
PackageManager packageManager = context.getPackageManager();
return packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT);
}
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiHotspot2Test.java b/tests/tests/net/src/android/net/wifi/cts/WifiHotspot2Test.java
new file mode 100644
index 0000000..a05b81b
--- /dev/null
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiHotspot2Test.java
@@ -0,0 +1,488 @@
+/*
+ * Copyright (C) 2020 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.net.wifi.cts;
+
+import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE;
+
+import android.net.Uri;
+import android.net.wifi.hotspot2.OsuProvider;
+import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.pps.Credential;
+import android.net.wifi.hotspot2.pps.HomeSp;
+import android.test.AndroidTestCase;
+import android.text.TextUtils;
+
+import java.lang.reflect.Constructor;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+public class WifiHotspot2Test extends AndroidTestCase {
+ static final int SIM_CREDENTIAL = 0;
+ static final int USER_CREDENTIAL = 1;
+ static final int CERT_CREDENTIAL = 2;
+ private static final String TEST_SSID = "TEST SSID";
+ private static final String TEST_FRIENDLY_NAME = "Friendly Name";
+ private static final Map<String, String> TEST_FRIENDLY_NAMES =
+ new HashMap<String, String>() {
+ {
+ put("en", TEST_FRIENDLY_NAME);
+ put("kr", TEST_FRIENDLY_NAME + 2);
+ put("jp", TEST_FRIENDLY_NAME + 3);
+ }
+ };
+ private static final String TEST_SERVICE_DESCRIPTION = "Dummy Service";
+ private static final Uri TEST_SERVER_URI = Uri.parse("https://test.com");
+ private static final String TEST_NAI = "test.access.com";
+ private static final List<Integer> TEST_METHOD_LIST =
+ Arrays.asList(1 /* METHOD_SOAP_XML_SPP */);
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Tests {@link PasspointConfiguration#getMeteredOverride()} method.
+ * <p>
+ * Test default value
+ */
+ public void testGetMeteredOverride() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ PasspointConfiguration passpointConfiguration = new PasspointConfiguration();
+ assertEquals(METERED_OVERRIDE_NONE, passpointConfiguration.getMeteredOverride());
+ }
+
+ /**
+ * Tests {@link PasspointConfiguration#getSubscriptionExpirationTimeMillis()} method.
+ * <p>
+ * Test default value
+ */
+ public void testGetSubscriptionExpirationTimeMillis() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ PasspointConfiguration passpointConfiguration = new PasspointConfiguration();
+ assertEquals(Long.MIN_VALUE,
+ passpointConfiguration.getSubscriptionExpirationTimeMillis());
+ }
+
+ /**
+ * Tests {@link PasspointConfiguration#getUniqueId()} method.
+ * <p>
+ * Test unique identifier is not null
+ */
+ public void testGetUniqueId() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+
+ // Create a configuration and make sure the unique ID is not null
+ PasspointConfiguration passpointConfiguration1 = createConfig(SIM_CREDENTIAL, "123456*",
+ 18 /* EAP_SIM */);
+ String uniqueId1 = passpointConfiguration1.getUniqueId();
+ assertNotNull(uniqueId1);
+
+ // Create another configuration and make sure the unique ID is not null
+ PasspointConfiguration passpointConfiguration2 = createConfig(SIM_CREDENTIAL, "567890*",
+ 23 /* EAP_AKA */);
+ String uniqueId2 = passpointConfiguration2.getUniqueId();
+ assertNotNull(uniqueId2);
+
+ // Make sure the IDs are not equal
+ assertFalse(uniqueId1.equals(uniqueId2));
+
+ passpointConfiguration2 = createConfig(USER_CREDENTIAL);
+ assertFalse(uniqueId1.equals(passpointConfiguration2.getUniqueId()));
+
+ passpointConfiguration2 = createConfig(CERT_CREDENTIAL);
+ assertFalse(uniqueId1.equals(passpointConfiguration2.getUniqueId()));
+ }
+
+ /**
+ * Tests {@link PasspointConfiguration#isAutojoinEnabled()} method.
+ * <p>
+ * Test default value
+ */
+ public void testIsAutojoinEnabled() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ PasspointConfiguration passpointConfiguration = new PasspointConfiguration();
+ assertTrue(passpointConfiguration.isAutojoinEnabled());
+ }
+
+ /**
+ * Tests {@link PasspointConfiguration#isMacRandomizationEnabled()} method.
+ * <p>
+ * Test default value
+ */
+ public void testIsMacRandomizationEnabled() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ PasspointConfiguration passpointConfiguration = new PasspointConfiguration();
+ assertTrue(passpointConfiguration.isMacRandomizationEnabled());
+ }
+
+ /**
+ * Tests {@link PasspointConfiguration#isOsuProvisioned()} method.
+ * <p>
+ * Test default value
+ */
+ public void testIsOsuProvisioned() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ PasspointConfiguration passpointConfiguration = createConfig(USER_CREDENTIAL);
+ assertFalse(passpointConfiguration.isOsuProvisioned());
+ }
+
+ /**
+ * Tests {@link PasspointConfiguration#PasspointConfiguration(PasspointConfiguration)} method.
+ * <p>
+ * Test the PasspointConfiguration copy constructor
+ */
+ public void testPasspointConfigurationCopyConstructor() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ PasspointConfiguration passpointConfiguration = createConfig(USER_CREDENTIAL);
+ PasspointConfiguration copyOfPasspointConfiguration =
+ new PasspointConfiguration(passpointConfiguration);
+ assertEquals(passpointConfiguration, copyOfPasspointConfiguration);
+ }
+
+ /**
+ * Tests {@link HomeSp#HomeSp(HomeSp)} method.
+ * <p>
+ * Test the HomeSp copy constructor
+ */
+ public void testHomeSpCopyConstructor() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ HomeSp homeSp = createHomeSp();
+ HomeSp copyOfHomeSp = new HomeSp(homeSp);
+ assertEquals(copyOfHomeSp, homeSp);
+ }
+
+ /**
+ * Tests {@link Credential#Credential(Credential)} method.
+ * <p>
+ * Test the Credential copy constructor
+ */
+ public void testCredentialCopyConstructor() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ Credential credential = createCredentialWithSimCredential("123456*", 18 /* EAP_SIM */);
+ Credential copyOfCredential = new Credential(credential);
+ assertEquals(copyOfCredential, credential);
+ }
+
+ /**
+ * Tests {@link Credential.UserCredential#UserCredential(Credential.UserCredential)} method.
+ * <p>
+ * Test the Credential.UserCredential copy constructor
+ */
+ public void testUserCredentialCopyConstructor() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ Credential.UserCredential userCredential = new Credential.UserCredential();
+ userCredential.setUsername("username");
+ userCredential.setPassword("password");
+ userCredential.setEapType(21 /* EAP_TTLS */);
+ userCredential.setNonEapInnerMethod("MS-CHAP");
+
+ Credential.UserCredential copyOfUserCredential =
+ new Credential.UserCredential(userCredential);
+ assertEquals(copyOfUserCredential, userCredential);
+ }
+
+ /**
+ * Tests
+ * {@link Credential.CertificateCredential#CertificateCredential(Credential.CertificateCredential)}
+ * method.
+ * <p>
+ * Test the Credential.CertificateCredential copy constructor
+ */
+ public void testCertCredentialCopyConstructor() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ Credential.CertificateCredential certCredential = new Credential.CertificateCredential();
+ certCredential.setCertType("x509v3");
+
+ Credential.CertificateCredential copyOfCertificateCredential =
+ new Credential.CertificateCredential(certCredential);
+ assertEquals(copyOfCertificateCredential, certCredential);
+ }
+
+ /**
+ * Tests {@link Credential.SimCredential#SimCredential(Credential.SimCredential)} method.
+ * <p>
+ * Test the Credential.SimCredential copy constructor
+ */
+ public void testSimCredentialCopyConstructor() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ Credential.SimCredential simCredential = new Credential.SimCredential();
+ simCredential.setImsi("1234*");
+ simCredential.setEapType(18/* EAP_SIM */);
+
+ Credential.SimCredential copyOfSimCredential = new Credential.SimCredential(simCredential);
+ assertEquals(copyOfSimCredential, simCredential);
+ }
+
+ /**
+ * Tests {@link Credential#getCaCertificate()} method.
+ * <p>
+ * Test that getting a set certificate produces the same value
+ */
+ public void testCredentialGetCertificate() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ Credential credential = new Credential();
+ credential.setCaCertificate(FakeKeys.CA_CERT0);
+
+ assertEquals(FakeKeys.CA_CERT0, credential.getCaCertificate());
+ }
+
+ /**
+ * Tests {@link Credential#getClientCertificateChain()} and {@link
+ * Credential#setCaCertificates(X509Certificate[])} methods.
+ * <p>
+ * Test that getting a set client certificate chain produces the same value
+ */
+ public void testCredentialClientCertificateChain() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ Credential credential = new Credential();
+ X509Certificate[] certificates = new X509Certificate[]{FakeKeys.CLIENT_CERT};
+ credential.setClientCertificateChain(certificates);
+
+ assertTrue(Arrays.equals(certificates, credential.getClientCertificateChain()));
+ }
+
+ /**
+ * Tests {@link Credential#getClientPrivateKey()} and
+ * {@link Credential#setClientPrivateKey(PrivateKey)}
+ * methods.
+ * <p>
+ * Test that getting a set client private key produces the same value
+ */
+ public void testCredentialSetGetClientPrivateKey() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ Credential credential = new Credential();
+ credential.setClientPrivateKey(FakeKeys.RSA_KEY1);
+
+ assertEquals(FakeKeys.RSA_KEY1, credential.getClientPrivateKey());
+ }
+
+ /**
+ * Tests {@link Credential#getClientPrivateKey()} and
+ * {@link Credential#setClientPrivateKey(PrivateKey)}
+ * methods.
+ * <p>
+ * Test that getting a set client private key produces the same value
+ */
+ public void testCredentialGetClientPrivateKey() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ Credential credential = new Credential();
+ credential.setClientPrivateKey(FakeKeys.RSA_KEY1);
+
+ assertEquals(FakeKeys.RSA_KEY1, credential.getClientPrivateKey());
+ }
+
+ private static PasspointConfiguration createConfig(int type) throws Exception {
+ return createConfig(type, "123456*", 18 /* EAP_SIM */);
+ }
+
+ private static PasspointConfiguration createConfig(int type, String imsi, int eapType)
+ throws Exception {
+ PasspointConfiguration config = new PasspointConfiguration();
+ config.setHomeSp(createHomeSp());
+ switch (type) {
+ default:
+ case SIM_CREDENTIAL:
+ config.setCredential(
+ createCredentialWithSimCredential(imsi, eapType));
+ break;
+ case USER_CREDENTIAL:
+ config.setCredential(createCredentialWithUserCredential());
+ break;
+ case CERT_CREDENTIAL:
+ config.setCredential(createCredentialWithCertificateCredential());
+ break;
+ }
+
+ return config;
+ }
+
+ /**
+ * Helper function for generating HomeSp for testing.
+ *
+ * @return {@link HomeSp}
+ */
+ private static HomeSp createHomeSp() {
+ HomeSp homeSp = new HomeSp();
+ homeSp.setFqdn("test.com");
+ homeSp.setFriendlyName("friendly name");
+ homeSp.setRoamingConsortiumOis(new long[]{0x55, 0x66});
+ return homeSp;
+ }
+
+ /**
+ * Helper function for generating Credential for testing.
+ *
+ * @param userCred Instance of UserCredential
+ * @param certCred Instance of CertificateCredential
+ * @param simCred Instance of SimCredential
+ * @param clientCertificateChain Chain of client certificates
+ * @param clientPrivateKey Client private key
+ * @param caCerts CA certificates
+ * @return {@link Credential}
+ */
+ private static Credential createCredential(Credential.UserCredential userCred,
+ Credential.CertificateCredential certCred,
+ Credential.SimCredential simCred,
+ X509Certificate[] clientCertificateChain, PrivateKey clientPrivateKey,
+ X509Certificate... caCerts) {
+ Credential cred = new Credential();
+ cred.setRealm("realm");
+ cred.setUserCredential(userCred);
+ cred.setCertCredential(certCred);
+ cred.setSimCredential(simCred);
+ return cred;
+ }
+
+ /**
+ * Helper function for generating certificate credential for testing.
+ *
+ * @return {@link Credential}
+ */
+ private static Credential createCredentialWithCertificateCredential()
+ throws NoSuchAlgorithmException, CertificateEncodingException {
+ Credential.CertificateCredential certCred = new Credential.CertificateCredential();
+ certCred.setCertType("x509v3");
+ certCred.setCertSha256Fingerprint(
+ MessageDigest.getInstance("SHA-256").digest(
+ FakeKeys.CLIENT_CERT.getEncoded()));
+ return createCredential(null, certCred, null, new X509Certificate[]{
+ FakeKeys.CLIENT_CERT},
+ FakeKeys.RSA_KEY1, FakeKeys.CA_CERT0,
+ FakeKeys.CA_CERT1);
+ }
+
+ /**
+ * Helper function for generating SIM credential for testing.
+ *
+ * @return {@link Credential}
+ */
+ private static Credential createCredentialWithSimCredential(String imsi, int eapType) {
+ Credential.SimCredential simCred = new Credential.SimCredential();
+ simCred.setImsi(imsi);
+ simCred.setEapType(eapType);
+ return createCredential(null, null, simCred, null, null, (X509Certificate[]) null);
+ }
+
+ /**
+ * Helper function for generating user credential for testing.
+ *
+ * @return {@link Credential}
+ */
+ private static Credential createCredentialWithUserCredential() {
+ Credential.UserCredential userCred = new Credential.UserCredential();
+ userCred.setUsername("username");
+ userCred.setPassword("password");
+ userCred.setEapType(21 /* EAP_TTLS */);
+ userCred.setNonEapInnerMethod("MS-CHAP");
+ return createCredential(userCred, null, null, null, null,
+ FakeKeys.CA_CERT0);
+ }
+
+ /**
+ * Tests {@link OsuProvider#getFriendlyName()} and {@link OsuProvider#getServerUri()} methods.
+ * <p>
+ * Test that getting a set friendly name and server URI produces the same value
+ */
+ public void testOsuProviderGetters() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+
+ // Using Java reflection to construct an OsuProvider instance because its constructor is
+ // hidden and not available to apps.
+ Class<?> osuProviderClass = Class.forName("android.net.wifi.hotspot2.OsuProvider");
+ Constructor<?> osuProviderClassConstructor = osuProviderClass.getConstructor(String.class,
+ Map.class, String.class, Uri.class, String.class, List.class);
+
+ OsuProvider osuProvider = (OsuProvider) osuProviderClassConstructor.newInstance(TEST_SSID,
+ TEST_FRIENDLY_NAMES, TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI,
+ TEST_METHOD_LIST);
+ String lang = Locale.getDefault().getLanguage();
+ String friendlyName = TEST_FRIENDLY_NAMES.get(lang);
+ if (TextUtils.isEmpty(friendlyName)) {
+ friendlyName = TEST_FRIENDLY_NAMES.get("en");
+ }
+ assertEquals(friendlyName, osuProvider.getFriendlyName());
+ assertEquals(TEST_SERVER_URI, osuProvider.getServerUri());
+ }
+}
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
index f4c20e3..ae5ef75 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -32,7 +32,6 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.net.util.MacAddressUtils;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.MacAddress;
@@ -40,15 +39,28 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
+import android.net.TetheringManager;
+import android.net.Uri;
+import android.net.util.MacAddressUtils;
import android.net.wifi.ScanResult;
+import android.net.wifi.SoftApCapability;
import android.net.wifi.SoftApConfiguration;
+import android.net.wifi.SoftApInfo;
+import android.net.wifi.WifiClient;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.WifiLock;
import android.net.wifi.WifiNetworkConnectionStatistics;
import android.net.wifi.hotspot2.ConfigParser;
+import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.ProvisioningCallback;
+import android.net.wifi.hotspot2.pps.Credential;
+import android.net.wifi.hotspot2.pps.HomeSp;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.HandlerThread;
import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -66,16 +78,24 @@
import com.android.compatibility.common.util.PollingCheck;
import com.android.compatibility.common.util.ShellIdentityUtils;
import com.android.compatibility.common.util.SystemUtil;
+import com.android.compatibility.common.util.ThrowingRunnable;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.lang.reflect.Constructor;
import java.net.HttpURLConnection;
import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -90,6 +110,7 @@
private WifiManager mWifiManager;
private ConnectivityManager mConnectivityManager;
+ private TetheringManager mTetheringManager;
private WifiLock mWifiLock;
private static MySync mMySync;
private List<ScanResult> mScanResults = null;
@@ -97,6 +118,7 @@
private final Object mLock = new Object();
private UiDevice mUiDevice;
private boolean mWasVerboseLoggingEnabled;
+ private SoftApConfiguration mOriginalSoftApConfig = null;
// Please refer to WifiManager
private static final int MIN_RSSI = -100;
@@ -117,7 +139,7 @@
private static final int SCAN_TIMEOUT_MSEC = 9000;
private static final int TIMEOUT_MSEC = 6000;
private static final int WAIT_MSEC = 60;
- private static final int DURATION = 10_000;
+ private static final int TEST_WAIT_DURATION_MS = 10_000;
private static final int DURATION_SCREEN_TOGGLE = 2000;
private static final int DURATION_SETTINGS_TOGGLE = 1_000;
private static final int WIFI_SCAN_TEST_INTERVAL_MILLIS = 60 * 1000;
@@ -177,6 +199,54 @@
}
}
};
+ // Initialize with an invalid status value (0)
+ private int mProvisioningStatus = 0;
+ // Initialize with an invalid status value (0)
+ private int mProvisioningFailureStatus = 0;
+ private boolean mProvisioningComplete = false;
+ private ProvisioningCallback mProvisioningCallback = new ProvisioningCallback() {
+ @Override
+ public void onProvisioningFailure(int status) {
+ synchronized (mLock) {
+ mProvisioningFailureStatus = status;
+ mLock.notify();
+ }
+ }
+
+ @Override
+ public void onProvisioningStatus(int status) {
+ synchronized (mLock) {
+ mProvisioningStatus = status;
+ mLock.notify();
+ }
+ }
+
+ @Override
+ public void onProvisioningComplete() {
+ mProvisioningComplete = true;
+ }
+ };
+ private static final String TEST_SSID = "TEST SSID";
+ private static final String TEST_FRIENDLY_NAME = "Friendly Name";
+ private static final Map<String, String> TEST_FRIENDLY_NAMES =
+ new HashMap<String, String>() {
+ {
+ put("en", TEST_FRIENDLY_NAME);
+ put("kr", TEST_FRIENDLY_NAME + 2);
+ put("jp", TEST_FRIENDLY_NAME + 3);
+ }
+ };
+ private static final String TEST_SERVICE_DESCRIPTION = "Dummy Service";
+ private static final Uri TEST_SERVER_URI = Uri.parse("https://test.com");
+ private static final String TEST_NAI = "test.access.com";
+ private static final List<Integer> TEST_METHOD_LIST =
+ Arrays.asList(1 /* METHOD_SOAP_XML_SPP */);
+ private final HandlerThread mHandlerThread = new HandlerThread("WifiManagerTest");
+ protected final Executor mExecutor;
+ {
+ mHandlerThread.start();
+ mExecutor = new HandlerExecutor(new Handler(mHandlerThread.getLooper()));
+ }
@Override
protected void setUp() throws Exception {
@@ -199,7 +269,9 @@
mContext.registerReceiver(mReceiver, mIntentFilter);
mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
mConnectivityManager = getContext().getSystemService(ConnectivityManager.class);
+ mTetheringManager = getContext().getSystemService(TetheringManager.class);
assertNotNull(mWifiManager);
+ assertNotNull(mTetheringManager);
// turn on verbose logging for tests
mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions(
@@ -213,7 +285,7 @@
setWifiEnabled(true);
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
turnScreenOnNoDelay();
- Thread.sleep(DURATION);
+ Thread.sleep(TEST_WAIT_DURATION_MS);
assertTrue(mWifiManager.isWifiEnabled());
synchronized (mMySync) {
mMySync.expectedState = STATE_NULL;
@@ -222,6 +294,10 @@
List<WifiConfiguration> savedNetworks = ShellIdentityUtils.invokeWithShellPermissions(
mWifiManager::getConfiguredNetworks);
assertFalse("Need at least one saved network", savedNetworks.isEmpty());
+
+ // Get original config for restore
+ mOriginalSoftApConfig = ShellIdentityUtils.invokeWithShellPermissions(
+ mWifiManager::getSoftApConfiguration);
}
@Override
@@ -237,7 +313,10 @@
mContext.unregisterReceiver(mReceiver);
ShellIdentityUtils.invokeWithShellPermissions(
() -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled));
- Thread.sleep(DURATION);
+ // restore original softap config
+ ShellIdentityUtils.invokeWithShellPermissions(
+ () -> mWifiManager.setSoftApConfiguration(mOriginalSoftApConfig));
+ Thread.sleep(TEST_WAIT_DURATION_MS);
super.tearDown();
}
@@ -355,7 +434,7 @@
+ " empty when location is disabled!");
}
setWifiEnabled(false);
- Thread.sleep(DURATION);
+ Thread.sleep(TEST_WAIT_DURATION_MS);
startScan();
if (mWifiManager.isScanAlwaysAvailable() && isScanCurrentlyAvailable()) {
// Make sure at least one AP is found.
@@ -506,6 +585,140 @@
}
}
+ public class TestSoftApCallback implements WifiManager.SoftApCallback {
+ Object softApLock;
+ int currentState;
+ int currentFailureReason;
+ List<WifiClient> currentClientList;
+ SoftApInfo currentSoftApInfo;
+ SoftApCapability currentSoftApCapability;
+ MacAddress lastBlockedClientMacAddress;
+ int lastBlockedClientReason;
+ boolean onStateChangedCalled = false;
+ boolean onSoftapInfoChangedCalled = false;
+ boolean onSoftApCapabilityChangedCalled = false;
+ boolean onConnectedClientCalled = false;
+ boolean onBlockedClientConnectingCalled = false;
+
+ TestSoftApCallback(Object lock) {
+ softApLock = lock;
+ }
+
+ public boolean getOnStateChangedCalled() {
+ synchronized(softApLock) {
+ return onStateChangedCalled;
+ }
+ }
+
+ public boolean getOnSoftapInfoChangedCalled() {
+ synchronized(softApLock) {
+ return onSoftapInfoChangedCalled;
+ }
+ }
+
+ public boolean getOnSoftApCapabilityChangedCalled() {
+ synchronized(softApLock) {
+ return onSoftApCapabilityChangedCalled;
+ }
+ }
+
+ public boolean getOnConnectedClientCalled() {
+ synchronized(softApLock) {
+ return onConnectedClientCalled;
+ }
+ }
+
+ public boolean getOnBlockedClientConnectingCalled() {
+ synchronized(softApLock) {
+ return onBlockedClientConnectingCalled;
+ }
+ }
+
+ public int getCurrentState() {
+ synchronized(softApLock) {
+ return currentState;
+ }
+ }
+
+ public int getCurrentStateFailureReason() {
+ synchronized(softApLock) {
+ return currentFailureReason;
+ }
+ }
+
+ public List<WifiClient> getCurrentClientList() {
+ synchronized(softApLock) {
+ return currentClientList;
+ }
+ }
+
+ public SoftApInfo getCurrentSoftApInfo() {
+ synchronized(softApLock) {
+ return currentSoftApInfo;
+ }
+ }
+
+ public SoftApCapability getCurrentSoftApCapability() {
+ synchronized(softApLock) {
+ return currentSoftApCapability;
+ }
+ }
+
+ public MacAddress getLastBlockedClientMacAddress() {
+ synchronized(softApLock) {
+ return lastBlockedClientMacAddress;
+ }
+ }
+
+ public int getLastBlockedClientReason() {
+ synchronized(softApLock) {
+ return lastBlockedClientReason;
+ }
+ }
+
+ @Override
+ public void onStateChanged(int state, int failureReason) {
+ synchronized(softApLock) {
+ currentState = state;
+ currentFailureReason = failureReason;
+ onStateChangedCalled = true;
+ }
+ }
+
+ @Override
+ public void onConnectedClientsChanged(List<WifiClient> clients) {
+ synchronized(softApLock) {
+ currentClientList = new ArrayList<>(clients);
+ onConnectedClientCalled = true;
+ }
+ }
+
+ @Override
+ public void onInfoChanged(SoftApInfo softApInfo) {
+ synchronized(softApLock) {
+ currentSoftApInfo = softApInfo;
+ onSoftapInfoChangedCalled = true;
+ }
+ }
+
+ @Override
+ public void onCapabilityChanged(SoftApCapability softApCapability) {
+ synchronized(softApLock) {
+ currentSoftApCapability = softApCapability;
+ onSoftApCapabilityChangedCalled = true;
+ }
+ }
+
+ @Override
+ public void onBlockedClientConnecting(WifiClient client, int blockedReason) {
+ synchronized(softApLock) {
+ lastBlockedClientMacAddress = client.getMacAddress();
+ lastBlockedClientReason = blockedReason;
+ onBlockedClientConnectingCalled = true;
+ }
+ }
+ }
+
private static class TestLocalOnlyHotspotCallback extends WifiManager.LocalOnlyHotspotCallback {
Object hotspotLock;
WifiManager.LocalOnlyHotspotReservation reservation = null;
@@ -556,12 +769,15 @@
try {
mWifiManager.startLocalOnlyHotspot(callback, null);
// now wait for callback
- mLock.wait(DURATION);
+ mLock.wait(TEST_WAIT_DURATION_MS);
} catch (InterruptedException e) {
}
// check if we got the callback
assertTrue(callback.onStartedCalled);
- assertNotNull(callback.reservation.getSoftApConfiguration());
+
+ SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration();
+ assertNotNull(softApConfig);
+ assertNotNull(softApConfig.toWifiConfiguration());
if (!hasAutomotiveFeature()) {
assertEquals(
SoftApConfiguration.BAND_2GHZ,
@@ -647,7 +863,7 @@
boolean wifiEnabled = mWifiManager.isWifiEnabled();
// now we should fail to toggle wifi state.
assertFalse(mWifiManager.setWifiEnabled(!wifiEnabled));
- Thread.sleep(DURATION);
+ Thread.sleep(TEST_WAIT_DURATION_MS);
assertEquals(wifiEnabled, mWifiManager.isWifiEnabled());
}
@@ -1055,8 +1271,12 @@
Thread.sleep(DURATION_SCREEN_TOGGLE);
}
- private void turnScreenOff() throws Exception {
+ private void turnScreenOffNoDelay() throws Exception {
mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP");
+ }
+
+ private void turnScreenOff() throws Exception {
+ turnScreenOffNoDelay();
// Since the screen on/off intent is ordered, they will not be sent right now.
Thread.sleep(DURATION_SCREEN_TOGGLE);
}
@@ -1067,6 +1287,23 @@
}
}
+ private void runWithScanningEnabled(ThrowingRunnable r) throws Exception {
+ boolean wasScanEnabledForTest = false;
+ if (!mWifiManager.isScanAlwaysAvailable()) {
+ ShellIdentityUtils.invokeWithShellPermissions(
+ () -> mWifiManager.setScanAlwaysAvailable(true));
+ wasScanEnabledForTest = true;
+ }
+ try {
+ r.run();
+ } finally {
+ if (wasScanEnabledForTest) {
+ ShellIdentityUtils.invokeWithShellPermissions(
+ () -> mWifiManager.setScanAlwaysAvailable(false));
+ }
+ }
+ }
+
/**
* Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is disabled
* but location is on.
@@ -1085,17 +1322,16 @@
fail("Please enable location for this test - since Marshmallow WiFi scan results are"
+ " empty when location is disabled!");
}
- if(!mWifiManager.isScanAlwaysAvailable()) {
- fail("Please enable Wi-Fi scanning for this test!");
- }
- setWifiEnabled(false);
- turnScreenOn();
- assertWifiScanningIsOn();
- // Toggle screen and verify Wi-Fi scanning is still on.
- turnScreenOff();
- assertWifiScanningIsOn();
- turnScreenOn();
- assertWifiScanningIsOn();
+ runWithScanningEnabled(() -> {
+ setWifiEnabled(false);
+ turnScreenOn();
+ assertWifiScanningIsOn();
+ // Toggle screen and verify Wi-Fi scanning is still on.
+ turnScreenOff();
+ assertWifiScanningIsOn();
+ turnScreenOn();
+ assertWifiScanningIsOn();
+ });
}
/**
@@ -1115,17 +1351,16 @@
fail("Please enable location for this test - since Marshmallow WiFi scan results are"
+ " empty when location is disabled!");
}
- if(!mWifiManager.isScanAlwaysAvailable()) {
- fail("Please enable Wi-Fi scanning for this test!");
- }
- setWifiEnabled(true);
- turnScreenOn();
- assertWifiScanningIsOn();
- // Toggle screen and verify Wi-Fi scanning is still on.
- turnScreenOff();
- assertWifiScanningIsOn();
- turnScreenOn();
- assertWifiScanningIsOn();
+ runWithScanningEnabled(() -> {
+ setWifiEnabled(true);
+ turnScreenOn();
+ assertWifiScanningIsOn();
+ // Toggle screen and verify Wi-Fi scanning is still on.
+ turnScreenOff();
+ assertWifiScanningIsOn();
+ turnScreenOn();
+ assertWifiScanningIsOn();
+ });
}
/**
@@ -1141,6 +1376,178 @@
> ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP);
}
+ private void verifyRegisterSoftApCallback(TestExecutor executor, TestSoftApCallback callback)
+ throws Exception{
+ // Register callback to get SoftApCapability
+ mWifiManager.registerSoftApCallback(executor, callback);
+ PollingCheck.check(
+ "SoftAp register failed!", 1_000,
+ () -> { executor.runAll();
+ // Verify callback is run on the supplied executor and called
+ return callback.getOnStateChangedCalled() &&
+ callback.getOnSoftapInfoChangedCalled() &&
+ callback.getOnSoftApCapabilityChangedCalled() &&
+ callback.getOnConnectedClientCalled();
+ });
+ }
+
+ private void verifySetGetSoftApConfig(SoftApConfiguration targetConfig) {
+ mWifiManager.setSoftApConfiguration(targetConfig);
+ // Bssid set dodesn't support for tethered hotspot
+ SoftApConfiguration currentConfig = mWifiManager.getSoftApConfiguration();
+ assertNull(currentConfig.getBssid());
+ compareSoftApConfiguration(targetConfig, currentConfig);
+ }
+
+ private void compareSoftApConfiguration(SoftApConfiguration currentConfig,
+ SoftApConfiguration testSoftApConfig) {
+ assertEquals(currentConfig.getSsid(), testSoftApConfig.getSsid());
+ assertEquals(currentConfig.getSecurityType(), testSoftApConfig.getSecurityType());
+ assertEquals(currentConfig.getPassphrase(), testSoftApConfig.getPassphrase());
+ assertEquals(currentConfig.isHiddenSsid(), testSoftApConfig.isHiddenSsid());
+ assertEquals(currentConfig.getBand(), testSoftApConfig.getBand());
+ assertEquals(currentConfig.getChannel(), testSoftApConfig.getChannel());
+ assertEquals(currentConfig.getMaxNumberOfClients(),
+ testSoftApConfig.getMaxNumberOfClients());
+ assertEquals(currentConfig.isAutoShutdownEnabled(),
+ testSoftApConfig.isAutoShutdownEnabled());
+ assertEquals(currentConfig.getShutdownTimeoutMillis(),
+ testSoftApConfig.getShutdownTimeoutMillis());
+ assertEquals(currentConfig.isClientControlByUserEnabled(),
+ testSoftApConfig.isClientControlByUserEnabled());
+ assertEquals(currentConfig.getAllowedClientList(),
+ testSoftApConfig.getAllowedClientList());
+ assertEquals(currentConfig.getBlockedClientList(),
+ testSoftApConfig.getBlockedClientList());
+ }
+
+ private void turnOffWifiAndTetheredHotspotIfEnabled() throws Exception {
+ if (mWifiManager.isWifiEnabled()) {
+ Log.d(TAG, "Turn off WiFi");
+ mWifiManager.setWifiEnabled(false);
+ PollingCheck.check(
+ "Wifi turn off failed!", 2_000,
+ () -> mWifiManager.isWifiEnabled() == false);
+ }
+ if (mWifiManager.isWifiApEnabled()) {
+ mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
+ Log.d(TAG, "Turn off tethered Hotspot");
+ PollingCheck.check(
+ "SoftAp turn off failed!", 2_000,
+ () -> mWifiManager.isWifiApEnabled() == false);
+ mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
+ }
+ }
+
+ /**
+ * Verify that the configuration from getSoftApConfiguration is same as the configuration which
+ * set by setSoftApConfiguration. And depends softap capability callback to test different
+ * configuration.
+ * @throws Exception
+ */
+ public void testSetGetSoftApConfigurationAndSoftApCapabilityCallback() throws Exception {
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ try {
+ uiAutomation.adoptShellPermissionIdentity();
+ turnOffWifiAndTetheredHotspotIfEnabled();
+ TestExecutor executor = new TestExecutor();
+ TestSoftApCallback callback = new TestSoftApCallback(mLock);
+ verifyRegisterSoftApCallback(executor, callback);
+
+ SoftApConfiguration.Builder softApConfigBuilder = new SoftApConfiguration.Builder()
+ .setSsid(TEST_SSID_UNQUOTED)
+ .setBssid(TEST_MAC)
+ .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+ .setAutoShutdownEnabled(true)
+ .setShutdownTimeoutMillis(100000)
+ .setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ)
+ .setHiddenSsid(false);
+
+ // Test SoftApConfiguration set and get
+ verifySetGetSoftApConfig(softApConfigBuilder.build());
+
+ // Test CLIENT_FORCE_DISCONNECT supported config.
+ if (callback.getCurrentSoftApCapability()
+ .areFeaturesSupported(
+ SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT)) {
+ softApConfigBuilder.setMaxNumberOfClients(10);
+ softApConfigBuilder.setClientControlByUserEnabled(true);
+ softApConfigBuilder.setBlockedClientList(new ArrayList<>());
+ softApConfigBuilder.setAllowedClientList(new ArrayList<>());
+ verifySetGetSoftApConfig(softApConfigBuilder.build());
+ }
+
+ // Test SAE config
+ if (callback.getCurrentSoftApCapability()
+ .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_WPA3_SAE)) {
+ softApConfigBuilder
+ .setPassphrase(TEST_PASSPHRASE,
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
+ verifySetGetSoftApConfig(softApConfigBuilder.build());
+ softApConfigBuilder
+ .setPassphrase(TEST_PASSPHRASE,
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
+ verifySetGetSoftApConfig(softApConfigBuilder.build());
+ }
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
+ * Verify that startTetheredHotspot with specific channel config.
+ * @throws Exception
+ */
+ public void testStartTetheredHotspotWithChannelConfigAndSoftApStateAndInfoCallback()
+ throws Exception {
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ try {
+ uiAutomation.adoptShellPermissionIdentity();
+ turnOffWifiAndTetheredHotspotIfEnabled();
+ TestExecutor executor = new TestExecutor();
+ TestSoftApCallback callback = new TestSoftApCallback(mLock);
+ verifyRegisterSoftApCallback(executor, callback);
+
+ SoftApConfiguration testSoftApConfig = new SoftApConfiguration.Builder()
+ .setSsid(TEST_SSID_UNQUOTED)
+ .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+ .setChannel(11, SoftApConfiguration.BAND_2GHZ) // Channel 11 = Freq 2462
+ .build();
+
+ mWifiManager.setSoftApConfiguration(testSoftApConfig);
+
+ // start tethering which used to verify startTetheredHotspot
+ mTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor,
+ new TetheringManager.StartTetheringCallback() {
+ @Override
+ public void onTetheringFailed(final int result) {
+ }
+ });
+
+ // Verify state and info callback value as expected
+ PollingCheck.check(
+ "SoftAp channel and state mismatch!!!", 5_000,
+ () -> { executor.runAll();
+ return WifiManager.WIFI_AP_STATE_ENABLED == callback.getCurrentState() &&
+ 2462 == callback.getCurrentSoftApInfo().getFrequency();
+ });
+
+ // stop tethering which used to verify stopSoftAp
+ mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
+
+ // Verify clean up
+ PollingCheck.check(
+ "Stop Softap failed", 2_000,
+ () -> { executor.runAll();
+ return WifiManager.WIFI_AP_STATE_DISABLED == callback.getCurrentState() &&
+ 0 == callback.getCurrentSoftApInfo().getBandwidth() &&
+ 0 == callback.getCurrentSoftApInfo().getFrequency();
+ });
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
private static class TestActionListener implements WifiManager.ActionListener {
private final Object mLock;
public boolean onSuccessCalled = false;
@@ -1203,7 +1610,7 @@
mWifiManager.connect(savedNetworks.get(0), actionListener);
}
// now wait for callback
- mLock.wait(DURATION);
+ mLock.wait(TEST_WAIT_DURATION_MS);
} catch (InterruptedException e) {
}
}
@@ -1282,7 +1689,7 @@
.build(),
networkCallbackListener);
// now wait for callback
- mLock.wait(DURATION);
+ mLock.wait(TEST_WAIT_DURATION_MS);
} catch (InterruptedException e) {
}
}
@@ -1330,7 +1737,7 @@
modSavedNetwork.meteredOverride = WifiConfiguration.METERED_OVERRIDE_METERED;
mWifiManager.save(modSavedNetwork, actionListener);
// now wait for callback
- mLock.wait(DURATION);
+ mLock.wait(TEST_WAIT_DURATION_MS);
} catch (InterruptedException e) {
}
}
@@ -1378,7 +1785,7 @@
try {
mWifiManager.forget(newNetworkId, actionListener);
// now wait for callback
- mLock.wait(DURATION);
+ mLock.wait(TEST_WAIT_DURATION_MS);
} catch (InterruptedException e) {
}
}
@@ -1455,13 +1862,107 @@
mWifiManager.isPreferredNetworkOffloadSupported();
}
+ /** Test that PNO scans reconnects us when the device is disconnected and the screen is off. */
+ public void testPnoScan() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ if (!mWifiManager.isPreferredNetworkOffloadSupported()) {
+ // skip the test if PNO scanning is not supported
+ return;
+ }
+
+ // make sure we're connected
+ waitForConnection();
+
+ WifiInfo currentNetwork = ShellIdentityUtils.invokeWithShellPermissions(
+ mWifiManager::getConnectionInfo);
+
+ // disable all networks that aren't already disabled
+ List<WifiConfiguration> savedNetworks = ShellIdentityUtils.invokeWithShellPermissions(
+ mWifiManager::getConfiguredNetworks);
+ Set<Integer> disabledNetworkIds = new HashSet<>();
+ for (WifiConfiguration config : savedNetworks) {
+ if (config.getNetworkSelectionStatus().getNetworkSelectionDisableReason()
+ == WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE) {
+ ShellIdentityUtils.invokeWithShellPermissions(
+ () -> mWifiManager.disableNetwork(config.networkId));
+ disabledNetworkIds.add(config.networkId);
+ }
+ }
+
+ try {
+ // wait for disconnection from current network
+ waitForDisconnection();
+
+ // turn screen off
+ turnScreenOffNoDelay();
+
+ // re-enable the current network - this will trigger PNO
+ ShellIdentityUtils.invokeWithShellPermissions(
+ () -> mWifiManager.enableNetwork(currentNetwork.getNetworkId(), false));
+ disabledNetworkIds.remove(currentNetwork.getNetworkId());
+
+ // PNO should reconnect us back to the network we disconnected from
+ waitForConnection();
+ } finally {
+ // re-enable disabled networks
+ for (int disabledNetworkId : disabledNetworkIds) {
+ ShellIdentityUtils.invokeWithShellPermissions(
+ () -> mWifiManager.enableNetwork(disabledNetworkId, false));
+ }
+ }
+ }
+
+ /**
+ * Tests {@link WifiManager#isTdlsSupported()} does not crash.
+ */
+ public void testIsTdlsSupported() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ mWifiManager.isTdlsSupported();
+ }
+
+ /**
+ * Tests {@link WifiManager#isStaApConcurrencySupported().
+ */
+ public void testIsStaApConcurrencySupported() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ // check that softap mode is supported by the device
+ if (!mWifiManager.isPortableHotspotSupported()) {
+ return;
+ }
+ assertTrue(mWifiManager.isWifiEnabled());
+
+ boolean isStaApConcurrencySupported = mWifiManager.isStaApConcurrencySupported();
+ // start local only hotspot.
+ TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
+ if (isStaApConcurrencySupported) {
+ assertTrue(mWifiManager.isWifiEnabled());
+ } else {
+ // no concurrency, wifi should be disabled.
+ assertFalse(mWifiManager.isWifiEnabled());
+ }
+ stopLocalOnlyHotspot(callback, true);
+
+ assertTrue(mWifiManager.isWifiEnabled());
+ }
+
private static class TestTrafficStateCallback implements WifiManager.TrafficStateCallback {
private final Object mLock;
+ private final int mWaitForState;
public boolean onStateChangedCalled = false;
public int state = -1;
- TestTrafficStateCallback(Object lock) {
+ TestTrafficStateCallback(Object lock, int waitForState) {
mLock = lock;
+ mWaitForState = waitForState;
}
@Override
@@ -1469,7 +1970,9 @@
synchronized (mLock) {
onStateChangedCalled = true;
this.state = state;
- mLock.notify();
+ if (mWaitForState == state) { // only notify if we got the expected state.
+ mLock.notify();
+ }
}
}
}
@@ -1503,7 +2006,8 @@
// skip the test if WiFi is not supported
return;
}
- TestTrafficStateCallback trafficStateCallback = new TestTrafficStateCallback(mLock);
+ TestTrafficStateCallback trafficStateCallback =
+ new TestTrafficStateCallback(mLock, DATA_ACTIVITY_INOUT);
UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
try {
uiAutomation.adoptShellPermissionIdentity();
@@ -1520,7 +2024,7 @@
// Send some traffic to trigger the traffic state change callbacks.
sendTraffic();
// now wait for callback
- mLock.wait(DURATION);
+ mLock.wait(TEST_WAIT_DURATION_MS);
} catch (InterruptedException e) {
}
}
@@ -1743,7 +2247,7 @@
.build(),
networkCallbackListener);
// now wait for callback
- mLock.wait(DURATION);
+ mLock.wait(TEST_WAIT_DURATION_MS);
} catch (InterruptedException e) {
}
}
@@ -1759,4 +2263,252 @@
assertNull(ShellIdentityUtils.invokeWithShellPermissions(mWifiManager::getCurrentNetwork));
}
+
+ /**
+ * Tests {@link WifiManager#isWpa3SaeSupported()} does not crash.
+ */
+ public void testIsWpa3SaeSupported() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ mWifiManager.isWpa3SaeSupported();
+ }
+
+ /**
+ * Tests {@link WifiManager#isWpa3SuiteBSupported()} does not crash.
+ */
+ public void testIsWpa3SuiteBSupported() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ mWifiManager.isWpa3SuiteBSupported();
+ }
+
+ /**
+ * Tests {@link WifiManager#isEnhancedOpenSupported()} does not crash.
+ */
+ public void testIsEnhancedOpenSupported() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ mWifiManager.isEnhancedOpenSupported();
+ }
+
+ /**
+ * Test that {@link WifiManager#is5GHzBandSupported()} returns successfully in
+ * both WiFi enabled/disabled states.
+ * Note that the response depends on device support and hence both true/false
+ * are valid responses.
+ */
+ public void testIs5GhzBandSupported() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+
+ // Check for 5GHz support with wifi enabled
+ setWifiEnabled(true);
+ PollingCheck.check(
+ "Wifi not enabled!",
+ 20000,
+ () -> mWifiManager.isWifiEnabled());
+ boolean isSupportedEnabled = mWifiManager.is5GHzBandSupported();
+
+ // Check for 5GHz support with wifi disabled
+ setWifiEnabled(false);
+ PollingCheck.check(
+ "Wifi not disabled!",
+ 20000,
+ () -> !mWifiManager.isWifiEnabled());
+ boolean isSupportedDisabled = mWifiManager.is5GHzBandSupported();
+
+ // If Support is true when WiFi is disable, then it has to be true when it is enabled.
+ // Note, the reverse is a valid case.
+ if (isSupportedDisabled) {
+ assertTrue(isSupportedEnabled);
+ }
+ }
+
+ /**
+ * Test that {@link WifiManager#is6GHzBandSupported()} returns successfully in
+ * both Wifi enabled/disabled states.
+ * Note that the response depends on device support and hence both true/false
+ * are valid responses.
+ */
+ public void testIs6GhzBandSupported() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+
+ // Check for 6GHz support with wifi enabled
+ setWifiEnabled(true);
+ PollingCheck.check(
+ "Wifi not enabled!",
+ 20000,
+ () -> mWifiManager.isWifiEnabled());
+ boolean isSupportedEnabled = mWifiManager.is6GHzBandSupported();
+
+ // Check for 6GHz support with wifi disabled
+ setWifiEnabled(false);
+ PollingCheck.check(
+ "Wifi not disabled!",
+ 20000,
+ () -> !mWifiManager.isWifiEnabled());
+ boolean isSupportedDisabled = mWifiManager.is6GHzBandSupported();
+
+ // If Support is true when WiFi is disable, then it has to be true when it is enabled.
+ // Note, the reverse is a valid case.
+ if (isSupportedDisabled) {
+ assertTrue(isSupportedEnabled);
+ }
+ }
+
+ /**
+ * Test that {@link WifiManager#isWifiStandardSupported()} returns successfully in
+ * both Wifi enabled/disabled states. The test is to be performed on
+ * {@link WifiAnnotations}'s {@code WIFI_STANDARD_}
+ * Note that the response depends on device support and hence both true/false
+ * are valid responses.
+ */
+ public void testIsWifiStandardsSupported() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+
+ // Check for WiFi standards support with wifi enabled
+ setWifiEnabled(true);
+ PollingCheck.check(
+ "Wifi not enabled!",
+ 20000,
+ () -> mWifiManager.isWifiEnabled());
+ boolean isLegacySupportedEnabled =
+ mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY);
+ boolean is11nSupporedEnabled =
+ mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N);
+ boolean is11acSupportedEnabled =
+ mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC);
+ boolean is11axSupportedEnabled =
+ mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX);
+
+ // Check for WiFi standards support with wifi disabled
+ setWifiEnabled(false);
+ PollingCheck.check(
+ "Wifi not disabled!",
+ 20000,
+ () -> !mWifiManager.isWifiEnabled());
+
+ boolean isLegacySupportedDisabled =
+ mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY);
+ boolean is11nSupportedDisabled =
+ mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N);
+ boolean is11acSupportedDisabled =
+ mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC);
+ boolean is11axSupportedDisabled =
+ mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX);
+
+ if (isLegacySupportedDisabled) {
+ assertTrue(isLegacySupportedEnabled);
+ }
+
+ if (is11nSupportedDisabled) {
+ assertTrue(is11nSupporedEnabled);
+ }
+
+ if (is11acSupportedDisabled) {
+ assertTrue(is11acSupportedEnabled);
+ }
+
+ if (is11axSupportedDisabled) {
+ assertTrue(is11axSupportedEnabled);
+ }
+ }
+
+ private static PasspointConfiguration createPasspointConfiguration() {
+ PasspointConfiguration config = new PasspointConfiguration();
+ HomeSp homeSp = new HomeSp();
+ homeSp.setFqdn("test.com");
+ homeSp.setFriendlyName("friendly name");
+ homeSp.setRoamingConsortiumOis(new long[]{0x55, 0x66});
+ config.setHomeSp(homeSp);
+ Credential.SimCredential simCred = new Credential.SimCredential();
+ simCred.setImsi("123456*");
+ simCred.setEapType(23 /* EAP_AKA */);
+ Credential cred = new Credential();
+ cred.setRealm("realm");
+ cred.setSimCredential(simCred);
+ config.setCredential(cred);
+
+ return config;
+ }
+
+ /**
+ * Tests {@link WifiManager#addOrUpdatePasspointConfiguration(PasspointConfiguration)}
+ * adds a Passpoint configuration correctly by getting it once it is added, and comparing it
+ * to the local copy of the configuration.
+ */
+ public void testAddOrUpdatePasspointConfiguration() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+
+ // Create and install a Passpoint configuration
+ PasspointConfiguration passpointConfiguration = createPasspointConfiguration();
+ mWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration);
+
+ // Compare configurations
+ List<PasspointConfiguration> configurations = mWifiManager.getPasspointConfigurations();
+ assertNotNull(configurations);
+ assertEquals(passpointConfiguration, configurations.get(0));
+
+ // Clean up
+ mWifiManager.removePasspointConfiguration(passpointConfiguration.getHomeSp().getFqdn());
+ }
+
+ /**
+ * Tests that
+ * {@link WifiManager#startSubscriptionProvisioning(OsuProvider, Executor, ProvisioningCallback)}
+ * starts a subscription provisioning, and confirm a status callback invoked once.
+ */
+ public void testStartSubscriptionProvisioning() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+
+ // Using Java reflection to construct an OsuProvider instance because its constructor is
+ // hidden and not available to apps.
+ Class<?> osuProviderClass = Class.forName("android.net.wifi.hotspot2.OsuProvider");
+ Constructor<?> osuProviderClassConstructor = osuProviderClass.getConstructor(String.class,
+ Map.class, String.class, Uri.class, String.class, List.class);
+
+ OsuProvider osuProvider = (OsuProvider) osuProviderClassConstructor.newInstance(TEST_SSID,
+ TEST_FRIENDLY_NAMES, TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI,
+ TEST_METHOD_LIST);
+
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ try {
+ uiAutomation.adoptShellPermissionIdentity();
+ synchronized (mLock) {
+ // Start a subscription provisioning for a non-existent Passpoint R2 AP
+ mWifiManager.startSubscriptionProvisioning(osuProvider, mExecutor,
+ mProvisioningCallback);
+ mLock.wait(TEST_WAIT_DURATION_MS);
+ }
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
+
+ // Expect only a single callback event, connecting. Since AP doesn't exist, it ends here
+ assertEquals(ProvisioningCallback.OSU_STATUS_AP_CONNECTING, mProvisioningStatus);
+ // No failure callbacks expected
+ assertEquals(0, mProvisioningFailureStatus);
+ // No completion callback expected
+ assertFalse(mProvisioningComplete);
+ }
}
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiMigrationTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiMigrationTest.java
index 6e19a21..7d94ad3 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiMigrationTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiMigrationTest.java
@@ -16,16 +16,9 @@
package android.net.wifi.cts;
-import static org.junit.Assert.assertNotNull;
-
-import android.net.wifi.SoftApConfiguration;
-import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiMigration;
import android.test.AndroidTestCase;
-import java.util.Arrays;
-import java.util.List;
-
public class WifiMigrationTest extends AndroidTestCase {
private static final String TEST_SSID_UNQUOTED = "testSsid1";
@@ -49,42 +42,7 @@
}
/**
- * Tests {@link android.net.wifi.WifiMigration.ConfigStoreMigrationData} class.
- */
- public void testWifiMigrationConfigStoreDataBuilder() throws Exception {
- if (!WifiFeature.isWifiSupported(getContext())) {
- // skip the test if WiFi is not supported
- return;
- }
- WifiConfiguration savedNetwork1 = new WifiConfiguration();
- savedNetwork1.SSID = "\"test1\"";
- WifiConfiguration savedNetwork2 = new WifiConfiguration();
- savedNetwork1.SSID = "\"test2\"";
- List<WifiConfiguration> savedNetworks = Arrays.asList(savedNetwork1, savedNetwork2);
-
- SoftApConfiguration softApConfiguration = new SoftApConfiguration.Builder()
- .setSsid("\"test3\"")
- .build();
-
- WifiMigration.ConfigStoreMigrationData migrationData =
- new WifiMigration.ConfigStoreMigrationData.Builder()
- .setUserSavedNetworkConfigurations(savedNetworks)
- .setUserSoftApConfiguration(softApConfiguration)
- .build();
-
- assertNotNull(migrationData);
- assertEquals(savedNetworks.size(),
- migrationData.getUserSavedNetworkConfigurations().size());
- assertEquals(savedNetwork1.SSID,
- migrationData.getUserSavedNetworkConfigurations().get(0).SSID);
- assertEquals(savedNetwork2.SSID,
- migrationData.getUserSavedNetworkConfigurations().get(1).SSID);
- assertEquals(softApConfiguration.getSsid(),
- migrationData.getUserSoftApConfiguration().getSsid());
- }
-
- /**
- * Tests {@link android.net.wifi.WifiMigration.ConfigStoreMigrationData} class.
+ * Tests {@link android.net.wifi.WifiMigration.SettingsMigrationData.Builder} class.
*/
public void testWifiMigrationSettingsDataBuilder() throws Exception {
if (!WifiFeature.isWifiSupported(getContext())) {
@@ -111,4 +69,15 @@
assertTrue(migrationData.isVerboseLoggingEnabled());
assertEquals(TEST_SSID_UNQUOTED, migrationData.getP2pDeviceName());
}
+
+ /**
+ * Tests {@link android.net.wifi.WifiMigration.SettingsMigrationData} class.
+ */
+ public void testWifiMigrationSettings() throws Exception {
+ try {
+ // ensure that this does not crash.
+ WifiMigration.loadFromSettings(getContext());
+ } catch (Exception ignore) {
+ }
+ }
}
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java
index 96cf45f..2065bb0 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java
@@ -31,6 +31,7 @@
import android.net.NetworkRequest;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiEnterpriseConfig;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.NetworkRequestMatchCallback;
@@ -506,4 +507,44 @@
.build();
testUserRejectionWithSpecifier(specifier);
}
+
+ /**
+ * Tests the builder for WPA2 enterprise networks.
+ * Note: Can't do end to end tests for such networks in CTS environment.
+ */
+ public void testBuilderForWpa2Enterprise() {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ WifiNetworkSpecifier specifier1 = new WifiNetworkSpecifier.Builder()
+ .setSsid(WifiInfo.sanitizeSsid(mTestNetwork.SSID))
+ .setWpa2EnterpriseConfig(new WifiEnterpriseConfig())
+ .build();
+ WifiNetworkSpecifier specifier2 = new WifiNetworkSpecifier.Builder()
+ .setSsid(WifiInfo.sanitizeSsid(mTestNetwork.SSID))
+ .setWpa2EnterpriseConfig(new WifiEnterpriseConfig())
+ .build();
+ assertThat(specifier1.satisfiedBy(specifier2)).isTrue();
+ }
+
+ /**
+ * Tests the builder for WPA3 enterprise networks.
+ * Note: Can't do end to end tests for such networks in CTS environment.
+ */
+ public void testBuilderForWpa3Enterprise() {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ WifiNetworkSpecifier specifier1 = new WifiNetworkSpecifier.Builder()
+ .setSsid(WifiInfo.sanitizeSsid(mTestNetwork.SSID))
+ .setWpa3EnterpriseConfig(new WifiEnterpriseConfig())
+ .build();
+ WifiNetworkSpecifier specifier2 = new WifiNetworkSpecifier.Builder()
+ .setSsid(WifiInfo.sanitizeSsid(mTestNetwork.SSID))
+ .setWpa3EnterpriseConfig(new WifiEnterpriseConfig())
+ .build();
+ assertThat(specifier1.satisfiedBy(specifier2)).isTrue();
+ }
}
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java
index 994b6c9..e73abb8 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiNetworkSuggestionTest.java
@@ -17,6 +17,7 @@
package android.net.wifi.cts;
import static android.net.wifi.WifiEnterpriseConfig.Eap.AKA;
+import static android.net.wifi.WifiEnterpriseConfig.Eap.WAPI_CERT;
import android.net.MacAddress;
import android.net.wifi.WifiEnterpriseConfig;
@@ -199,6 +200,28 @@
}
/**
+ * Tests {@link android.net.wifi.WifiNetworkSuggestion.Builder} class.
+ */
+ public void testBuilderWithWapiEnterprise() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ enterpriseConfig.setEapMethod(WAPI_CERT);
+ WifiNetworkSuggestion suggestion =
+ createBuilderWithCommonParams()
+ .setWapiEnterpriseConfig(enterpriseConfig)
+ .build();
+ validateCommonParams(suggestion);
+ assertNull(suggestion.getPassphrase());
+ assertNotNull(suggestion.getEnterpriseConfig());
+ assertEquals(enterpriseConfig.getEapMethod(),
+ suggestion.getEnterpriseConfig().getEapMethod());
+ assertNull(suggestion.getPasspointConfig());
+ }
+
+ /**
* Helper function for creating a {@link PasspointConfiguration} for testing.
*
* @return {@link PasspointConfiguration}
diff --git a/tests/tests/net/src/android/net/wifi/nl80211/cts/DeviceWiphyCapabilitiesTest.java b/tests/tests/net/src/android/net/wifi/nl80211/cts/DeviceWiphyCapabilitiesTest.java
new file mode 100644
index 0000000..d8f5e57
--- /dev/null
+++ b/tests/tests/net/src/android/net/wifi/nl80211/cts/DeviceWiphyCapabilitiesTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2020 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.net.wifi.nl80211.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.net.wifi.ScanResult;
+import android.net.wifi.cts.WifiFeature;
+import android.net.wifi.nl80211.DeviceWiphyCapabilities;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** CTS tests for {@link DeviceWiphyCapabilities}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DeviceWiphyCapabilitiesTest {
+
+ @Before
+ public void setUp() {
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ // skip tests if Wifi is not supported
+ assumeTrue(WifiFeature.isWifiSupported(context));
+ }
+
+ /**
+ * Test that a {@link DeviceWiphyCapabilities} object can be serialized and deserialized,
+ * while keeping its values unchanged.
+ */
+ @Test
+ public void canSerializeAndDeserialize() {
+ DeviceWiphyCapabilities capa = new DeviceWiphyCapabilities();
+
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, true);
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, true);
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AX, false);
+
+ Parcel parcel = Parcel.obtain();
+ capa.writeToParcel(parcel, 0);
+ // Rewind the pointer to the head of the parcel.
+ parcel.setDataPosition(0);
+ DeviceWiphyCapabilities capaDeserialized =
+ DeviceWiphyCapabilities.CREATOR.createFromParcel(parcel);
+
+ assertThat(capaDeserialized.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N)).isTrue();
+ assertThat(capaDeserialized.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC))
+ .isTrue();
+ assertThat(capaDeserialized.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX))
+ .isFalse();
+ assertThat(capaDeserialized).isEqualTo(capa);
+ assertThat(capaDeserialized.hashCode()).isEqualTo(capa.hashCode());
+ }
+
+ /** Test mapping wifi standard support into channel width support */
+ @Test
+ public void testMappingWifiStandardIntoChannelWidthSupport() {
+ DeviceWiphyCapabilities capa = new DeviceWiphyCapabilities();
+
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, false);
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, false);
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AX, false);
+ assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_20MHZ)).isTrue();
+ assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ)).isFalse();
+ assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ)).isFalse();
+
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, true);
+ assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_20MHZ)).isTrue();
+ assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ)).isTrue();
+ assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ)).isFalse();
+
+ capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, true);
+ assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_20MHZ)).isTrue();
+ assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ)).isTrue();
+ assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ)).isTrue();
+ }
+}
diff --git a/tests/tests/net/src/android/net/wifi/nl80211/cts/NativeWifiClientTest.java b/tests/tests/net/src/android/net/wifi/nl80211/cts/NativeWifiClientTest.java
new file mode 100644
index 0000000..3149b54
--- /dev/null
+++ b/tests/tests/net/src/android/net/wifi/nl80211/cts/NativeWifiClientTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2020 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.net.wifi.nl80211.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.net.MacAddress;
+import android.net.wifi.cts.WifiFeature;
+import android.net.wifi.nl80211.NativeWifiClient;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** CTS tests for {@link NativeWifiClient}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NativeWifiClientTest {
+
+ private static final byte[] TEST_MAC = { 1, 2, 3, 4, 5, 6 };
+
+ @Before
+ public void setUp() {
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ // skip tests if Wifi is not supported
+ assumeTrue(WifiFeature.isWifiSupported(context));
+ }
+
+ @Test
+ public void testGetters() {
+ NativeWifiClient client = new NativeWifiClient(MacAddress.fromBytes(TEST_MAC));
+
+ assertThat(client.getMacAddress().toByteArray()).isEqualTo(TEST_MAC);
+ }
+
+ @Test
+ public void canSerializeAndDeserialize() {
+ NativeWifiClient client = new NativeWifiClient(MacAddress.fromBytes(TEST_MAC));
+
+ Parcel parcel = Parcel.obtain();
+ client.writeToParcel(parcel, 0);
+ // Rewind the pointer to the head of the parcel.
+ parcel.setDataPosition(0);
+ NativeWifiClient clientDeserialized = NativeWifiClient.CREATOR.createFromParcel(parcel);
+
+ assertThat(clientDeserialized.getMacAddress().toByteArray()).isEqualTo(TEST_MAC);
+ assertThat(clientDeserialized).isEqualTo(client);
+ assertThat(clientDeserialized.hashCode()).isEqualTo(client.hashCode());
+ }
+
+ @Test
+ public void testEquals() {
+ NativeWifiClient client = new NativeWifiClient(MacAddress.fromBytes(TEST_MAC));
+ NativeWifiClient client2 =
+ new NativeWifiClient(MacAddress.fromBytes(new byte[] { 7, 8, 9, 10, 11, 12 }));
+
+ assertThat(client2).isNotEqualTo(client);
+ }
+}
diff --git a/tests/tests/net/src/android/net/wifi/nl80211/cts/PnoNetworkTest.java b/tests/tests/net/src/android/net/wifi/nl80211/cts/PnoNetworkTest.java
new file mode 100644
index 0000000..f3a8f05
--- /dev/null
+++ b/tests/tests/net/src/android/net/wifi/nl80211/cts/PnoNetworkTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 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.net.wifi.nl80211.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.net.wifi.cts.WifiFeature;
+import android.net.wifi.nl80211.PnoNetwork;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** CTS tests for {@link PnoNetwork}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PnoNetworkTest {
+
+ private static final byte[] TEST_SSID = { 's', 's', 'i', 'd' };
+ private static final int[] TEST_FREQUENCIES = { 2412, 2417, 5035 };
+
+ @Before
+ public void setUp() {
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ // skip tests if Wifi is not supported
+ assumeTrue(WifiFeature.isWifiSupported(context));
+ }
+
+ @Test
+ public void testGetters() {
+ PnoNetwork network = new PnoNetwork();
+ network.setSsid(TEST_SSID);
+ network.setFrequenciesMhz(TEST_FREQUENCIES);
+ network.setHidden(true);
+
+ assertThat(network.getSsid()).isEqualTo(TEST_SSID);
+ assertThat(network.getFrequenciesMhz()).isEqualTo(TEST_FREQUENCIES);
+ assertThat(network.isHidden()).isTrue();
+ }
+
+ @Test
+ public void canSerializeAndDeserialize() {
+ PnoNetwork network = new PnoNetwork();
+ network.setSsid(TEST_SSID);
+ network.setFrequenciesMhz(TEST_FREQUENCIES);
+ network.setHidden(true);
+
+ Parcel parcel = Parcel.obtain();
+ network.writeToParcel(parcel, 0);
+ // Rewind the pointer to the head of the parcel.
+ parcel.setDataPosition(0);
+ PnoNetwork networkDeserialized = PnoNetwork.CREATOR.createFromParcel(parcel);
+
+ assertThat(networkDeserialized.getSsid()).isEqualTo(TEST_SSID);
+ assertThat(networkDeserialized.getFrequenciesMhz()).isEqualTo(TEST_FREQUENCIES);
+ assertThat(networkDeserialized.isHidden()).isTrue();
+ assertThat(networkDeserialized).isEqualTo(network);
+ assertThat(networkDeserialized.hashCode()).isEqualTo(network.hashCode());
+ }
+
+ @Test
+ public void testEquals() {
+ PnoNetwork network = new PnoNetwork();
+ network.setSsid(TEST_SSID);
+ network.setFrequenciesMhz(TEST_FREQUENCIES);
+ network.setHidden(true);
+
+ PnoNetwork network2 = new PnoNetwork();
+ network.setSsid(new byte[] { 'a', 's', 'd', 'f'});
+ network.setFrequenciesMhz(new int[] { 1, 2, 3 });
+ network.setHidden(false);
+
+ assertThat(network2).isNotEqualTo(network);
+ }
+}
diff --git a/tests/tests/net/src/android/net/wifi/nl80211/cts/PnoSettingsTest.java b/tests/tests/net/src/android/net/wifi/nl80211/cts/PnoSettingsTest.java
new file mode 100644
index 0000000..59f5d99
--- /dev/null
+++ b/tests/tests/net/src/android/net/wifi/nl80211/cts/PnoSettingsTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 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.net.wifi.nl80211.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.net.wifi.cts.WifiFeature;
+import android.net.wifi.nl80211.PnoNetwork;
+import android.net.wifi.nl80211.PnoSettings;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.List;
+
+/** CTS tests for {@link PnoSettings}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PnoSettingsTest {
+
+ private static List<PnoNetwork> createTestNetworks() {
+ PnoNetwork network1 = new PnoNetwork();
+ network1.setSsid(new byte[] { 's', 's', 'i', 'd' });
+ network1.setFrequenciesMhz(new int[] { 2412, 2417, 5035 });
+ network1.setHidden(true);
+
+ PnoNetwork network2 = new PnoNetwork();
+ network2.setSsid(new byte[] { 'a', 's', 'd', 'f' });
+ network2.setFrequenciesMhz(new int[] { 2422, 2427, 5040 });
+ network2.setHidden(false);
+
+ return Arrays.asList(network1, network2);
+ }
+
+ @Before
+ public void setUp() {
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ // skip tests if Wifi is not supported
+ assumeTrue(WifiFeature.isWifiSupported(context));
+ }
+
+ @Test
+ public void testGetters() {
+ PnoSettings settings = new PnoSettings();
+ settings.setIntervalMillis(1000);
+ settings.setMin2gRssiDbm(-70);
+ settings.setMin5gRssiDbm(-60);
+ settings.setMin6gRssiDbm(-50);
+ settings.setPnoNetworks(createTestNetworks());
+
+ assertThat(settings.getIntervalMillis()).isEqualTo(1000);
+ assertThat(settings.getMin2gRssiDbm()).isEqualTo(-70);
+ assertThat(settings.getMin5gRssiDbm()).isEqualTo(-60);
+ assertThat(settings.getMin6gRssiDbm()).isEqualTo(-50);
+ assertThat(settings.getPnoNetworks()).isEqualTo(createTestNetworks());
+ }
+
+ @Test
+ public void canSerializeAndDeserialize() {
+ PnoSettings settings = new PnoSettings();
+ settings.setIntervalMillis(1000);
+ settings.setMin2gRssiDbm(-70);
+ settings.setMin5gRssiDbm(-60);
+ settings.setMin6gRssiDbm(-50);
+ settings.setPnoNetworks(createTestNetworks());
+
+ Parcel parcel = Parcel.obtain();
+ settings.writeToParcel(parcel, 0);
+ // Rewind the pointer to the head of the parcel.
+ parcel.setDataPosition(0);
+ PnoSettings settingsDeserialized = PnoSettings.CREATOR.createFromParcel(parcel);
+
+ assertThat(settingsDeserialized.getIntervalMillis()).isEqualTo(1000);
+ assertThat(settingsDeserialized.getMin2gRssiDbm()).isEqualTo(-70);
+ assertThat(settingsDeserialized.getMin5gRssiDbm()).isEqualTo(-60);
+ assertThat(settingsDeserialized.getMin6gRssiDbm()).isEqualTo(-50);
+ assertThat(settingsDeserialized.getPnoNetworks()).isEqualTo(createTestNetworks());
+ assertThat(settingsDeserialized).isEqualTo(settings);
+ assertThat(settingsDeserialized.hashCode()).isEqualTo(settings.hashCode());
+ }
+
+ @Test
+ public void testEquals() {
+ PnoSettings settings = new PnoSettings();
+ settings.setIntervalMillis(1000);
+ settings.setMin2gRssiDbm(-70);
+ settings.setMin5gRssiDbm(-60);
+ settings.setMin6gRssiDbm(-50);
+ settings.setPnoNetworks(createTestNetworks());
+
+ PnoSettings settings2 = new PnoSettings();
+ settings.setIntervalMillis(2000);
+ settings.setMin2gRssiDbm(-70);
+ settings.setMin5gRssiDbm(-60);
+ settings.setMin6gRssiDbm(-50);
+ settings.setPnoNetworks(createTestNetworks());
+
+ assertThat(settings2).isNotEqualTo(settings);
+ }
+}
diff --git a/tests/tests/net/src/android/net/wifi/nl80211/cts/RadioChainInfoTest.java b/tests/tests/net/src/android/net/wifi/nl80211/cts/RadioChainInfoTest.java
new file mode 100644
index 0000000..0a76bdb
--- /dev/null
+++ b/tests/tests/net/src/android/net/wifi/nl80211/cts/RadioChainInfoTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 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.net.wifi.nl80211.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.net.wifi.cts.WifiFeature;
+import android.net.wifi.nl80211.RadioChainInfo;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** CTS tests for {@link RadioChainInfo}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RadioChainInfoTest {
+
+ private static final int TEST_CHAIN_ID = 1;
+ private static final int TEST_CHAIN_ID2 = 2;
+ private static final int TEST_LEVEL_DBM = -50;
+ private static final int TEST_LEVEL_DBM2 = -80;
+
+ @Before
+ public void setUp() {
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ // skip tests if Wifi is not supported
+ assumeTrue(WifiFeature.isWifiSupported(context));
+ }
+
+ @Test
+ public void testGetters() {
+ RadioChainInfo info = new RadioChainInfo(TEST_CHAIN_ID, TEST_LEVEL_DBM);
+ assertThat(info.getChainId()).isEqualTo(TEST_CHAIN_ID);
+ assertThat(info.getLevelDbm()).isEqualTo(TEST_LEVEL_DBM);
+ }
+
+ @Test
+ public void canSerializeAndDeserialize() {
+ RadioChainInfo info = new RadioChainInfo(TEST_CHAIN_ID, TEST_LEVEL_DBM);
+
+ Parcel parcel = Parcel.obtain();
+ info.writeToParcel(parcel, 0);
+ // Rewind the pointer to the head of the parcel.
+ parcel.setDataPosition(0);
+ RadioChainInfo infoDeserialized = RadioChainInfo.CREATOR.createFromParcel(parcel);
+
+ assertThat(infoDeserialized.getChainId()).isEqualTo(TEST_CHAIN_ID);
+ assertThat(infoDeserialized.getLevelDbm()).isEqualTo(TEST_LEVEL_DBM);
+ assertThat(infoDeserialized).isEqualTo(info);
+ assertThat(infoDeserialized.hashCode()).isEqualTo(info.hashCode());
+ }
+
+ @Test
+ public void testEquals() {
+ RadioChainInfo info = new RadioChainInfo(TEST_CHAIN_ID, TEST_LEVEL_DBM);
+ RadioChainInfo info2 = new RadioChainInfo(TEST_CHAIN_ID2, TEST_LEVEL_DBM2);
+
+ assertThat(info2).isNotEqualTo(info);
+ }
+}
diff --git a/tests/tests/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java b/tests/tests/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java
new file mode 100644
index 0000000..f1f3010
--- /dev/null
+++ b/tests/tests/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 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.net.wifi.nl80211.cts;
+
+import static android.net.wifi.nl80211.WifiNl80211Manager.OemSecurityType;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.net.wifi.ScanResult;
+import android.net.wifi.cts.WifiFeature;
+import android.net.wifi.nl80211.WifiNl80211Manager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+/** CTS tests for {@link WifiNl80211Manager}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WifiNl80211ManagerTest {
+
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ // skip tests if Wifi is not supported
+ assumeTrue(WifiFeature.isWifiSupported(mContext));
+ }
+
+ @Test
+ public void testOemSecurityTypeConstructor() {
+ OemSecurityType securityType = new OemSecurityType(
+ ScanResult.PROTOCOL_WPA,
+ Arrays.asList(ScanResult.KEY_MGMT_PSK, ScanResult.KEY_MGMT_SAE),
+ Arrays.asList(ScanResult.CIPHER_NONE, ScanResult.CIPHER_TKIP),
+ ScanResult.CIPHER_CCMP);
+
+ assertThat(securityType.protocol).isEqualTo(ScanResult.PROTOCOL_WPA);
+ assertThat(securityType.keyManagement)
+ .isEqualTo(Arrays.asList(ScanResult.KEY_MGMT_PSK, ScanResult.KEY_MGMT_SAE));
+ assertThat(securityType.pairwiseCipher)
+ .isEqualTo(Arrays.asList(ScanResult.CIPHER_NONE, ScanResult.CIPHER_TKIP));
+ assertThat(securityType.groupCipher).isEqualTo(ScanResult.CIPHER_CCMP);
+ }
+
+ @Test
+ public void testSendMgmtFrame() {
+ try {
+ WifiNl80211Manager manager = mContext.getSystemService(WifiNl80211Manager.class);
+ manager.sendMgmtFrame("wlan0", new byte[]{}, -1, Runnable::run,
+ new WifiNl80211Manager.SendMgmtFrameCallback() {
+ @Override
+ public void onAck(int elapsedTimeMs) {}
+
+ @Override
+ public void onFailure(int reason) {}
+ });
+ } catch (Exception ignore) {}
+ }
+}
diff --git a/tests/tests/net/src/android/net/wifi/p2p/cts/WifiP2pDeviceTest.java b/tests/tests/net/src/android/net/wifi/p2p/cts/WifiP2pDeviceTest.java
new file mode 100644
index 0000000..1510d7c
--- /dev/null
+++ b/tests/tests/net/src/android/net/wifi/p2p/cts/WifiP2pDeviceTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 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.net.wifi.p2p.cts;
+
+import android.net.InetAddresses;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.test.AndroidTestCase;
+
+public class WifiP2pDeviceTest extends AndroidTestCase {
+
+ public void testDefaultWpsMethodSupportCheck() {
+ WifiP2pDevice dev = new WifiP2pDevice();
+
+ assertFalse(dev.wpsPbcSupported());
+ assertFalse(dev.wpsDisplaySupported());
+ assertFalse(dev.wpsKeypadSupported());
+ }
+
+ public void testDefaultDeviceCapabilityCheck() {
+ WifiP2pDevice dev = new WifiP2pDevice();
+
+ assertFalse(dev.isServiceDiscoveryCapable());
+ }
+}
diff --git a/tests/tests/net/src/android/net/wifi/p2p/cts/WifiP2pServiceRequestTest.java b/tests/tests/net/src/android/net/wifi/p2p/cts/WifiP2pServiceRequestTest.java
new file mode 100644
index 0000000..b363b1e
--- /dev/null
+++ b/tests/tests/net/src/android/net/wifi/p2p/cts/WifiP2pServiceRequestTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 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.net.wifi.p2p.cts;
+
+import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
+import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
+import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.stream.Collectors;
+
+public class WifiP2pServiceRequestTest extends AndroidTestCase {
+
+ private final int TEST_UPNP_VERSION = 0x10;
+ private final String TEST_UPNP_QUERY = "ssdp:all";
+
+ private String bin2HexStr(byte[] data) {
+ StringBuffer sb = new StringBuffer();
+ for (byte b: data) {
+ sb.append(String.format(Locale.US, "%02x", b & 0xff));
+ }
+ return sb.toString();
+ }
+
+ public void testValidRawRequest() throws IllegalArgumentException {
+ StringBuffer sb = new StringBuffer();
+ sb.append(String.format(Locale.US, "%02x", TEST_UPNP_VERSION));
+ sb.append(bin2HexStr(TEST_UPNP_QUERY.getBytes()));
+
+ WifiP2pServiceRequest rawRequest =
+ WifiP2pServiceRequest.newInstance(
+ WifiP2pServiceInfo.SERVICE_TYPE_UPNP,
+ sb.toString());
+
+ WifiP2pUpnpServiceRequest upnpRequest =
+ WifiP2pUpnpServiceRequest.newInstance(
+ TEST_UPNP_QUERY);
+
+ assertEquals(rawRequest, upnpRequest);
+ }
+
+ public void testInvalidRawRequest() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(String.format(Locale.US, "%02x", TEST_UPNP_VERSION));
+ sb.append(bin2HexStr(TEST_UPNP_QUERY.getBytes()));
+ sb.append("x");
+
+ try {
+ WifiP2pServiceRequest request =
+ WifiP2pServiceRequest.newInstance(
+ WifiP2pServiceInfo.SERVICE_TYPE_UPNP, sb.toString());
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException ex) {
+ return;
+ }
+ }
+}
diff --git a/tests/tests/os/src/android/os/cts/BinderTest.java b/tests/tests/os/src/android/os/cts/BinderTest.java
index 5bc304a..d73aff8 100644
--- a/tests/tests/os/src/android/os/cts/BinderTest.java
+++ b/tests/tests/os/src/android/os/cts/BinderTest.java
@@ -331,6 +331,8 @@
assertTrue(mBinder.unlinkToDeath(new MockDeathRecipient(), 0));
assertTrue(mBinder.pingBinder());
+
+ assertTrue(IBinder.getSuggestedMaxIpcSizeBytes() > 0);
}
public void testFlushPendingCommands() {
diff --git a/tests/tests/os/src/android/os/cts/ParcelTest.java b/tests/tests/os/src/android/os/cts/ParcelTest.java
index 0fd3d38..bb7b41a 100644
--- a/tests/tests/os/src/android/os/cts/ParcelTest.java
+++ b/tests/tests/os/src/android/os/cts/ParcelTest.java
@@ -2055,6 +2055,18 @@
p.recycle();
}
+ public void testReadParcelableCreator() {
+ MockClassLoader mcl = new MockClassLoader();
+ final String signatureString = "1234567890abcdef";
+ Signature s = new Signature(signatureString);
+
+ Parcel p = Parcel.obtain();
+ p.writeParcelableCreator(s);
+ p.setDataPosition(0);
+ assertSame(Signature.CREATOR, p.readParcelableCreator(mcl));
+ p.recycle();
+ }
+
public void testReadParcelableArray() {
Parcel p;
MockClassLoader mcl = new MockClassLoader();
diff --git a/tests/tests/os/src/android/os/cts/StrictModeTest.java b/tests/tests/os/src/android/os/cts/StrictModeTest.java
index 1a4f0ef..b750e707 100644
--- a/tests/tests/os/src/android/os/cts/StrictModeTest.java
+++ b/tests/tests/os/src/android/os/cts/StrictModeTest.java
@@ -626,10 +626,11 @@
.penaltyLog()
.build());
+ final String wmClassName = WindowManager.class.getSimpleName();
inspectViolation(
() -> getContext().getApplicationContext().getSystemService(WindowManager.class),
info -> assertThat(info.getStackTrace()).contains(
- "Tried to access visual service " + WINDOW_SERVICE));
+ "Tried to access visual service " + wmClassName));
final Display display = getContext().getSystemService(DisplayManager.class)
.getDisplay(DEFAULT_DISPLAY);
diff --git a/tests/tests/os/src/android/os/cts/VibratorTest.java b/tests/tests/os/src/android/os/cts/VibratorTest.java
index 09ba0fa..f597612 100644
--- a/tests/tests/os/src/android/os/cts/VibratorTest.java
+++ b/tests/tests/os/src/android/os/cts/VibratorTest.java
@@ -144,25 +144,36 @@
mVibrator.hasAmplitudeControl();
}
+ /**
+ * For devices with vibrator we assert the IsVibrating state, for devices without vibrator just
+ * ensure it won't crash with IsVibrating call.
+ */
+ private void assertIsVibrating(boolean expected) {
+ final boolean isVibrating = mVibrator.isVibrating();
+ if (mVibrator.hasVibrator()) {
+ assertEquals(isVibrating, expected);
+ }
+ }
+
@Test
public void testVibratorIsVibrating() {
final UiAutomation ui = InstrumentationRegistry.getInstrumentation().getUiAutomation();
ui.adoptShellPermissionIdentity("android.permission.ACCESS_VIBRATOR_STATE");
- assertEquals(mVibrator.isVibrating(), false);
+ assertIsVibrating(false);
mVibrator.vibrate(1000);
- assertEquals(mVibrator.isVibrating(), true);
+ assertIsVibrating(true);
mVibrator.cancel();
- assertEquals(mVibrator.isVibrating(), false);
+ assertIsVibrating(false);
}
@Test
public void testVibratorVibratesNoLongerThanDuration() {
final UiAutomation ui = InstrumentationRegistry.getInstrumentation().getUiAutomation();
ui.adoptShellPermissionIdentity("android.permission.ACCESS_VIBRATOR_STATE");
- assertEquals(mVibrator.isVibrating(), false);
+ assertIsVibrating(false);
mVibrator.vibrate(100);
SystemClock.sleep(150);
- assertEquals(mVibrator.isVibrating(), false);
+ assertIsVibrating(false);
}
@Test
@@ -179,7 +190,7 @@
.times(1)).onVibratorStateChanged(false);
mVibrator.vibrate(1000);
- assertEquals(mVibrator.isVibrating(), true);
+ assertIsVibrating(true);
verify(mListener1, timeout(CALLBACK_TIMEOUT_MILLIS)
.times(1)).onVibratorStateChanged(true);
@@ -193,7 +204,7 @@
mVibrator.removeVibratorStateListener(mListener2);
mVibrator.cancel();
- assertEquals(mVibrator.isVibrating(), false);
+ assertIsVibrating(false);
}
private static void sleep(long millis) {
diff --git a/tests/tests/packageinstaller/nopermission/AndroidTest.xml b/tests/tests/packageinstaller/nopermission/AndroidTest.xml
index 2229230..08ae8cc 100644
--- a/tests/tests/packageinstaller/nopermission/AndroidTest.xml
+++ b/tests/tests/packageinstaller/nopermission/AndroidTest.xml
@@ -36,6 +36,10 @@
<option name="test-file-name" value="CtsNoPermissionTestCases.apk" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="appops set android.packageinstaller.nopermission.cts REQUEST_INSTALL_PACKAGES allow" />
+ </target_preparer>
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.packageinstaller.nopermission.cts" />
<option name="runtime-hint" value="1m" />
diff --git a/tests/tests/packageinstaller/nopermission/src/android.packageinstaller.nopermission.cts/NoPermissionTests.kt b/tests/tests/packageinstaller/nopermission/src/android.packageinstaller.nopermission.cts/NoPermissionTests.kt
index 022d598..024d1ad 100644
--- a/tests/tests/packageinstaller/nopermission/src/android.packageinstaller.nopermission.cts/NoPermissionTests.kt
+++ b/tests/tests/packageinstaller/nopermission/src/android.packageinstaller.nopermission.cts/NoPermissionTests.kt
@@ -15,7 +15,6 @@
*/
package android.packageinstaller.nopermission.cts
-import android.app.AppOpsManager.MODE_ALLOWED
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
@@ -33,7 +32,6 @@
import android.support.test.uiautomator.UiDevice
import android.support.test.uiautomator.Until
import androidx.core.content.FileProvider
-import com.android.compatibility.common.util.AppOpsUtils
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -54,7 +52,6 @@
private const val ACTION = "NoPermissionTests.install_cb"
private const val WAIT_FOR_UI_TIMEOUT = 5000L
-private const val APP_OP_STR = "REQUEST_INSTALL_PACKAGES"
@RunWith(AndroidJUnit4::class)
@MediumTest
@@ -92,12 +89,6 @@
}
@Before
- fun allowToInstallPackages() {
- // To make sure no other blocking dialogs appear
- AppOpsUtils.setOpMode(context.packageName, APP_OP_STR, MODE_ALLOWED)
- }
-
- @Before
fun registerInstallResultReceiver() {
context.registerReceiver(receiver, IntentFilter(ACTION))
}
diff --git a/tests/tests/permission/src/android/permission/cts/SecureElementPermissionTest.java b/tests/tests/permission/src/android/permission/cts/SecureElementPermissionTest.java
index cb857f0..0940d5f 100644
--- a/tests/tests/permission/src/android/permission/cts/SecureElementPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/SecureElementPermissionTest.java
@@ -35,7 +35,7 @@
public final class SecureElementPermissionTest {
// Needed because SECURE_ELEMENT_PRIVILEGED_PERMISSION is a systemapi
public static final String SECURE_ELEMENT_PRIVILEGED_PERMISSION =
- "android.permission.SECURE_ELEMENT_PRIVILEGED";
+ "android.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION";
@Test
public void testSecureElementPrivilegedPermission() {
@@ -59,8 +59,8 @@
.collect(Collectors.toList());
if (nonSpecialPackages.size() > 1) {
- fail("Only one app on the device is allowed to hold the SECURE_ELEMENT_PRIVILEGED " +
- "permission.");
+ fail("Only one app on the device is allowed to hold the "
+ + "SECURE_ELEMENT_PRIVILEGED_OPERATION permission.");
}
}
}
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 3e831fd..da3cc11 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -727,10 +727,10 @@
<!-- ====================================================================== -->
<eat-comment />
- <!-- @SystemApi Allows accessing the messages on ICC
+ <!-- Allows accessing the messages on ICC
@hide Used internally. -->
<permission android:name="android.permission.ACCESS_MESSAGES_ON_ICC"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- Used for runtime permissions related to user's SMS messages. -->
<permission-group android:name="android.permission-group.SMS"
@@ -1102,13 +1102,12 @@
grants your app this permission. If you don't need this permission, be sure your <a
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
targetSdkVersion}</a> is 4 or higher.
- <p>Protection level: dangerous
+ <p>Protection level: normal
-->
<permission android:name="android.permission.READ_PHONE_STATE"
- android:permissionGroup="android.permission-group.UNDEFINED"
android:label="@string/permlab_readPhoneState"
android:description="@string/permdesc_readPhoneState"
- android:protectionLevel="dangerous" />
+ android:protectionLevel="normal" />
<!-- Allows read access to the device's phone number(s). This is a subset of the capabilities
granted by {@link #READ_PHONE_STATE} but is exposed to instant applications.
@@ -1180,6 +1179,14 @@
android:description="@string/permdesc_callCompanionApp"
android:protectionLevel="normal" />
+ <!-- Exempt this uid from restrictions to background audio recording
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS"
+ android:label="@string/permlab_exemptFromAudioRecordRestrictions"
+ android:description="@string/permdesc_exemptFromAudioRecordRestrictions"
+ android:protectionLevel="signature|privileged" />
+
<!-- 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
@@ -1672,13 +1679,17 @@
<permission android:name="android.permission.NETWORK_FACTORY"
android:protectionLevel="signature" />
+ <!-- @SystemApi @hide Allows applications to access network stats provider -->
+ <permission android:name="android.permission.NETWORK_STATS_PROVIDER"
+ android:protectionLevel="signature" />
+
<!-- Allows Settings and SystemUI to call methods in Networking services
<p>Not for use by third-party or privileged applications.
@SystemApi
@hide This should only be used by Settings and SystemUI.
-->
<permission android:name="android.permission.NETWORK_SETTINGS"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- Allows holder to request bluetooth/wifi scan bypassing global "use location" setting and
location permissions.
@@ -1821,7 +1832,7 @@
<!-- @SystemApi Allows an internal user to use privileged SecureElement APIs.
@hide -->
- <permission android:name="android.permission.SECURE_ELEMENT_PRIVILEGED"
+ <permission android:name="android.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION"
android:protectionLevel="signature|privileged" />
<!-- @deprecated This permission used to allow too broad access to sensitive methods and all its
@@ -2112,7 +2123,7 @@
<!-- @SystemApi Allows granting runtime permissions to telephony related components.
@hide -->
<permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- Allows modification of the telephony state - power on, mmi, etc.
Does not include placing calls.
@@ -2140,7 +2151,7 @@
<!-- @SystemApi Allows listen permission to always reported signal strength.
@hide Used internally. -->
<permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Protects the ability to register any PhoneAccount with
PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION. This capability indicates that the PhoneAccount
@@ -2253,21 +2264,21 @@
<!-- Must be required by a telephony data service to ensure that only the
system can bind to it.
- <p>Protection level: signature|telephony
+ <p>Protection level: signature
@SystemApi
@hide
-->
<permission android:name="android.permission.BIND_TELEPHONY_DATA_SERVICE"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- Must be required by a NetworkService to ensure that only the
system can bind to it.
- <p>Protection level: signature|telephony
+ <p>Protection level: signature
@SystemApi
@hide
-->
<permission android:name="android.permission.BIND_TELEPHONY_NETWORK_SERVICE"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to manage embedded subscriptions (those on a eUICC)
through EuiccManager APIs.
@@ -2279,19 +2290,19 @@
<!-- @SystemApi Must be required by an EuiccService to ensure that only the system can bind to
it.
- <p>Protection level: signature|telephony
+ <p>Protection level: signature
@hide
-->
<permission android:name="android.permission.BIND_EUICC_SERVICE"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- Required for reading information about carrier apps from SystemConfigManager.
- <p>Protection level: signature|telephony
+ <p>Protection level: signature
@SystemApi
@hide
-->
<permission android:name="android.permission.READ_CARRIER_APP_INFO"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- ================================== -->
<!-- Permissions for sdcard interaction -->
@@ -2411,7 +2422,7 @@
types of interactions
@hide -->
<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
- android:protectionLevel="signature|installer|telephony" />
+ android:protectionLevel="signature|installer" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<!-- Allows interaction across profiles in the same profile group. -->
@@ -2649,7 +2660,7 @@
@hide
-->
<permission android:name="android.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- Allows applications like settings to suggest the user's manually chosen time / time zone.
<p>Not for use by third-party applications.
@@ -3073,7 +3084,7 @@
@hide -->
// TODO: remove telephony once decouple settings activity from phone process
<permission android:name="android.permission.STATUS_BAR_SERVICE"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- Allows an application to bind to third party quick settings tiles.
<p>Should only be requested by the System, should be required by
@@ -3131,7 +3142,7 @@
@hide
-->
<permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to use
{@link android.view.WindowManager.LayoutsParams#SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS}
@@ -3208,7 +3219,7 @@
@hide
-->
<permission android:name="android.permission.SET_ACTIVITY_WATCHER"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to call the activity manager shutdown() API
to put the higher-level system there into a shutdown state.
@@ -3732,6 +3743,12 @@
<permission android:name="android.permission.WHITELIST_RESTRICTED_PERMISSIONS"
android:protectionLevel="signature|installer" />
+ <!-- @SystemApi Allows an application to an exempt an app from having its permission be
+ auto-revoked when unused for an extended period of time.
+ @hide -->
+ <permission android:name="android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS"
+ android:protectionLevel="signature|installer" />
+
<!-- @hide Allows an application to observe permission changes. -->
<permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
android:protectionLevel="signature|privileged" />
@@ -3745,7 +3762,7 @@
@hide
STOPSHIP b/145526313: Remove wellbeing protection flag from MANAGE_ROLE_HOLDERS. -->
<permission android:name="android.permission.MANAGE_ROLE_HOLDERS"
- android:protectionLevel="signature|installer|telephony|wellbeing" />
+ android:protectionLevel="signature|installer|wellbeing" />
<!-- @SystemApi Allows an application to observe role holder changes.
@hide -->
@@ -3982,7 +3999,7 @@
@hide
-->
<permission android:name="android.permission.DEVICE_POWER"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- Allows toggling battery saver on the system.
Superseded by DEVICE_POWER permission. @hide @SystemApi
@@ -4017,13 +4034,13 @@
<p>Not for use by third-party applications.
-->
<permission android:name="android.permission.BROADCAST_SMS"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- Allows an application to broadcast a WAP PUSH receipt notification.
<p>Not for use by third-party applications.
-->
<permission android:name="android.permission.BROADCAST_WAP_PUSH"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to broadcast privileged networking requests.
<p>Not for use by third-party applications.
@@ -4689,13 +4706,13 @@
{@link android.provider.BlockedNumberContract}.
@hide -->
<permission android:name="android.permission.READ_BLOCKED_NUMBERS"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- Allows the holder to write blocked numbers. See
{@link android.provider.BlockedNumberContract}.
@hide -->
<permission android:name="android.permission.WRITE_BLOCKED_NUMBERS"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- Must be required by an {@link android.service.vr.VrListenerService}, to ensure that only
the system can bind to it.
@@ -4855,7 +4872,7 @@
<!-- @hide Permission that allows configuring appops.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.MANAGE_APPOPS"
- android:protectionLevel="signature|telephony" />
+ android:protectionLevel="signature" />
<!-- @hide Permission that allows background clipboard access.
<p>Not for use by third-party applications. -->
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index 3024a49..82e2a2a 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -402,9 +402,6 @@
case "runtime": {
protectionLevel |= PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY;
} break;
- case "telephony": {
- protectionLevel |= PermissionInfo.PROTECTION_FLAG_TELEPHONY;
- } break;
case "companion": {
protectionLevel |= PermissionInfo.PROTECTION_FLAG_COMPANION;
} break;
diff --git a/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt b/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt
index 26c6cc8..96c04d5 100644
--- a/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt
+++ b/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt
@@ -34,7 +34,6 @@
import android.Manifest.permission.READ_CONTACTS
import android.Manifest.permission.READ_EXTERNAL_STORAGE
import android.Manifest.permission.READ_PHONE_NUMBERS
-import android.Manifest.permission.READ_PHONE_STATE
import android.Manifest.permission.READ_SMS
import android.Manifest.permission.RECEIVE_MMS
import android.Manifest.permission.RECEIVE_SMS
@@ -123,7 +122,7 @@
WRITE_CALENDAR, SEND_SMS, RECEIVE_SMS, READ_SMS, RECEIVE_MMS, RECEIVE_WAP_PUSH,
READ_CELL_BROADCASTS, READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE,
ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, READ_CALL_LOG, WRITE_CALL_LOG,
- PROCESS_OUTGOING_CALLS, READ_PHONE_STATE, READ_PHONE_NUMBERS, CALL_PHONE,
+ PROCESS_OUTGOING_CALLS, READ_PHONE_NUMBERS, CALL_PHONE,
ADD_VOICEMAIL, USE_SIP, ANSWER_PHONE_CALLS, ACCEPT_HANDOVER, RECORD_AUDIO, CAMERA,
BODY_SENSORS)
diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionTest23.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionTest23.kt
index cecdd38..8a61da7 100644
--- a/tests/tests/permission3/src/android/permission3/cts/PermissionTest23.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/PermissionTest23.kt
@@ -16,6 +16,7 @@
package android.permission3.cts
+import androidx.test.filters.FlakyTest
import org.junit.Before
import org.junit.Test
@@ -228,6 +229,7 @@
assertAppHasPermission(android.Manifest.permission.READ_CONTACTS, false)
}
+ @FlakyTest
@Test
fun testNoResidualPermissionsOnUninstall() {
// Grant all permissions
@@ -309,7 +311,6 @@
android.Manifest.permission.WRITE_CALENDAR,
android.Manifest.permission.WRITE_CONTACTS,
android.Manifest.permission.READ_SMS,
- android.Manifest.permission.READ_PHONE_STATE,
android.Manifest.permission.READ_CALL_LOG,
android.Manifest.permission.WRITE_CALL_LOG,
android.Manifest.permission.ADD_VOICEMAIL,
diff --git a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
index 4c5f898..357e5e8 100644
--- a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
@@ -55,6 +55,13 @@
private static final String RESOURCE_DONE = "done";
private static final String RESOURCE_SEE_MORE = "see_more";
private static final String RESOURCE_TITLE = "panel_title";
+ private static final String RESOURCE_HEADER = "header_title";
+ private static final String TEST_PACKAGE_NAME = "test_package_name";
+ private static final String MEDIA_OUTPUT_TITLE_NAME = "Media";
+ private static final String ACTION_MEDIA_OUTPUT =
+ "com.android.settings.panel.action.MEDIA_OUTPUT";
+ private static final String EXTRA_PACKAGE_NAME =
+ "com.android.settings.panel.extra.PACKAGE_NAME";
private String mSettingsPackage;
private String mLauncherPackage;
@@ -120,6 +127,24 @@
}
@Test
+ public void mediaOutputPanel_withPackageNameExtra_correctPackage() {
+ launchMediaOutputPanel(TEST_PACKAGE_NAME);
+
+ String currentPackage = mDevice.getCurrentPackageName();
+
+ assertThat(currentPackage).isEqualTo(mSettingsPackage);
+ }
+
+ @Test
+ public void mediaOutputPanel_noPutPackageNameExtra_correctPackage() {
+ launchMediaOutputPanel(null /* packageName */);
+
+ String currentPackage = mDevice.getCurrentPackageName();
+
+ assertThat(currentPackage).isEqualTo(mSettingsPackage);
+ }
+
+ @Test
public void wifiPanel_correctPackage() {
launchWifiPanel();
@@ -129,6 +154,14 @@
}
@Test
+ public void mediaOutputPanel_correctTitle() {
+ launchMediaOutputPanel(TEST_PACKAGE_NAME);
+
+ final UiObject2 titleView = mDevice.findObject(By.res(mSettingsPackage, RESOURCE_HEADER));
+
+ assertThat(titleView.getText()).isEqualTo(MEDIA_OUTPUT_TITLE_NAME);
+ }
+ @Test
public void internetPanel_doneClosesPanel() {
// Launch panel
launchInternetPanel();
@@ -189,6 +222,22 @@
}
@Test
+ public void mediaOutputPanel_doneClosesPanel() {
+ // Launch panel
+ launchMediaOutputPanel(TEST_PACKAGE_NAME);
+ String currentPackage = mDevice.getCurrentPackageName();
+ assertThat(currentPackage).isEqualTo(mSettingsPackage);
+
+ // Click the done button
+ mDevice.findObject(By.res(currentPackage, RESOURCE_DONE)).click();
+ mDevice.wait(Until.hasObject(By.pkg(mLauncherPackage).depth(0)), TIMEOUT);
+
+ // Assert that we have left the panel
+ currentPackage = mDevice.getCurrentPackageName();
+ assertThat(currentPackage).isNotEqualTo(mSettingsPackage);
+ }
+
+ @Test
public void internetPanel_seeMoreButton_launchesIntoSettings() {
// Launch panel
launchInternetPanel();
@@ -261,6 +310,19 @@
assertThat(titleView).isNull();
}
+ @Test
+ public void mediaOutputPanel_seeMoreButton_doNothing() {
+ // Launch panel
+ launchMediaOutputPanel(TEST_PACKAGE_NAME);
+ String currentPackage = mDevice.getCurrentPackageName();
+ assertThat(currentPackage).isEqualTo(mSettingsPackage);
+
+ // Find the see more button
+ // SeeMoreIntent is null in MediaOutputPanel, so the see more button will not visible.
+ UiObject2 seeMoreView = mDevice.findObject(By.res(mSettingsPackage, RESOURCE_SEE_MORE));
+ assertThat(seeMoreView).isNull();
+ }
+
private void launchVolumePanel() {
launchPanel(Settings.Panel.ACTION_VOLUME);
}
@@ -269,6 +331,10 @@
launchPanel(Settings.Panel.ACTION_INTERNET_CONNECTIVITY);
}
+ private void launchMediaOutputPanel(String packageName) {
+ launchPanel(ACTION_MEDIA_OUTPUT, packageName);
+ }
+
private void launchNfcPanel() {
assumeTrue(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC));
launchPanel(Settings.Panel.ACTION_NFC);
@@ -280,6 +346,10 @@
}
private void launchPanel(String action) {
+ launchPanel(action, null /* packageName */);
+ }
+
+ private void launchPanel(String action, String packageName) {
// Start from the home screen
mDevice.pressHome();
mDevice.wait(Until.hasObject(By.pkg(mLauncherPackage).depth(0)), TIMEOUT);
@@ -287,6 +357,7 @@
Intent intent = new Intent(action);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK); // Clear out any previous instances
+ intent.putExtra(EXTRA_PACKAGE_NAME, packageName);
mContext.startActivity(intent);
// Wait for the app to appear
diff --git a/tests/tests/security/AndroidTest.xml b/tests/tests/security/AndroidTest.xml
index 4dfec996..45220d9 100644
--- a/tests/tests/security/AndroidTest.xml
+++ b/tests/tests/security/AndroidTest.xml
@@ -17,7 +17,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="security" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
index 5a035dd..47730e1 100644
--- a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
+++ b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
@@ -15,11 +15,15 @@
*/
package android.security.cts;
+import android.app.ActivityManager;
import android.os.IBinder;
import android.platform.test.annotations.SecurityTest;
+import android.util.Log;
import junit.framework.TestCase;
+import java.lang.reflect.InvocationTargetException;
+
@SecurityTest
public class ActivityManagerTest extends TestCase {
@@ -44,4 +48,32 @@
// Patched devices should throw this exception
}
}
+
+ // b/144285917
+ @SecurityTest(minPatchLevel = "2020-05")
+ public void testActivityManager_attachNullApplication() {
+ SecurityException securityException = null;
+ Exception unexpectedException = null;
+ try {
+ final Object iam = ActivityManager.class.getDeclaredMethod("getService").invoke(null);
+ Class.forName("android.app.IActivityManager").getDeclaredMethod("attachApplication",
+ Class.forName("android.app.IApplicationThread"), long.class)
+ .invoke(iam, null /* thread */, 0 /* startSeq */);
+ } catch (SecurityException e) {
+ securityException = e;
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof SecurityException) {
+ securityException = (SecurityException) e.getCause();
+ } else {
+ unexpectedException = e;
+ }
+ } catch (Exception e) {
+ unexpectedException = e;
+ }
+ if (unexpectedException != null) {
+ Log.w("ActivityManagerTest", "Unexpected exception", unexpectedException);
+ }
+
+ assertNotNull("Expect SecurityException by attaching null application", securityException);
+ }
}
diff --git a/tests/tests/security/src/android/security/cts/CertificateTest.java b/tests/tests/security/src/android/security/cts/CertificateTest.java
index 54bacc9..2d88988 100644
--- a/tests/tests/security/src/android/security/cts/CertificateTest.java
+++ b/tests/tests/security/src/android/security/cts/CertificateTest.java
@@ -93,7 +93,7 @@
* For questions, comments, and code reviews please contact security@android.com.
*/
public void testNoRemovedWfaCertificates() throws Exception {
- if (!supportPasspoint()) {
+ if (!isWifiSupported()) {
return;
}
Set<String> expectedCertificates = new HashSet<>(
@@ -104,7 +104,7 @@
}
public void testNoAddedWfaCertificates() throws Exception {
- if (!supportPasspoint()) {
+ if (!isWifiSupported()) {
return;
}
Set<String> expectedCertificates = new HashSet<String>(
@@ -114,8 +114,8 @@
assertEquals("Unknown WFA CA certificates", Collections.EMPTY_SET, deviceWfaCertificates);
}
- private boolean supportPasspoint() {
- return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT);
+ private boolean isWifiSupported() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
}
private KeyStore createWfaKeyStore() throws CertificateException, IOException,
diff --git a/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java b/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java
index e7ab8eb..a324fd7 100644
--- a/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java
+++ b/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java
@@ -48,9 +48,11 @@
import android.util.Log;
import android.annotation.Nullable;
+import android.platform.test.annotations.AppModeFull;
import static java.lang.Thread.sleep;
import static org.junit.Assert.assertTrue;
+@AppModeFull
@SecurityTest
public class NanoAppBundleTest extends AndroidTestCase {
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 6b122da..875bc91 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -111,17 +111,17 @@
@SecurityTest(minPatchLevel = "2016-08")
public void testStagefright_cve_2016_3829() throws Exception {
- doStagefrightTest(R.raw.cve_2016_3829, false);
+ doStagefrightTest(R.raw.cve_2016_3829, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-06")
public void testStagefright_cve_2017_0643() throws Exception {
- doStagefrightTest(R.raw.cve_2017_0643, false);
+ doStagefrightTest(R.raw.cve_2017_0643, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-08")
public void testStagefright_cve_2017_0728() throws Exception {
- doStagefrightTest(R.raw.cve_2017_0728, false);
+ doStagefrightTest(R.raw.cve_2017_0728, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-10")
@@ -161,7 +161,7 @@
@SecurityTest(minPatchLevel = "2017-06")
public void testStagefright_bug_35763994() throws Exception {
- doStagefrightTest(R.raw.bug_35763994, false);
+ doStagefrightTest(R.raw.bug_35763994, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-03")
@@ -171,7 +171,7 @@
@SecurityTest(minPatchLevel = "2017-07")
public void testStagefright_cve_2016_2507() throws Exception {
- doStagefrightTest(R.raw.cve_2016_2507, false);
+ doStagefrightTest(R.raw.cve_2016_2507, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-03")
@@ -266,13 +266,14 @@
@SecurityTest(minPatchLevel = "2017-02")
public void testStagefright_cve_2016_2429_b_27211885() throws Exception {
- doStagefrightTest(R.raw.cve_2016_2429_b_27211885, false);
+ doStagefrightTest(R.raw.cve_2016_2429_b_27211885,
+ new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-08")
public void testStagefright_bug_34031018() throws Exception {
- doStagefrightTest(R.raw.bug_34031018_32bit, false);
- doStagefrightTest(R.raw.bug_34031018_64bit, false);
+ doStagefrightTest(R.raw.bug_34031018_32bit, new CrashUtils.Config().checkMinAddress(false));
+ doStagefrightTest(R.raw.bug_34031018_64bit, new CrashUtils.Config().checkMinAddress(false));
}
/***********************************************************
@@ -297,7 +298,8 @@
@SecurityTest(minPatchLevel = "2018-01")
public void testStagefright_cve_2017_0852_b_62815506() throws Exception {
- doStagefrightTest(R.raw.cve_2017_0852_b_62815506, false);
+ doStagefrightTest(R.raw.cve_2017_0852_b_62815506,
+ new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2018-02")
@@ -323,7 +325,7 @@
@SecurityTest(minPatchLevel = "2016-10")
public void testStagefright_cve_2016_3920() throws Exception {
- doStagefrightTest(R.raw.cve_2016_3920, false);
+ doStagefrightTest(R.raw.cve_2016_3920, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2018-06")
@@ -338,7 +340,7 @@
@SecurityTest(minPatchLevel = "2016-08")
public void testStagefright_cve_2016_3821() throws Exception {
- doStagefrightTest(R.raw.cve_2016_3821, false);
+ doStagefrightTest(R.raw.cve_2016_3821, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2018-04")
@@ -358,12 +360,12 @@
@SecurityTest(minPatchLevel = "2017-09")
public void testStagefright_bug_38115076() throws Exception {
- doStagefrightTest(R.raw.bug_38115076, false);
+ doStagefrightTest(R.raw.bug_38115076, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-05")
public void testStagefright_bug_34618607() throws Exception {
- doStagefrightTest(R.raw.bug_34618607, false);
+ doStagefrightTest(R.raw.bug_34618607, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2018-02")
@@ -388,13 +390,14 @@
@SecurityTest(minPatchLevel = "2017-05")
public void testStagefright_cve_2017_0600() throws Exception {
- doStagefrightTest(R.raw.cve_2017_0600, false);
+ doStagefrightTest(R.raw.cve_2017_0600, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-08")
public void testBug_38014992() throws Exception {
int[] frameSizes = getFrameSizes(R.raw.bug_38014992_framelen);
- doStagefrightTestRawBlob(R.raw.bug_38014992_avc, "video/avc", 640, 480, frameSizes, false);
+ doStagefrightTestRawBlob(R.raw.bug_38014992_avc, "video/avc", 640, 480, frameSizes,
+ new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-07")
@@ -424,7 +427,8 @@
@SecurityTest(minPatchLevel = "2017-03")
public void testBug_33387820() throws Exception {
int[] frameSizes = {45, 3202, 430, 2526};
- doStagefrightTestRawBlob(R.raw.bug_33387820_avc, "video/avc", 320, 240, frameSizes, false);
+ doStagefrightTestRawBlob(R.raw.bug_33387820_avc, "video/avc", 320, 240, frameSizes,
+ new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-07")
@@ -461,13 +465,15 @@
public void testBug_28816956() throws Exception {
int[] frameSizes = getFrameSizes(R.raw.bug_28816956_framelen);
doStagefrightTestRawBlob(
- R.raw.bug_28816956_hevc, "video/hevc", 352, 288, frameSizes, false);
+ R.raw.bug_28816956_hevc, "video/hevc", 352, 288, frameSizes,
+ new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-03")
public void testBug_33818500() throws Exception {
int[] frameSizes = getFrameSizes(R.raw.bug_33818500_framelen);
- doStagefrightTestRawBlob(R.raw.bug_33818500_avc, "video/avc", 64, 32, frameSizes, false);
+ doStagefrightTestRawBlob(R.raw.bug_33818500_avc, "video/avc", 64, 32, frameSizes,
+ new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2018-01")
@@ -496,7 +502,7 @@
@SecurityTest(minPatchLevel = "2017-05")
public void testStagefright_cve_2017_0599() throws Exception {
- doStagefrightTest(R.raw.cve_2017_0599, false);
+ doStagefrightTest(R.raw.cve_2017_0599, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-09")
@@ -526,7 +532,7 @@
@SecurityTest(minPatchLevel = "2017-09")
public void testStagefright_cve_2016_6712() throws Exception {
- doStagefrightTest(R.raw.cve_2016_6712, false);
+ doStagefrightTest(R.raw.cve_2016_6712, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-04")
@@ -552,12 +558,12 @@
@SecurityTest(minPatchLevel = "2017-06")
public void testStagefright_bug_33818508() throws Exception {
- doStagefrightTest(R.raw.bug_33818508, false);
+ doStagefrightTest(R.raw.bug_33818508, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-08")
public void testStagefright_bug_32873375() throws Exception {
- doStagefrightTest(R.raw.bug_32873375, false);
+ doStagefrightTest(R.raw.bug_32873375, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2018-02")
@@ -620,7 +626,7 @@
@SecurityTest(minPatchLevel = "2016-06")
public void testStagefright_cve_2016_2428() throws Exception {
- doStagefrightTest(R.raw.cve_2016_2428, false);
+ doStagefrightTest(R.raw.cve_2016_2428, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2016-07")
@@ -658,7 +664,8 @@
@Override
public void run() {
try {
- doStagefrightTestMediaCodec(tempFile.getAbsolutePath(), false);
+ doStagefrightTestMediaCodec(tempFile.getAbsolutePath(),
+ new CrashUtils.Config().checkMinAddress(false));
} catch (Exception | AssertionError e) {
if (!tempFile.delete()) {
Log.e(TAG, "Failed to delete temporary PoC file");
@@ -683,7 +690,7 @@
@SecurityTest(minPatchLevel = "2017-06")
public void testStagefright_bug_32322258() throws Exception {
- doStagefrightTest(R.raw.bug_32322258, false);
+ doStagefrightTest(R.raw.bug_32322258, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2015-10")
@@ -713,7 +720,8 @@
@SecurityTest(minPatchLevel = "2015-10")
public void testStagefright_cve_2015_3862_b_22954006() throws Exception {
- doStagefrightTest(R.raw.cve_2015_3862_b_22954006, false);
+ doStagefrightTest(R.raw.cve_2015_3862_b_22954006,
+ new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2015-10")
@@ -778,12 +786,13 @@
@SecurityTest(minPatchLevel = "2016-07")
public void testStagefright_cve_2016_3755() throws Exception {
- doStagefrightTest(R.raw.cve_2016_3755, false);
+ doStagefrightTest(R.raw.cve_2016_3755, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2016-09")
public void testStagefright_cve_2016_3878_b_29493002() throws Exception {
- doStagefrightTest(R.raw.cve_2016_3878_b_29493002, false);
+ doStagefrightTest(R.raw.cve_2016_3878_b_29493002,
+ new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-08")
@@ -803,12 +812,12 @@
@SecurityTest(minPatchLevel = "2016-06")
public void testStagefright_bug_27855419_CVE_2016_2463() throws Exception {
- doStagefrightTest(R.raw.bug_27855419, false);
+ doStagefrightTest(R.raw.bug_27855419, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2015-11")
public void testStagefright_bug_19779574() throws Exception {
- doStagefrightTest(R.raw.bug_19779574, false);
+ doStagefrightTest(R.raw.bug_19779574, new CrashUtils.Config().checkMinAddress(false));
}
/***********************************************************
@@ -823,7 +832,7 @@
@SecurityTest(minPatchLevel = "2017-07")
public void testStagefright_bug_36279112() throws Exception {
- doStagefrightTest(R.raw.bug_36279112, false);
+ doStagefrightTest(R.raw.bug_36279112, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-06")
@@ -905,7 +914,8 @@
};
server.start();
String uri = "http://127.0.0.1:8080/bug_68342866.m3u8";
- final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(false);
+ final MediaPlayerCrashListener mpcl =
+ new MediaPlayerCrashListener(new CrashUtils.Config().checkMinAddress(false));
LooperThread t = new LooperThread(new Runnable() {
@Override
public void run() {
@@ -1071,7 +1081,7 @@
@SecurityTest(minPatchLevel = "2016-12")
public void testStagefright_cve_2016_6764() throws Exception {
- doStagefrightTest(R.raw.cve_2016_6764, false);
+ doStagefrightTest(R.raw.cve_2016_6764, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2018-01")
@@ -1081,7 +1091,7 @@
@SecurityTest(minPatchLevel = "2017-06")
public void testStagefright_bug_35467107() throws Exception {
- doStagefrightTest(R.raw.bug_35467107, false);
+ doStagefrightTest(R.raw.bug_35467107, new CrashUtils.Config().checkMinAddress(false));
}
/***********************************************************
@@ -1217,12 +1227,12 @@
@SecurityTest(minPatchLevel = "2016-12")
public void testStagefright_cve_2016_6765() throws Exception {
- doStagefrightTest(R.raw.cve_2016_6765, false);
+ doStagefrightTest(R.raw.cve_2016_6765, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2016-07")
public void testStagefright_cve_2016_2508() throws Exception {
- doStagefrightTest(R.raw.cve_2016_2508, false);
+ doStagefrightTest(R.raw.cve_2016_2508, new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2016-11")
@@ -1242,19 +1252,19 @@
@SecurityTest(minPatchLevel = "2016-09")
public void testStagefright_cve_2016_3879() throws Exception {
- doStagefrightTest(R.raw.cve_2016_3879, false);
+ doStagefrightTest(R.raw.cve_2016_3879, new CrashUtils.Config().checkMinAddress(false));
}
private void doStagefrightTest(final int rid) throws Exception {
- doStagefrightTest(rid, true); // check addresss by default
+ doStagefrightTest(rid, null);
}
- private void doStagefrightTest(final int rid, boolean checkMinCrashAddress) throws Exception {
+ private void doStagefrightTest(final int rid, CrashUtils.Config config) throws Exception {
NetworkSecurityPolicy policy = NetworkSecurityPolicy.getInstance();
policy.setCleartextTrafficPermitted(true);
- doStagefrightTestMediaPlayer(rid, checkMinCrashAddress);
- doStagefrightTestMediaCodec(rid, checkMinCrashAddress);
- doStagefrightTestMediaMetadataRetriever(rid, checkMinCrashAddress);
+ doStagefrightTestMediaPlayer(rid, config);
+ doStagefrightTestMediaCodec(rid, config);
+ doStagefrightTestMediaMetadataRetriever(rid, config);
Context context = getInstrumentation().getContext();
CtsTestServer server = null;
@@ -1270,10 +1280,10 @@
String rname = resources.getResourceEntryName(rid);
String url = server.getAssetUrl("raw/" + rname);
verifyServer(rid, url);
- doStagefrightTestMediaPlayer(url, checkMinCrashAddress);
- doStagefrightTestMediaCodec(url, checkMinCrashAddress);
- doStagefrightTestMediaMetadataRetriever(url, checkMinCrashAddress);
policy.setCleartextTrafficPermitted(false);
+ doStagefrightTestMediaPlayer(url, config);
+ doStagefrightTestMediaCodec(url, config);
+ doStagefrightTestMediaMetadataRetriever(url, config);
server.shutdown();
}
@@ -1303,16 +1313,16 @@
}
private void doStagefrightTest(final int rid, int timeout) throws Exception {
- doStagefrightTest(rid, true, timeout); // check crash address by default
+ doStagefrightTest(rid, null, timeout);
}
private void doStagefrightTest(
- final int rid, boolean checkMinCrashAddress, int timeout) throws Exception {
+ final int rid, CrashUtils.Config config, int timeout) throws Exception {
runWithTimeout(new Runnable() {
@Override
public void run() {
try {
- doStagefrightTest(rid, checkMinCrashAddress);
+ doStagefrightTest(rid, config);
} catch (Exception e) {
fail(e.toString());
}
@@ -1321,12 +1331,12 @@
}
private void doStagefrightTestANR(final int rid) throws Exception {
- doStagefrightTestANR(rid, true); // check crash address by default
+ doStagefrightTestANR(rid, null);
}
private void doStagefrightTestANR(
- final int rid, boolean checkMinCrashAddress) throws Exception {
- doStagefrightTestMediaPlayerANR(rid, null);
+ final int rid, CrashUtils.Config config) throws Exception {
+ doStagefrightTestMediaPlayerANR(rid, null, config);
}
public JSONArray getCrashReport(String testname, long timeout)
@@ -1360,7 +1370,7 @@
MediaPlayer.OnPreparedListener,
MediaPlayer.OnCompletionListener {
- boolean checkMinAddress = true;
+ CrashUtils.Config config;
private final Pattern[] validProcessPatterns = {
Pattern.compile("adsprpcd"),
@@ -1384,10 +1394,16 @@
};
MediaPlayerCrashListener() {
+ this(null);
}
- MediaPlayerCrashListener(boolean checkMinAddress) {
- this.checkMinAddress = checkMinAddress;
+ MediaPlayerCrashListener(CrashUtils.Config config) {
+ if (config == null) {
+ config = new CrashUtils.Config();
+ }
+ // if a different process is needed for a test, it should be added to the main list.
+ config.setProcessPatterns(validProcessPatterns);
+ this.config = config;
}
@Override
@@ -1435,8 +1451,7 @@
if (crashes == null) {
Log.e(TAG, "Crash results not found for test " + getName());
return what;
- } else if (CrashUtils.securityCrashDetected(
- crashes, checkMinAddress, validProcessPatterns)) {
+ } else if (CrashUtils.securityCrashDetected(crashes, config)) {
return what;
} else {
Log.i(TAG, "Crash ignored due to no security crash found for test " +
@@ -1484,21 +1499,21 @@
}
private void doStagefrightTestMediaPlayer(final int rid) throws Exception {
- doStagefrightTestMediaPlayer(rid, true); // check crash address by default
+ doStagefrightTestMediaPlayer(rid, null, null);
}
private void doStagefrightTestMediaPlayer(
- final int rid, boolean checkMinCrashAddress) throws Exception {
- doStagefrightTestMediaPlayer(rid, null, checkMinCrashAddress);
+ final int rid, CrashUtils.Config config) throws Exception {
+ doStagefrightTestMediaPlayer(rid, null, config);
}
private void doStagefrightTestMediaPlayer(final String url) throws Exception {
- doStagefrightTestMediaPlayer(url, true); // check crash address by default
+ doStagefrightTestMediaPlayer(url, null);
}
private void doStagefrightTestMediaPlayer(
- final String url, boolean checkMinCrashAddress) throws Exception {
- doStagefrightTestMediaPlayer(-1, url, checkMinCrashAddress);
+ final String url, CrashUtils.Config config) throws Exception {
+ doStagefrightTestMediaPlayer(-1, url, config);
}
private void closeQuietly(AutoCloseable closeable) {
@@ -1513,17 +1528,17 @@
}
private void doStagefrightTestMediaPlayer(final int rid, final String uri) throws Exception {
- doStagefrightTestMediaPlayer(rid, uri, true); // check crash address by default
+ doStagefrightTestMediaPlayer(rid, uri, null);
}
private void doStagefrightTestMediaPlayer(final int rid, final String uri,
- boolean checkMinCrashAddress) throws Exception {
+ CrashUtils.Config config) throws Exception {
String name = uri != null ? uri :
getInstrumentation().getContext().getResources().getResourceEntryName(rid);
Log.i(TAG, "start mediaplayer test for: " + name);
- final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(config);
LooperThread t = new LooperThread(new Runnable() {
@Override
@@ -1644,31 +1659,31 @@
}
private void doStagefrightTestMediaCodec(final int rid) throws Exception {
- doStagefrightTestMediaCodec(rid, true); // check crash address by default
+ doStagefrightTestMediaCodec(rid, null, null);
}
private void doStagefrightTestMediaCodec(
- final int rid, boolean checkMinCrashAddress) throws Exception {
- doStagefrightTestMediaCodec(rid, null, checkMinCrashAddress);
+ final int rid, CrashUtils.Config config) throws Exception {
+ doStagefrightTestMediaCodec(rid, null, config);
}
private void doStagefrightTestMediaCodec(final String url) throws Exception {
- doStagefrightTestMediaCodec(url, true); // check crash address by default
+ doStagefrightTestMediaCodec(url, null);
}
private void doStagefrightTestMediaCodec(
- final String url, boolean checkMinCrashAddress) throws Exception {
- doStagefrightTestMediaCodec(-1, url, checkMinCrashAddress);
+ final String url, CrashUtils.Config config) throws Exception {
+ doStagefrightTestMediaCodec(-1, url, config);
}
private void doStagefrightTestMediaCodec(final int rid, final String url) throws Exception {
- doStagefrightTestMediaCodec(rid, url, true); // check crash address by default
+ doStagefrightTestMediaCodec(rid, url, null);
}
private void doStagefrightTestMediaCodec(
- final int rid, final String url, boolean checkMinCrashAddress) throws Exception {
+ final int rid, final String url, CrashUtils.Config config) throws Exception {
- final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(config);
LooperThread thr = new LooperThread(new Runnable() {
@Override
@@ -1826,31 +1841,31 @@
}
private void doStagefrightTestMediaMetadataRetriever(final int rid) throws Exception {
- doStagefrightTestMediaMetadataRetriever(rid, true); // check crash address by default
+ doStagefrightTestMediaMetadataRetriever(rid, null, null);
}
private void doStagefrightTestMediaMetadataRetriever(
- final int rid, boolean checkMinCrashAddress) throws Exception {
- doStagefrightTestMediaMetadataRetriever(rid, null, checkMinCrashAddress);
+ final int rid, CrashUtils.Config config) throws Exception {
+ doStagefrightTestMediaMetadataRetriever(rid, null, config);
}
private void doStagefrightTestMediaMetadataRetriever(final String url) throws Exception {
- doStagefrightTestMediaMetadataRetriever(url, true); // check crash address by default
+ doStagefrightTestMediaMetadataRetriever(url, null);
}
private void doStagefrightTestMediaMetadataRetriever(
- final String url, boolean checkMinCrashAddress) throws Exception {
- doStagefrightTestMediaMetadataRetriever(-1, url, checkMinCrashAddress);
+ final String url, CrashUtils.Config config) throws Exception {
+ doStagefrightTestMediaMetadataRetriever(-1, url, config);
}
private void doStagefrightTestMediaMetadataRetriever(
final int rid, final String url) throws Exception {
- doStagefrightTestMediaMetadataRetriever(rid, url, true); // check crash address by default
+ doStagefrightTestMediaMetadataRetriever(rid, url, null);
}
private void doStagefrightTestMediaMetadataRetriever(
- final int rid, final String url, boolean checkMinCrashAddress) throws Exception {
+ final int rid, final String url, CrashUtils.Config config) throws Exception {
- final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(config);
LooperThread thr = new LooperThread(new Runnable() {
@Override
@@ -1925,12 +1940,14 @@
@SecurityTest(minPatchLevel = "2017-08")
public void testBug36816007() throws Exception {
- doStagefrightTestRawBlob(R.raw.bug_36816007, "video/avc", 320, 240, false);
+ doStagefrightTestRawBlob(R.raw.bug_36816007, "video/avc", 320, 240,
+ new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-05")
public void testBug36895511() throws Exception {
- doStagefrightTestRawBlob(R.raw.bug_36895511, "video/hevc", 320, 240, false);
+ doStagefrightTestRawBlob(R.raw.bug_36895511, "video/hevc", 320, 240,
+ new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "2017-11")
@@ -1960,7 +1977,8 @@
@SecurityTest(minPatchLevel = "2018-04")
public void testBug_70897394() throws Exception {
- doStagefrightTestRawBlob(R.raw.bug_70897394_avc, "video/avc", 320, 240, false);
+ doStagefrightTestRawBlob(R.raw.bug_70897394_avc, "video/avc", 320, 240,
+ new CrashUtils.Config().checkMinAddress(false));
}
@SecurityTest(minPatchLevel = "Unknown")
@@ -2032,14 +2050,13 @@
private void doStagefrightTestRawBlob(
int rid, String mime, int initWidth, int initHeight) throws Exception {
- // check crash address by default
- doStagefrightTestRawBlob(rid, mime, initWidth, initHeight, true);
+ doStagefrightTestRawBlob(rid, mime, initWidth, initHeight, new CrashUtils.Config());
}
private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight,
- boolean checkMinCrashAddress) throws Exception {
+ CrashUtils.Config config) throws Exception {
- final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(config);
final Context context = getInstrumentation().getContext();
final Resources resources = context.getResources();
@@ -2154,13 +2171,13 @@
private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight,
int frameSizes[]) throws Exception {
// check crash address by default
- doStagefrightTestRawBlob(rid, mime, initWidth, initHeight, frameSizes, true);
+ doStagefrightTestRawBlob(rid, mime, initWidth, initHeight, frameSizes, new CrashUtils.Config());
}
private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight,
- int frameSizes[], boolean checkMinCrashAddress) throws Exception {
+ int frameSizes[], CrashUtils.Config config) throws Exception {
- final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(config);
final Context context = getInstrumentation().getContext();
final Resources resources = context.getResources();
@@ -2294,16 +2311,16 @@
}
private void doStagefrightTestMediaPlayerANR(final int rid, final String uri) throws Exception {
- doStagefrightTestMediaPlayerANR(rid, uri, true); // check crash address by default
+ doStagefrightTestMediaPlayerANR(rid, uri, null);
}
private void doStagefrightTestMediaPlayerANR(final int rid, final String uri,
- boolean checkMinCrashAddress) throws Exception {
+ CrashUtils.Config config) throws Exception {
String name = uri != null ? uri :
getInstrumentation().getContext().getResources().getResourceEntryName(rid);
Log.i(TAG, "start mediaplayerANR test for: " + name);
- final MediaPlayerCrashListener mpl = new MediaPlayerCrashListener(checkMinCrashAddress);
+ final MediaPlayerCrashListener mpl = new MediaPlayerCrashListener(config);
LooperThread t = new LooperThread(new Runnable() {
@Override
@@ -2347,12 +2364,12 @@
}
private void doStagefrightTestExtractorSeek(final int rid, final long offset) throws Exception {
- doStagefrightTestExtractorSeek(rid, offset, true); // check crash address by default
+ doStagefrightTestExtractorSeek(rid, offset, new CrashUtils.Config()); // check crash address by default
}
private void doStagefrightTestExtractorSeek(final int rid, final long offset,
- boolean checkMinCrashAddress) throws Exception {
- final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
+ CrashUtils.Config config) throws Exception {
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(config);
LooperThread thr = new LooperThread(new Runnable() {
@Override
public void run() {
diff --git a/tests/tests/sharesheet/AndroidManifest.xml b/tests/tests/sharesheet/AndroidManifest.xml
index c99b38a..e501caf 100644
--- a/tests/tests/sharesheet/AndroidManifest.xml
+++ b/tests/tests/sharesheet/AndroidManifest.xml
@@ -24,17 +24,45 @@
failure -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <application android:requestLegacyExternalStorage="true">
- <uses-library android:name="android.test.runner" />
+ <application
+ android:requestLegacyExternalStorage="true"
+ android:label="@string/test_app_label">
- <!-- Add activities, services, etc here to test sharesheet API -->
-
- <activity android:name="CtsSharesheetDeviceActivity" >
+ <uses-library android:name="android.test.runner" />
+
+ <activity android:name=".CtsSharesheetDeviceActivity">
+
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
+
+ <intent-filter>
+ <action android:name="android.intent.action.SEND" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:mimeType="test/cts" />
+ </intent-filter>
+
+ <!-- Used to provide Sharing Shortcuts -->
+ <meta-data android:name="android.app.shortcuts"
+ android:resource="@xml/shortcuts"/>
+
+ <meta-data android:name="android.service.chooser.chooser_target_service"
+ android:value=".CtsSharesheetChooserTargetService"/>
+
</activity>
+
+ <service android:name=".CtsSharesheetChooserTargetService"
+ android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.chooser.ChooserTargetService" />
+ </intent-filter>
+ </service>
+
+ <activity-alias android:name=".ExtraInitialIntentTestActivity"
+ android:label="@string/test_extra_initial_intents_label"
+ android:targetActivity=".CtsSharesheetDeviceActivity"/>
+
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/sharesheet/AndroidTest.xml b/tests/tests/sharesheet/AndroidTest.xml
index bac02d8..59a4c97 100644
--- a/tests/tests/sharesheet/AndroidTest.xml
+++ b/tests/tests/sharesheet/AndroidTest.xml
@@ -17,7 +17,8 @@
<configuration description="Config for CTS Sharesheet test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="framework" />
- <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <!-- Instant apps can't access ShortcutManager -->
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<option name="not-shardable" value="true" />
@@ -25,6 +26,9 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsSharesheetTestCases.apk" />
+ <option name="test-file-name" value="CtsSharesheetActivityLabelTester.apk" />
+ <option name="test-file-name" value="CtsSharesheetIntentFilterLabelTester.apk" />
+ <option name="test-file-name" value="CtsSharesheetExcludeTester.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
@@ -38,4 +42,5 @@
<option name="collect-on-run-ended-only" value="true" />
<option name="clean-up" value="false" />
</metrics_collector>
+
</configuration>
diff --git a/tests/tests/sharesheet/OWNERS b/tests/tests/sharesheet/OWNERS
index 47f9b3b..8bea7af 100644
--- a/tests/tests/sharesheet/OWNERS
+++ b/tests/tests/sharesheet/OWNERS
@@ -2,4 +2,5 @@
digman@google.com
asc@google.com
dsandler@google.com
-mpietal@google.com
\ No newline at end of file
+mpietal@google.com
+arangelov@google.com
\ No newline at end of file
diff --git a/tests/tests/sharesheet/packages/Android.bp b/tests/tests/sharesheet/packages/Android.bp
new file mode 100644
index 0000000..12a6838
--- /dev/null
+++ b/tests/tests/sharesheet/packages/Android.bp
@@ -0,0 +1,64 @@
+// Copyright (C) 2020 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.
+
+android_test_helper_app {
+ name: "CtsSharesheetActivityLabelTester",
+ defaults: ["cts_defaults"],
+ srcs: ["packages/src/**/*.java"],
+ // tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+ aaptflags: [
+ "--rename-manifest-package",
+ "android.sharesheet.cts.packages.activitylabeltester",
+ ],
+ manifest: "AndroidManifest-ActivityLabelTester.xml",
+}
+
+android_test_helper_app {
+ name: "CtsSharesheetIntentFilterLabelTester",
+ defaults: ["cts_defaults"],
+ srcs: ["packages/src/**/*.java"],
+ // tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+ aaptflags: [
+ "--rename-manifest-package",
+ "android.sharesheet.cts.packages.intentfilterlabeltester",
+ ],
+ manifest: "AndroidManifest-IntentFilterLabelTester.xml",
+}
+
+android_test_helper_app {
+ name: "CtsSharesheetExcludeTester",
+ defaults: ["cts_defaults"],
+ srcs: ["packages/src/**/*.java"],
+ // tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+ aaptflags: [
+ "--rename-manifest-package",
+ "android.sharesheet.cts.packages.excludetester",
+ ],
+ manifest: "AndroidManifest-ExcludeTester.xml",
+}
\ No newline at end of file
diff --git a/tests/tests/sharesheet/packages/AndroidManifest-ActivityLabelTester.xml b/tests/tests/sharesheet/packages/AndroidManifest-ActivityLabelTester.xml
new file mode 100644
index 0000000..9da4a37
--- /dev/null
+++ b/tests/tests/sharesheet/packages/AndroidManifest-ActivityLabelTester.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2020 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.sharesheet.cts.packages">
+
+ <application android:label="App A">
+
+ <activity android:name=".LabelTestActivity" android:label="Activity A">
+
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ <intent-filter>
+ <action android:name="android.intent.action.SEND" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:mimeType="test/cts" />
+ </intent-filter>
+
+ </activity>
+
+ </application>
+
+</manifest>
+
diff --git a/tests/tests/sharesheet/packages/AndroidManifest-ExcludeTester.xml b/tests/tests/sharesheet/packages/AndroidManifest-ExcludeTester.xml
new file mode 100644
index 0000000..ca2e79e
--- /dev/null
+++ b/tests/tests/sharesheet/packages/AndroidManifest-ExcludeTester.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.sharesheet.cts.packages">
+
+ <application android:label="Bl Label">
+
+ <activity android:name=".LabelTestActivity">
+
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ <intent-filter>
+ <action android:name="android.intent.action.SEND" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:mimeType="test/cts" />
+ </intent-filter>
+
+ </activity>
+
+ </application>
+
+</manifest>
+
diff --git a/tests/tests/sharesheet/packages/AndroidManifest-IntentFilterLabelTester.xml b/tests/tests/sharesheet/packages/AndroidManifest-IntentFilterLabelTester.xml
new file mode 100644
index 0000000..1169b49
--- /dev/null
+++ b/tests/tests/sharesheet/packages/AndroidManifest-IntentFilterLabelTester.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.sharesheet.cts.packages">
+
+ <application android:label="App If">
+
+ <activity android:name=".LabelTestActivity" android:label="Activity If">
+
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ <intent-filter android:label="IntentFilter If">
+ <action android:name="android.intent.action.SEND" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:mimeType="test/cts" />
+ </intent-filter>
+
+ </activity>
+
+ </application>
+
+</manifest>
+
diff --git a/tests/tests/sharesheet/packages/src/android/sharesheet/cts/packages/LabelTestActivity.java b/tests/tests/sharesheet/packages/src/android/sharesheet/cts/packages/LabelTestActivity.java
new file mode 100644
index 0000000..564c269
--- /dev/null
+++ b/tests/tests/sharesheet/packages/src/android/sharesheet/cts/packages/LabelTestActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 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.sharesheet.cts.packages;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+
+import java.lang.Override;
+
+public class LabelTestActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ // This activity may be opened to ensure click behavior functions properly.
+ // To ensure test repeatability do not stay open.
+ finish();
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/sharesheet/res/drawable-nodpi/black_64x64.png b/tests/tests/sharesheet/res/drawable-nodpi/black_64x64.png
new file mode 100644
index 0000000..7cc9373
--- /dev/null
+++ b/tests/tests/sharesheet/res/drawable-nodpi/black_64x64.png
Binary files differ
diff --git a/tests/tests/sharesheet/res/values/strings.xml b/tests/tests/sharesheet/res/values/strings.xml
new file mode 100644
index 0000000..62529b6
--- /dev/null
+++ b/tests/tests/sharesheet/res/values/strings.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ Copyright (C) 2020 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>
+ <!-- All strings are intentionally short to avoid potential issues with truncation -->
+ <string name="test_app_label">App 1</string>
+ <string name="test_activity_label_app">App A</string>
+ <string name="test_activity_label_activity">Activity A</string>
+ <string name="test_intent_filter_label_app">App If</string>
+ <string name="test_intent_filter_label_activity">Activity If</string>
+ <string name="test_intent_filter_label_intentfilter">IntentFilter If</string>
+ <string name="test_blacklist_label">Bl Label</string>
+ <string name="test_chooser_target_service_label">CTS target</string>
+ <string name="test_sharing_shortcut_label">ShS target</string>
+ <string name="test_extra_chooser_targets_label">ECT target</string>
+ <string name="test_extra_initial_intents_label">EII target</string>
+ <string name="test_preview_title">Preview title</string>
+ <string name="test_preview_text">Preview text</string>
+</resources>
diff --git a/tests/tests/sharesheet/res/xml/shortcuts.xml b/tests/tests/sharesheet/res/xml/shortcuts.xml
new file mode 100644
index 0000000..684ebb4
--- /dev/null
+++ b/tests/tests/sharesheet/res/xml/shortcuts.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
+ <share-target android:targetClass="android.sharesheet.cts.CtsSharesheetDeviceActivity">
+ <data android:mimeType="test/cts"/>
+ <category android:name="CATEGORY_CTS_TEST"/>
+ </share-target>
+</shortcuts>
\ No newline at end of file
diff --git a/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetChooserTargetService.java b/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetChooserTargetService.java
new file mode 100644
index 0000000..5fda05f
--- /dev/null
+++ b/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetChooserTargetService.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 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.sharesheet.cts;
+
+import android.content.ComponentName;
+import android.content.IntentFilter;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.service.chooser.ChooserTarget;
+import android.service.chooser.ChooserTargetService;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class CtsSharesheetChooserTargetService extends ChooserTargetService {
+
+ @Override
+ public List<ChooserTarget> onGetChooserTargets(ComponentName componentName,
+ IntentFilter intentFilter) {
+
+ ChooserTarget ct = new ChooserTarget(
+ getString(R.string.test_chooser_target_service_label),
+ Icon.createWithResource(this, R.drawable.black_64x64),
+ 1f,
+ componentName,
+ new Bundle());
+
+ ChooserTarget[] ret = {ct};
+ return Arrays.asList(ret);
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceActivity.java b/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceActivity.java
index 55a7e1b..f22a1cf 100644
--- a/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceActivity.java
+++ b/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceActivity.java
@@ -21,13 +21,13 @@
import java.lang.Override;
-/**
- * TODO: Add JavaDoc.
- */
public class CtsSharesheetDeviceActivity extends Activity {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ // This activity may be opened to ensure click behavior functions properly.
+ // To ensure test repeatability do not stay open.
+ finish();
}
}
\ No newline at end of file
diff --git a/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceTest.java b/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceTest.java
index 1824d96..52bb7bc 100644
--- a/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceTest.java
+++ b/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceTest.java
@@ -15,13 +15,47 @@
*/
package android.sharesheet.cts;
-import android.platform.test.annotations.Presubmit;
+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 androidx.test.rule.ActivityTestRule;
+import android.app.ActivityManager;
+import android.app.Instrumentation;
+import android.app.PendingIntent;
+import android.app.UiAutomation;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.LabeledIntent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.service.chooser.ChooserTarget;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+
+import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.Assert;
-import org.junit.Rule;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,25 +67,522 @@
public static final String TAG = CtsSharesheetDeviceTest.class.getSimpleName();
- @Rule
- public ActivityTestRule<CtsSharesheetDeviceActivity> mActivityRule =
- new ActivityTestRule(CtsSharesheetDeviceActivity.class);
+ private static final int WAIT_AND_ASSERT_FOUND_TIMEOUT_MS = 5000;
+ private static final int WAIT_AND_ASSERT_NOT_FOUND_TIMEOUT_MS = 2500;
+ private static final int WAIT_FOR_IDLE_TIMEOUT_MS = 5000;
+
+ private static final int MAX_EXTRA_INITIAL_INTENTS_SHOWN = 2;
+ private static final int MAX_EXTRA_CHOOSER_TARGETS_SHOWN = 2;
+
+ private static final String ACTION_INTENT_SENDER_FIRED_ON_CLICK =
+ "android.sharesheet.cts.ACTION_INTENT_SENDER_FIRED_ON_CLICK";
+
+ static final String CTS_DATA_TYPE = "test/cts"; // Special CTS mime type
+ static final String CATEGORY_CTS_TEST = "CATEGORY_CTS_TEST";
+
+ private Context mContext;
+ private Instrumentation mInstrumentation;
+ private UiAutomation mAutomation;
+ public UiDevice mDevice;
+
+ private String mPkg, mExcludePkg, mActivityLabelTesterPkg, mIntentFilterLabelTesterPkg;
+ private String mSharesheetPkg;
+
+ private ActivityManager mActivityManager;
+ private ShortcutManager mShortcutManager;
+
+ private String mAppLabel,
+ mActivityTesterAppLabel, mActivityTesterActivityLabel,
+ mIntentFilterTesterAppLabel, mIntentFilterTesterActivityLabel,
+ mIntentFilterTesterIntentFilterLabel,
+ mBlacklistLabel,
+ mChooserTargetServiceLabel, mSharingShortcutLabel, mExtraChooserTargetsLabelBase,
+ mExtraInitialIntentsLabelBase, mPreviewTitle, mPreviewText;
+
+ private Set<ComponentName> mTargetsToExclude;
/**
- * TODO: Add JavaDoc
- * This test runs on presubmit
+ * To validate Sharesheet API and API behavior works as intended UI test sare required. It is
+ * impossible to know the how the Sharesheet UI will be modified by end partners so these tests
+ * attempt to assume use the minimum needed assumptions to make the tests work.
+ *
+ * We cannot assume a scrolling direction or starting point because of potential UI variations.
+ * Because of limits of the UiAutomator pipeline only content visible on screen can be tested.
+ * These two constraints mean that all automated Sharesheet tests must be for content we
+ * reasonably expect to be visible after the sheet is opened without any direct interaction.
+ *
+ * Extra care is taken to ensure tested content is reasonably visible by:
+ * - Splitting tests across multiple Sharesheet calls
+ * - Excluding all packages not relevant to the test
+ * - Assuming a max of three targets per row of apps
*/
- @Presubmit
- @Test
- public void foo() throws Exception {
- Assert.assertNotNull(mActivityRule.getActivity());
+
+ @Before
+ public void init() throws Exception {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mContext = mInstrumentation.getTargetContext();
+ mPkg = mContext.getPackageName();
+ mExcludePkg = mPkg + ".packages.excludetester";
+ mActivityLabelTesterPkg = mPkg + ".packages.activitylabeltester";
+ mIntentFilterLabelTesterPkg = mPkg + ".packages.intentfilterlabeltester";
+
+ mDevice = UiDevice.getInstance(mInstrumentation);
+ mAutomation = mInstrumentation.getUiAutomation();
+
+ mActivityManager = mContext.getSystemService(ActivityManager.class);
+ mShortcutManager = mContext.getSystemService(ShortcutManager.class);
+ PackageManager pm = mContext.getPackageManager();
+ assertNotNull(mActivityManager);
+ assertNotNull(mShortcutManager);
+ assertNotNull(pm);
+
+ // Load in string to match against
+ mBlacklistLabel = mContext.getString(R.string.test_blacklist_label);
+ mAppLabel = mContext.getString(R.string.test_app_label);
+ mActivityTesterAppLabel = mContext.getString(R.string.test_activity_label_app);
+ mActivityTesterActivityLabel = mContext.getString(R.string.test_activity_label_activity);
+ mIntentFilterTesterAppLabel = mContext.getString(R.string.test_intent_filter_label_app);
+ mIntentFilterTesterActivityLabel =
+ mContext.getString(R.string.test_intent_filter_label_activity);
+ mIntentFilterTesterIntentFilterLabel =
+ mContext.getString(R.string.test_intent_filter_label_intentfilter);
+ mChooserTargetServiceLabel = mContext.getString(R.string.test_chooser_target_service_label);
+ mSharingShortcutLabel = mContext.getString(R.string.test_sharing_shortcut_label);
+ mExtraChooserTargetsLabelBase = mContext.getString(R.string.test_extra_chooser_targets_label);
+ mExtraInitialIntentsLabelBase = mContext.getString(R.string.test_extra_initial_intents_label);
+ mPreviewTitle = mContext.getString(R.string.test_preview_title);
+ mPreviewText = mContext.getString(R.string.test_preview_text);
+
+ // We want to only show targets in the sheet put forth by the CTS test. In order to do that
+ // a special type is used but this doesn't prevent apps registered against */* from showing.
+ // To hide */* targets, search for all matching targets and exclude them.
+ List<ResolveInfo> matchingTargets = mContext.getPackageManager().queryIntentActivities(
+ createMatchingIntent(),
+ PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA
+ );
+
+ mTargetsToExclude = matchingTargets.stream()
+ .map(ri -> {
+ return new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name);
+ })
+ .filter(cn -> {
+ // Exclude our own test targets
+ String pkg = cn.getPackageName();
+ boolean isInternalPkg = pkg.equals(mPkg) ||
+ pkg.equals(mActivityLabelTesterPkg) ||
+ pkg.equals(mIntentFilterLabelTesterPkg);
+
+ return !isInternalPkg;
+ })
+ .collect(Collectors.toSet());
+
+ // We need to know the package used by the system Sharesheet so we can properly
+ // wait for the UI to load. Do this by resolving which activity consumes the share intent.
+ // There must be a system Sharesheet or fail, otherwise fetch its the package.
+ Intent shareIntent = createShareIntent(false, 0, 0);
+ ResolveInfo shareRi = pm.resolveActivity(shareIntent, PackageManager.MATCH_DEFAULT_ONLY);
+
+ assertNotNull(shareRi);
+ assertNotNull(shareRi.activityInfo);
+
+ mSharesheetPkg = shareRi.activityInfo.packageName;
+ assertNotNull(mSharesheetPkg);
+
+ // Finally ensure the device is awake
+ mDevice.wakeUp();
}
/**
- * TODO: Add JavaDoc
+ * To test all features the Sharesheet will need to be opened and closed a few times. To keep
+ * total run time low, jam as many tests are possible into each visible test portion.
*/
@Test
- public void bar() throws Exception {
- Assert.assertTrue(true);
+ public void bulkTest1() {
+ try {
+ launchSharesheet(createShareIntent(true /* test content preview */,
+ 0 /* do not test EIIs */,
+ 0 /* do not test ECTs */));
+
+ doesExcludeComponents();
+ showsApplicationLabel();
+ showsAppAndActivityLabel();
+ showsAppAndIntentFilterLabel();
+ showsContentPreviewTitle();
+ showsContentPreviewText();
+ isChooserTargetServiceDirectShareEnabled();
+
+ // Must be run last, partial completion closes the Sharesheet
+ firesIntentSenderWithExtraChosenComponent();
+
+ } catch (Exception e) {
+ // No-op
+ } finally {
+ // The Sharesheet may or may not be open depending on test success, close it if it is
+ closeSharesheetIfNeeded();
+ }
+ }
+
+ @Test
+ public void bulkTest2() {
+ try {
+ addShortcuts(1);
+ launchSharesheet(createShareIntent(false /* do not test preview */,
+ MAX_EXTRA_INITIAL_INTENTS_SHOWN + 1 /* test EIIs at 1 above cap */,
+ MAX_EXTRA_CHOOSER_TARGETS_SHOWN + 1 /* test ECTs at 1 above cap */));
+ // Note: EII and ECT cap is not tested here
+
+ showsExtraInitialIntents();
+ showsExtraChooserTargets();
+ isSharingShortcutDirectShareEnabled();
+
+ } catch (Exception e) {
+ // No-op
+ } finally {
+ closeSharesheet();
+ clearShortcuts();
+ }
+ }
+
+ /*
+ Test methods
+ */
+
+ /**
+ * Tests API compliance for Intent.EXTRA_EXCLUDE_COMPONENTS. This test is necessary for other
+ * tests to run as expected.
+ */
+ public void doesExcludeComponents() {
+ // The excluded component should not be found on screen
+ waitAndAssertNoTextContains(mBlacklistLabel);
+ }
+
+ /**
+ * Tests API behavior compliance for security to always show application label
+ */
+ public void showsApplicationLabel() {
+ // For each app target the providing app's application manifest label should be shown
+ waitAndAssertTextContains(mAppLabel);
+ }
+
+ /**
+ * Tests API behavior compliance to show application and activity label when available
+ */
+ public void showsAppAndActivityLabel() {
+ waitAndAssertTextContains(mActivityTesterAppLabel);
+ waitAndAssertTextContains(mActivityTesterActivityLabel);
+ }
+
+ /**
+ * Tests API behavior compliance to show application and intent filter label when available
+ */
+ public void showsAppAndIntentFilterLabel() {
+ // NOTE: it is not necessary to show any set Activity label if an IntentFilter label is set
+ waitAndAssertTextContains(mIntentFilterTesterAppLabel);
+ waitAndAssertTextContains(mIntentFilterTesterIntentFilterLabel);
+ }
+
+ /**
+ * Tests API compliance for Intent.EXTRA_INITIAL_INTENTS
+ */
+ public void showsExtraInitialIntents() {
+ // Should show extra initial intents but must limit them, can't test limit here
+ waitAndAssertTextContains(mExtraInitialIntentsLabelBase);
+ }
+
+ /**
+ * Tests API compliance for Intent.EXTRA_CHOOSER_TARGETS
+ */
+ public void showsExtraChooserTargets() {
+ // Should show chooser targets but must limit them, can't test limit here
+ waitAndAssertTextContains(mExtraChooserTargetsLabelBase);
+ }
+
+ /**
+ * Tests API behavior compliance for Intent.EXTRA_TITLE
+ */
+ public void showsContentPreviewTitle() {
+ waitAndAssertTextContains(mPreviewTitle);
+ }
+
+ /**
+ * Tests API behavior compliance for Intent.EXTRA_TEXT
+ */
+ public void showsContentPreviewText() {
+ waitAndAssertTextContains(mPreviewText);
+ }
+
+ /**
+ * Tests API compliance for Intent.EXTRA_CHOSEN_COMPONENT_INTENT_SENDER and related APIs
+ * UI assumption: target labels are clickable, clicking opens target
+ */
+ public void firesIntentSenderWithExtraChosenComponent() throws Exception {
+ // To receive the extra chosen component a target must be clicked. Clicking the target
+ // will close the Sharesheet. Run this last in any sequence of tests.
+
+ // First find the target to click. This will fail if the showsApplicationLabel() test fails.
+ UiObject2 shareTarget = findTextContains(mAppLabel);
+ assertNotNull(shareTarget);
+
+ ComponentName clickedComponent = new ComponentName(mContext,
+ CtsSharesheetDeviceActivity.class);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ final Intent[] response = {null}; // Must be final so use an array
+
+ // Listen for the PendingIntent broadcast on click
+ BroadcastReceiver br = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ response[0] = intent;
+ latch.countDown();
+ }
+ };
+ mContext.registerReceiver(br, new IntentFilter(ACTION_INTENT_SENDER_FIRED_ON_CLICK));
+
+ // Start the event sequence and wait for results
+ shareTarget.click();
+
+ // The latch may fail for a number of reasons but we still need to unregister the
+ // BroadcastReceiver, so capture and rethrow any errors.
+ Exception delayedException = null;
+ try {
+ latch.await(1000, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ delayedException = e;
+ } finally {
+ mContext.unregisterReceiver(br);
+ }
+ if (delayedException != null) throw delayedException;
+
+ // Finally validate the received Intent
+ validateChosenComponentIntent(response[0], clickedComponent);
+ }
+
+ private void validateChosenComponentIntent(Intent intent, ComponentName matchingComponent) {
+ assertNotNull(intent);
+
+ assertTrue(intent.hasExtra(Intent.EXTRA_CHOSEN_COMPONENT));
+ Object extra = intent.getParcelableExtra(Intent.EXTRA_CHOSEN_COMPONENT);
+ assertNotNull(extra);
+
+ assertTrue(extra instanceof ComponentName);
+ ComponentName component = (ComponentName) extra;
+
+ assertEquals(component, matchingComponent);
+ }
+
+ /**
+ * Tests API behavior compliance for ChooserTargetService
+ */
+ public void isChooserTargetServiceDirectShareEnabled() {
+ // ChooserTargets can take time to load. To account for this:
+ // * All non-test ChooserTargetServices shouldn't be loaded because of blacklist
+ // * waitAndAssert operations have lengthy timeout periods
+ // * Last time to run in suite so prior operations reduce wait time
+
+ if (mActivityManager.isLowRamDevice()) {
+ // Ensure direct share is disabled on low ram devices
+ waitAndAssertNoTextContains(mChooserTargetServiceLabel);
+ } else {
+ // Ensure direct share is enabled
+ waitAndAssertTextContains(mChooserTargetServiceLabel);
+ }
+ }
+
+ /**
+ * Tests API behavior compliance for Sharing Shortcuts
+ */
+ public void isSharingShortcutDirectShareEnabled() {
+ if (mActivityManager.isLowRamDevice()) {
+ // Ensure direct share is disabled on low ram devices
+ waitAndAssertNoTextContains(mSharingShortcutLabel);
+ } else {
+ // Ensure direct share is enabled
+ waitAndAssertTextContains(mSharingShortcutLabel);
+ }
+ }
+
+ /*
+ Setup methods
+ */
+
+ public void addShortcuts(int size) {
+ mShortcutManager.addDynamicShortcuts(createShortcuts(size));
+ }
+
+ public void clearShortcuts() {
+ mShortcutManager.removeAllDynamicShortcuts();
+ }
+
+ private List<ShortcutInfo> createShortcuts(int size) {
+ List<ShortcutInfo> ret = new ArrayList<>();
+ for (int i=0; i<size; i++) {
+ ret.add(createShortcut(""+i));
+ }
+ return ret;
+ }
+
+ private ShortcutInfo createShortcut(String id) {
+ HashSet<String> categories = new HashSet<>();
+ categories.add(CATEGORY_CTS_TEST);
+
+ return new ShortcutInfo.Builder(mContext, id)
+ .setShortLabel(mSharingShortcutLabel)
+ .setIcon(Icon.createWithResource(mContext, R.drawable.black_64x64))
+ .setCategories(categories)
+ .setIntent(new Intent(Intent.ACTION_DEFAULT)) /* an Intent with an action must be set */
+ .build();
+ }
+
+ private void launchSharesheet(Intent shareIntent) {
+ mContext.startActivity(shareIntent);
+ waitAndAssertPkgVisible(mSharesheetPkg);
+ waitForIdle();
+ }
+
+ private void closeSharesheetIfNeeded() {
+ if (isSharesheetVisible()) closeSharesheet();
+ }
+
+ private void closeSharesheet() {
+ mDevice.pressBack();
+ waitAndAssertPkgNotVisible(mSharesheetPkg);
+ waitForIdle();
+ }
+
+ private boolean isSharesheetVisible() {
+ // This method intentionally does not wait, looks to see if visible on method call
+ return mDevice.findObject(By.pkg(mSharesheetPkg).depth(0)) != null;
+ }
+
+ private Intent createMatchingIntent() {
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType(CTS_DATA_TYPE);
+ return intent;
+ }
+
+ private Intent createShareIntent(boolean contentPreview,
+ int numExtraInitialIntents,
+ int numExtraChooserTargets) {
+
+ Intent intent = createMatchingIntent();
+
+ if (contentPreview) {
+ intent.putExtra(Intent.EXTRA_TITLE, mPreviewTitle);
+ intent.putExtra(Intent.EXTRA_TEXT, mPreviewText);
+ }
+
+ PendingIntent pi = PendingIntent.getBroadcast(
+ mContext,
+ 9384 /* number not relevant */ ,
+ new Intent(ACTION_INTENT_SENDER_FIRED_ON_CLICK),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ Intent shareIntent = Intent.createChooser(intent, null, pi.getIntentSender());
+
+ // Intent.EXTRA_EXCLUDE_COMPONENTS is used to ensure only test targets appear
+ List<ComponentName> list = new ArrayList<>(mTargetsToExclude);
+ list.add(new ComponentName(mPkg, mPkg + ".BlacklistTestActivity"));
+ shareIntent.putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS,
+ list.toArray(new ComponentName[0]));
+
+ if (numExtraInitialIntents > 0) {
+ Intent[] eiis = new Intent[numExtraInitialIntents];
+ for (int i = 0; i < eiis.length; i++) {
+ Intent eii = new Intent();
+ eii.setComponent(new ComponentName(mPkg,
+ mPkg + ".ExtraInitialIntentTestActivity"));
+
+ LabeledIntent labeledEii = new LabeledIntent(eii, mPkg,
+ getExtraInitialIntentsLabel(i),
+ 0 /* provide no icon */);
+
+ eiis[i] = labeledEii;
+ }
+
+ shareIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, eiis);
+ }
+
+ if (numExtraChooserTargets > 0) {
+ ChooserTarget[] ects = new ChooserTarget[numExtraChooserTargets];
+ for (int i = 0; i < ects.length; i++) {
+ ects[i] = new ChooserTarget(
+ getExtraChooserTargetLabel(i),
+ Icon.createWithResource(mContext, R.drawable.black_64x64),
+ 1f,
+ new ComponentName(mPkg, mPkg + ".CtsSharesheetDeviceActivity"),
+ new Bundle());
+ }
+
+ shareIntent.putExtra(Intent.EXTRA_CHOOSER_TARGETS, ects);
+ }
+
+ // Ensure the sheet will launch directly from the test
+ shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ return shareIntent;
+ }
+
+ private String getExtraChooserTargetLabel(int position) {
+ return mExtraChooserTargetsLabelBase + " " + position;
+ }
+
+ private String getExtraInitialIntentsLabel(int position) {
+ return mExtraInitialIntentsLabelBase + " " + position;
+ }
+
+ /*
+ UI testing methods
+ */
+
+ private void waitForIdle() {
+ mDevice.waitForIdle(WAIT_FOR_IDLE_TIMEOUT_MS);
+ }
+
+ private void waitAndAssertPkgVisible(String pkg) {
+ waitAndAssertFound(By.pkg(pkg).depth(0));
+ }
+
+ private void waitAndAssertPkgNotVisible(String pkg) {
+ waitAndAssertNotFound(By.pkg(pkg));
+ }
+
+ private void waitAndAssertTextContains(String containsText) {
+ waitAndAssertFound(By.textContains(containsText));
+ }
+
+ private void waitAndAssertNoTextContains(String containsText) {
+ waitAndAssertNotFound(By.textContains(containsText));
+ }
+
+ /**
+ * waitAndAssertFound will wait until UI defined by the selector is found. If it's never found,
+ * this will wait for the duration of the full timeout. Take care to call this method after
+ * reasonable steps are taken to ensure fast completion.
+ */
+ private void waitAndAssertFound(BySelector selector) {
+ assertNotNull(mDevice.wait(Until.findObject(selector), WAIT_AND_ASSERT_FOUND_TIMEOUT_MS));
+ }
+
+ /**
+ * waitAndAssertNotFound waits for any visible UI to be hidden, validates that it's indeed gone
+ * without waiting more and returns. This means if the UI wasn't visible to start with the
+ * method will return without no timeout. Take care to call this method only once there's reason
+ * to think the UI is in the right state for testing.
+ */
+ private void waitAndAssertNotFound(BySelector selector) {
+ mDevice.wait(Until.gone(selector), WAIT_AND_ASSERT_NOT_FOUND_TIMEOUT_MS);
+ assertNull(mDevice.findObject(selector));
+ }
+
+ /**
+ * findTextContains uses logic similar to waitAndAssertFound to locate UI objects that contain
+ * the provided String.
+ * @param containsText the String to search for, note this is not an exact match only contains
+ * @return UiObject2 that can be used, for example, to execute a click
+ */
+ private UiObject2 findTextContains(String containsText) {
+ return mDevice.wait(Until.findObject(By.textContains(containsText)),
+ WAIT_AND_ASSERT_FOUND_TIMEOUT_MS);
}
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/BasicInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/BasicInCallServiceTest.java
index ef20d33..75b9372 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BasicInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BasicInCallServiceTest.java
@@ -18,16 +18,23 @@
import static android.telecom.cts.TestUtils.shouldTestTelecom;
-import android.telecom.cts.MockInCallService.InCallServiceCallbacks;
-
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.telecom.Call;
import android.telecom.InCallService;
+import android.telecom.TelecomManager;
+import android.telecom.cts.MockInCallService.InCallServiceCallbacks;
import android.test.InstrumentationTestCase;
import android.text.TextUtils;
+import com.android.compatibility.common.util.CddTest;
+
+import org.junit.Test;
+
+import java.util.List;
import java.util.concurrent.TimeUnit;
/**
@@ -56,6 +63,32 @@
super.tearDown();
}
+ @CddTest(requirement = "7.4.1.2/C-1-3")
+ public void testResolveInCallIntent() {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+ PackageManager packageManager = mContext.getPackageManager();
+ Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE);
+ List<ResolveInfo> resolveInfo = packageManager.queryIntentServices(serviceIntent,
+ PackageManager.GET_META_DATA);
+
+ assertNotNull(resolveInfo);
+ assertTrue(resolveInfo.size() >= 1);
+
+ // Ensure at least one InCallService is able to handle the UI for calls.
+ assertTrue(resolveInfo
+ .stream()
+ .filter(r -> r.serviceInfo != null
+ && r.serviceInfo.metaData != null
+ && r.serviceInfo.metaData.containsKey(
+ TelecomManager.METADATA_IN_CALL_SERVICE_UI)
+ && r.serviceInfo.permission.equals(
+ android.Manifest.permission.BIND_INCALL_SERVICE)
+ && r.serviceInfo.name != null)
+ .count() >= 1);
+ }
+
/**
* Tests that when sending a CALL intent via the Telecom -> Telephony stack, Telecom
* binds to the registered {@link InCallService}s and adds a new call. This test will
diff --git a/tests/tests/telecom4/Android.mk b/tests/tests/telecom4/Android.mk
deleted file mode 100644
index 2fc8558..0000000
--- a/tests/tests/telecom4/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- ctstestrunner-axt \
- compatibility-device-util-axt
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsTelecom4TestCases
-LOCAL_SDK_VERSION := current
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_JAVA_LIBRARIES += android.test.runner.stubs
-LOCAL_JAVA_LIBRARIES += android.test.base.stubs
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/telecom4/AndroidManifest.xml b/tests/tests/telecom4/AndroidManifest.xml
deleted file mode 100644
index a887fdf..0000000
--- a/tests/tests/telecom4/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.telecom4.cts">
-
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.telecom4.cts">
- <meta-data android:name="listener"
- android:value="com.android.cts.runner.CtsTestRunListener" />
- </instrumentation>
-
-</manifest>
-
diff --git a/tests/tests/telecom4/AndroidTest.xml b/tests/tests/telecom4/AndroidTest.xml
deleted file mode 100644
index c88f8a6..0000000
--- a/tests/tests/telecom4/AndroidTest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-<configuration description="Config for CTS Telecom test cases">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="telecom" />
- <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
- <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
- <option name="not-shardable" value="true" />
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="CtsTelecom4TestCases.apk" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.telecom4.cts" />
- <option name="runtime-hint" value="7m30s" />
- </test>
-</configuration>
diff --git a/tests/tests/telecom4/OWNERS b/tests/tests/telecom4/OWNERS
deleted file mode 100644
index 93fe555..0000000
--- a/tests/tests/telecom4/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 20868
-
diff --git a/tests/tests/telecom4/src/android/telecom4/cts/InCallServiceImplTest.java b/tests/tests/telecom4/src/android/telecom4/cts/InCallServiceImplTest.java
deleted file mode 100644
index 0e68c64..0000000
--- a/tests/tests/telecom4/src/android/telecom4/cts/InCallServiceImplTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telecom4.cts;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.compatibility.common.util.CddTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Build, install and run the tests by running the commands below:
- * make CtsTelecom4TestCases -j64
- * cts-tradefed run cts -m CtsTelecom4TestCases --test android.telecom4.cts.InCallServiceImplTest
- */
-@RunWith(AndroidJUnit4.class)
-public class InCallServiceImplTest {
- private static final String TAG = "InCallServiceTest";
- private static final String IN_CALL_SERVICE_ACTION = "android.telecom.InCallService";
- private static final String IN_CALL_SERVICE_PERMISSION =
- "android.permission.BIND_INCALL_SERVICE";
-
- private Context mContext;
- private PackageManager mPackageManager;
-
- @Before
- public void setup() {
- mContext = InstrumentationRegistry.getContext();
- mPackageManager = mContext.getPackageManager();
- }
-
- @CddTest(requirement = "7.4.1.2/C-1-3")
- @Test
- public void resolveInCallIntent() {
- if (!hasTelephonyFeature()) {
- Log.d(TAG, "Bypass the test since telephony is not available.");
- return;
- }
-
- Intent intent = new Intent();
- intent.setAction(IN_CALL_SERVICE_ACTION);
- ResolveInfo resolveInfo = mPackageManager.resolveService(intent,
- PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
-
- assertNotNull(resolveInfo);
- assertNotNull(resolveInfo.serviceInfo);
- assertNotNull(resolveInfo.serviceInfo.packageName);
- assertNotNull(resolveInfo.serviceInfo.name);
- assertEquals(IN_CALL_SERVICE_PERMISSION, resolveInfo.serviceInfo.permission);
- }
-
- private boolean hasTelephonyFeature() {
- return mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
- }
-}
diff --git a/tests/tests/telephony/current/preconditions/app/AndroidManifest.xml b/tests/tests/telephony/current/preconditions/app/AndroidManifest.xml
index f84d1ec..9001092 100644
--- a/tests/tests/telephony/current/preconditions/app/AndroidManifest.xml
+++ b/tests/tests/telephony/current/preconditions/app/AndroidManifest.xml
@@ -18,6 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.telephony.cts.preconditions.app">
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
<application>
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java
index 92cd25b..3c95139 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java
@@ -137,6 +137,23 @@
assertEquals("KEY_CARRIER_VVM_PACKAGE_NAME_STRING doesn't match static default.",
config.getString(CarrierConfigManager.KEY_CARRIER_VVM_PACKAGE_NAME_STRING), "");
assertFalse(CarrierConfigManager.isConfigForIdentifiedCarrier(config));
+
+ // Check default value matching
+ assertEquals("KEY_DATA_LIMIT_NOTIFICATION_BOOL doesn't match static default.",
+ config.getBoolean(CarrierConfigManager.KEY_DATA_LIMIT_NOTIFICATION_BOOL),
+ true);
+ assertEquals("KEY_DATA_RAPID_NOTIFICATION_BOOL doesn't match static default.",
+ config.getBoolean(CarrierConfigManager.KEY_DATA_RAPID_NOTIFICATION_BOOL),
+ true);
+ assertEquals("KEY_DATA_WARNING_NOTIFICATION_BOOL doesn't match static default.",
+ config.getBoolean(CarrierConfigManager.KEY_DATA_WARNING_NOTIFICATION_BOOL),
+ true);
+ assertEquals("Gps.KEY_PERSIST_LPP_MODE_BOOL doesn't match static default.",
+ config.getBoolean(CarrierConfigManager.Gps.KEY_PERSIST_LPP_MODE_BOOL),
+ true);
+ assertEquals("KEY_MONTHLY_DATA_CYCLE_DAY_INT doesn't match static default.",
+ config.getInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT),
+ CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT);
}
// These key should return default values if not customized.
@@ -150,6 +167,12 @@
CarrierConfigManager.KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY));
assertNotNull(config.getIntArray(
CarrierConfigManager.KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY));
+
+ // Check the GPS key prefix
+ assertTrue("Gps.KEY_PREFIX doesn't match the prefix of the name of "
+ + "Gps.KEY_PERSIST_LPP_MODE_BOOL",
+ CarrierConfigManager.Gps.KEY_PERSIST_LPP_MODE_BOOL.startsWith(
+ CarrierConfigManager.Gps.KEY_PREFIX));
}
@Test
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/PhoneStateListenerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/PhoneStateListenerTest.java
index 32d18de..864cbac 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/PhoneStateListenerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/PhoneStateListenerTest.java
@@ -51,7 +51,6 @@
import androidx.test.InstrumentationRegistry;
import com.android.compatibility.common.util.ShellIdentityUtils;
-import com.android.compatibility.common.util.TestThread;
import org.junit.After;
import org.junit.Before;
@@ -59,9 +58,7 @@
import java.util.Arrays;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
public class PhoneStateListenerTest {
@@ -103,6 +100,8 @@
private final Object mLock = new Object();
private static final String TAG = "android.telephony.cts.PhoneStateListenerTest";
private static ConnectivityManager mCm;
+ private HandlerThread mHandlerThread;
+ private Handler mHandler;
private static final List<Integer> DATA_CONNECTION_STATE = Arrays.asList(
TelephonyManager.DATA_CONNECTED,
TelephonyManager.DATA_DISCONNECTED,
@@ -135,6 +134,9 @@
mTelephonyManager =
(TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE);
mCm = (ConnectivityManager)getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+ mHandlerThread = new HandlerThread("PhoneStateListenerTest");
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
}
@After
@@ -143,6 +145,9 @@
// unregister the listener
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE);
}
+ if (mHandlerThread != null) {
+ mHandlerThread.quitSafely();
+ }
}
@Test
@@ -156,11 +161,6 @@
new PhoneStateListener();
}
- /*
- * The tests below rely on the framework to immediately call the installed listener upon
- * registration. There is no simple way to emulate state changes for testing the listeners.
- */
-
@Test
public void testOnServiceStateChanged() throws Throwable {
if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
@@ -168,34 +168,26 @@
return;
}
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onServiceStateChanged(ServiceState serviceState) {
- synchronized(mLock) {
- mOnServiceStateChangedCalled = true;
- mLock.notify();
- }
- }
- };
- mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SERVICE_STATE);
-
- Looper.loop();
- }
- });
-
assertFalse(mOnServiceStateChangedCalled);
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onServiceStateChanged(ServiceState serviceState) {
+ synchronized (mLock) {
+ mOnServiceStateChangedCalled = true;
+ mLock.notify();
+ }
+ }
+ };
+ mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SERVICE_STATE);
+ });
synchronized (mLock) {
if (!mOnServiceStateChangedCalled){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertTrue(mOnServiceStateChangedCalled);
}
@@ -206,34 +198,26 @@
return;
}
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onServiceStateChanged(ServiceState serviceState) {
- synchronized(mLock) {
- mOnServiceStateChangedCalled = true;
- mLock.notify();
- }
- }
- };
- mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SERVICE_STATE);
-
- Looper.loop();
- }
- });
-
assertFalse(mOnServiceStateChangedCalled);
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onServiceStateChanged(ServiceState serviceState) {
+ synchronized (mLock) {
+ mOnServiceStateChangedCalled = true;
+ mLock.notify();
+ }
+ }
+ };
+ mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SERVICE_STATE);
+ });
synchronized (mLock) {
if (!mOnServiceStateChangedCalled){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertTrue(mOnServiceStateChangedCalled);
// reset and un-register
@@ -256,7 +240,7 @@
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertTrue(mOnServiceStateChangedCalled);
}
@@ -267,37 +251,33 @@
return;
}
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onSignalStrengthChanged(int asu) {
- synchronized(mLock) {
- mOnSignalStrengthChangedCalled = true;
- mLock.notify();
- }
- }
- };
- mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTH);
-
- Looper.loop();
- }
- });
-
assertFalse(mOnSignalStrengthChangedCalled);
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onSignalStrengthChanged(int asu) {
+ synchronized (mLock) {
+ mOnSignalStrengthChangedCalled = true;
+ mLock.notify();
+ }
+ }
+ };
+ mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTH);
+ });
synchronized (mLock) {
if (!mOnSignalStrengthChangedCalled){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertTrue(mOnSignalStrengthChangedCalled);
}
+ /**
+ * Due to the corresponding API is hidden in R and will be public in S, this test
+ * is commented and will be un-commented in Android S.
+ *
@Test
public void testOnAlwaysReportedSignalStrengthChanged() throws Throwable {
if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
@@ -305,38 +285,29 @@
return;
}
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onSignalStrengthsChanged(SignalStrength signalStrength) {
- synchronized (mLock) {
- mSignalStrength = signalStrength;
- mLock.notify();
- }
- }
- };
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.listen(mListener,
- PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH));
-
- Looper.loop();
- }
- });
-
assertTrue(mSignalStrength == null);
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+ synchronized (mLock) {
+ mSignalStrength = signalStrength;
+ mLock.notify();
+ }
+ }
+ };
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ (tm) -> tm.listen(mListener,
+ PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH));
+ });
synchronized (mLock) {
if (mSignalStrength == null) {
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
- assertTrue(mSignalStrength != null);
+ assertTrue(mSignalStrength != null);
// Call SignalStrength methods to make sure they do not throw any exceptions
mSignalStrength.getCdmaDbm();
mSignalStrength.getCdmaEcio();
@@ -348,12 +319,16 @@
mSignalStrength.isGsm();
mSignalStrength.getLevel();
}
+ */
/**
+ * Due to the corresponding API is hidden in R and will be public in S, this test
+ * is commented and will be un-commented in Android S.
+ *
* Validate that SecurityException should be thrown when listen
* with LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH without LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH
* permission.
- */
+ *
@Test
public void testOnAlwaysReportedSignalStrengthChangedWithoutPermission() throws Throwable {
if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
@@ -361,41 +336,38 @@
return;
}
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
+ assertTrue(mSignalStrength == null);
- mListener = new PhoneStateListener() {
- @Override
- public void onSignalStrengthsChanged(SignalStrength signalStrength) {
- synchronized (mLock) {
- mSignalStrength = signalStrength;
- mLock.notify();
- }
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+ synchronized (mLock) {
+ mSignalStrength = signalStrength;
+ mLock.notify();
}
- };
- try {
- mTelephonyManager.listen(mListener,
- PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH);
- } catch (SecurityException se) {
+ }
+ };
+ try {
+ mTelephonyManager.listen(mListener,
+ PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH);
+ } catch (SecurityException se) {
+ synchronized (mLock) {
mSecurityExceptionThrown = true;
mLock.notify();
}
- Looper.loop();
}
});
-
- assertTrue(mSignalStrength == null);
- t.start();
-
synchronized (mLock) {
if (!mSecurityExceptionThrown) {
mLock.wait(WAIT_TIME);
}
}
+
assertThat(mSecurityExceptionThrown).isTrue();
assertTrue(mSignalStrength == null);
}
+ */
@Test
public void testOnSignalStrengthsChanged() throws Throwable {
@@ -403,37 +375,27 @@
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
-
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onSignalStrengthsChanged(SignalStrength signalStrength) {
- synchronized(mLock) {
- mSignalStrength = signalStrength;
- mLock.notify();
- }
- }
- };
- mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
-
- Looper.loop();
- }
- });
-
assertTrue(mSignalStrength == null);
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+ synchronized (mLock) {
+ mSignalStrength = signalStrength;
+ mLock.notify();
+ }
+ }
+ };
+ mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
+ });
synchronized (mLock) {
if (mSignalStrength == null) {
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
- assertTrue(mSignalStrength != null);
+ assertTrue(mSignalStrength != null);
// Call SignalStrength methods to make sure they do not throw any exceptions
mSignalStrength.getCdmaDbm();
mSignalStrength.getCdmaEcio();
@@ -452,127 +414,94 @@
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
-
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onMessageWaitingIndicatorChanged(boolean mwi) {
- synchronized(mLock) {
- mOnMessageWaitingIndicatorChangedCalled = true;
- mLock.notify();
- }
- }
- };
- mTelephonyManager.listen(
- mListener, PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR);
-
- Looper.loop();
- }
- });
-
assertFalse(mOnMessageWaitingIndicatorChangedCalled);
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onMessageWaitingIndicatorChanged(boolean mwi) {
+ synchronized (mLock) {
+ mOnMessageWaitingIndicatorChangedCalled = true;
+ mLock.notify();
+ }
+ }
+ };
+ mTelephonyManager.listen(
+ mListener, PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR);
+ });
synchronized (mLock) {
if (!mOnMessageWaitingIndicatorChangedCalled){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertTrue(mOnMessageWaitingIndicatorChangedCalled);
}
- /*
- * The tests below rely on the framework to immediately call the installed listener upon
- * registration. There is no simple way to emulate state changes for testing the listeners.
- */
@Test
public void testOnPreciseCallStateChanged() throws Throwable {
if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
-
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onPreciseCallStateChanged(PreciseCallState preciseCallState) {
- synchronized (mLock) {
- mOnPreciseCallStateChangedCalled = true;
- mPreciseCallState = preciseCallState;
- mLock.notify();
- }
- }
- };
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.listen(mListener, PhoneStateListener.LISTEN_PRECISE_CALL_STATE));
- Looper.loop();
- }
- });
-
assertThat(mOnPreciseCallStateChangedCalled).isFalse();
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onPreciseCallStateChanged(PreciseCallState preciseCallState) {
+ synchronized (mLock) {
+ mOnPreciseCallStateChangedCalled = true;
+ mPreciseCallState = preciseCallState;
+ mLock.notify();
+ }
+ }
+ };
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ (tm) -> tm.listen(mListener, PhoneStateListener.LISTEN_PRECISE_CALL_STATE));
+ });
synchronized (mLock) {
if (!mOnPreciseCallStateChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
Log.d(TAG, "testOnPreciseCallStateChanged: " + mOnPreciseCallStateChangedCalled);
+
assertThat(mOnPreciseCallStateChangedCalled).isTrue();
assertThat(mPreciseCallState.getForegroundCallState()).isIn(PRECISE_CALL_STATE);
assertThat(mPreciseCallState.getBackgroundCallState()).isIn(PRECISE_CALL_STATE);
assertThat(mPreciseCallState.getRingingCallState()).isIn(PRECISE_CALL_STATE);
}
- /*
- * The tests below rely on the framework to immediately call the installed listener upon
- * registration. There is no simple way to emulate state changes for testing the listeners.
- */
@Test
public void testOnCallDisconnectCauseChanged() throws Throwable {
if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
-
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onCallDisconnectCauseChanged(int disconnectCause,
- int preciseDisconnectCause) {
- synchronized (mLock) {
- mOnCallDisconnectCauseChangedCalled = true;
- mLock.notify();
- }
- }
- };
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.listen(mListener,
- PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES));
- Looper.loop();
- }
- });
-
assertThat(mOnCallDisconnectCauseChangedCalled).isFalse();
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onCallDisconnectCauseChanged(int disconnectCause,
+ int preciseDisconnectCause) {
+ synchronized (mLock) {
+ mOnCallDisconnectCauseChangedCalled = true;
+ mLock.notify();
+ }
+ }
+ };
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ (tm) -> tm.listen(mListener,
+ PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES));
+ });
synchronized (mLock) {
if (!mOnCallDisconnectCauseChangedCalled){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertThat(mOnCallDisconnectCauseChangedCalled).isTrue();
}
@@ -582,36 +511,28 @@
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
-
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onImsCallDisconnectCauseChanged(ImsReasonInfo imsReason) {
- synchronized (mLock) {
- mOnImsCallDisconnectCauseChangedCalled = true;
- mLock.notify();
- }
- }
- };
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.listen(mListener,
- PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES));
- Looper.loop();
- }
- });
-
assertThat(mOnImsCallDisconnectCauseChangedCalled).isFalse();
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onImsCallDisconnectCauseChanged(ImsReasonInfo imsReason) {
+ synchronized (mLock) {
+ mOnImsCallDisconnectCauseChangedCalled = true;
+ mLock.notify();
+ }
+ }
+ };
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ (tm) -> tm.listen(mListener,
+ PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES));
+ });
synchronized (mLock) {
if (!mOnImsCallDisconnectCauseChangedCalled){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertThat(mOnImsCallDisconnectCauseChangedCalled).isTrue();
}
@@ -621,169 +542,130 @@
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener(mSimpleExecutor) {
- @Override
- public void onSrvccStateChanged(int state) {
- synchronized (mLock) {
- mSrvccStateChangedCalled = true;
- mLock.notify();
- }
- }
- };
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.listen(mListener,
- PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED));
- Looper.loop();
- }
- });
-
assertThat(mSrvccStateChangedCalled).isFalse();
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener(mSimpleExecutor) {
+ @Override
+ public void onSrvccStateChanged(int state) {
+ synchronized (mLock) {
+ mSrvccStateChangedCalled = true;
+ mLock.notify();
+ }
+ }
+ };
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ (tm) -> tm.listen(mListener,
+ PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED));
+ });
synchronized (mLock) {
if (!mSrvccStateChangedCalled){
mLock.wait(WAIT_TIME);
}
}
- assertThat(mSrvccStateChangedCalled).isTrue();
- t.checkException();
Log.d(TAG, "testOnPhoneStateListenerExecutorWithSrvccChanged");
+
+ assertThat(mSrvccStateChangedCalled).isTrue();
}
- /*
- * The tests below rely on the framework to immediately call the installed listener upon
- * registration. There is no simple way to emulate state changes for testing the listeners.
- */
@Test
public void testOnRadioPowerStateChanged() throws Throwable {
if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onRadioPowerStateChanged(int state) {
- synchronized(mLock) {
- mRadioPowerState = state;
- mOnRadioPowerStateChangedCalled = true;
- mLock.notify();
- }
- }
- };
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.listen(mListener,
- PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED));
- Looper.loop();
- }
- });
assertThat(mOnRadioPowerStateChangedCalled).isFalse();
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onRadioPowerStateChanged(int state) {
+ synchronized (mLock) {
+ mRadioPowerState = state;
+ mOnRadioPowerStateChangedCalled = true;
+ mLock.notify();
+ }
+ }
+ };
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ (tm) -> tm.listen(mListener,
+ PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED));
+ });
synchronized (mLock) {
if (!mOnRadioPowerStateChangedCalled){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
Log.d(TAG, "testOnRadioPowerStateChanged: " + mRadioPowerState);
+
assertThat(mTelephonyManager.getRadioPowerState()).isEqualTo(mRadioPowerState);
}
- /*
- * The tests below rely on the framework to immediately call the installed listener upon
- * registration. There is no simple way to emulate state changes for testing the listeners.
- */
@Test
public void testOnVoiceActivationStateChanged() throws Throwable {
if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onVoiceActivationStateChanged(int state) {
- synchronized(mLock) {
- mVoiceActivationState = state;
- mVoiceActivationStateChangedCalled = true;
- mLock.notify();
- }
- }
- };
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.listen(mListener,
- PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE));
- Looper.loop();
- }
- });
assertThat(mVoiceActivationStateChangedCalled).isFalse();
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onVoiceActivationStateChanged(int state) {
+ synchronized (mLock) {
+ mVoiceActivationState = state;
+ mVoiceActivationStateChangedCalled = true;
+ mLock.notify();
+ }
+ }
+ };
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ (tm) -> tm.listen(mListener,
+ PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE));
+ });
synchronized (mLock) {
if (!mVoiceActivationStateChangedCalled){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
Log.d(TAG, "onVoiceActivationStateChanged: " + mVoiceActivationState);
int state = ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
(tm) -> tm.getVoiceActivationState());
+
assertEquals(state, mVoiceActivationState);
}
- /*
- * The tests below rely on the framework to immediately call the installed listener upon
- * registration. There is no simple way to emulate state changes for testing the listeners.
- */
@Test
public void testOnPreciseDataConnectionStateChanged() throws Throwable {
if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
-
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onPreciseDataConnectionStateChanged(
- PreciseDataConnectionState state) {
- synchronized(mLock) {
- mOnPreciseDataConnectionStateChanged = true;
- mPreciseDataConnectionState = state;
- mLock.notify();
- }
- }
- };
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.listen(mListener,
- PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE));
- Looper.loop();
- }
- });
-
assertThat(mOnCallDisconnectCauseChangedCalled).isFalse();
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onPreciseDataConnectionStateChanged(
+ PreciseDataConnectionState state) {
+ synchronized (mLock) {
+ mOnPreciseDataConnectionStateChanged = true;
+ mPreciseDataConnectionState = state;
+ mLock.notify();
+ }
+ }
+ };
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ (tm) -> tm.listen(mListener,
+ PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE));
+ });
synchronized (mLock) {
if (!mOnPreciseDataConnectionStateChanged){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertThat(mOnPreciseDataConnectionStateChanged).isTrue();
assertThat(mPreciseDataConnectionState.getState())
.isIn(DATA_CONNECTION_STATE);
@@ -816,37 +698,27 @@
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
-
- TestThread t = new TestThread(new Runnable() {
- @Override
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onCallForwardingIndicatorChanged(boolean cfi) {
- synchronized(mLock) {
- mOnCallForwardingIndicatorChangedCalled = true;
- mLock.notify();
- }
- }
- };
- mTelephonyManager.listen(
- mListener, PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR);
-
- Looper.loop();
- }
- });
-
assertFalse(mOnCallForwardingIndicatorChangedCalled);
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onCallForwardingIndicatorChanged(boolean cfi) {
+ synchronized (mLock) {
+ mOnCallForwardingIndicatorChangedCalled = true;
+ mLock.notify();
+ }
+ }
+ };
+ mTelephonyManager.listen(
+ mListener, PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR);
+ });
synchronized (mLock) {
if (!mOnCallForwardingIndicatorChangedCalled){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertTrue(mOnCallForwardingIndicatorChangedCalled);
}
@@ -856,37 +728,27 @@
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
+ assertFalse(mOnCellLocationChangedCalled);
TelephonyManagerTest.grantLocationPermissions();
-
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onCellLocationChanged(CellLocation location) {
- synchronized(mLock) {
- mOnCellLocationChangedCalled = true;
- mLock.notify();
- }
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onCellLocationChanged(CellLocation location) {
+ synchronized (mLock) {
+ mOnCellLocationChangedCalled = true;
+ mLock.notify();
}
- };
- mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_CELL_LOCATION);
-
- Looper.loop();
- }
+ }
+ };
+ mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_CELL_LOCATION);
});
-
- assertFalse(mOnCellLocationChangedCalled);
- t.start();
-
synchronized (mLock) {
if (!mOnCellLocationChangedCalled){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertTrue(mOnCellLocationChangedCalled);
}
@@ -896,35 +758,26 @@
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
-
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onCallStateChanged(int state, String incomingNumber) {
- synchronized(mLock) {
- mOnCallStateChangedCalled = true;
- mLock.notify();
- }
- }
- };
- mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_CALL_STATE);
-
- Looper.loop();
- }
- });
-
assertFalse(mOnCallStateChangedCalled);
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onCallStateChanged(int state, String incomingNumber) {
+ synchronized (mLock) {
+ mOnCallStateChangedCalled = true;
+ mLock.notify();
+ }
+ }
+ };
+ mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_CALL_STATE);
+ });
synchronized (mLock) {
if (!mOnCallStateChangedCalled){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertTrue(mOnCallStateChangedCalled);
}
@@ -934,51 +787,42 @@
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
-
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onDataConnectionStateChanged(int state) {
- synchronized(mLock) {
- mOnDataConnectionStateChangedCalled = true;
- if (mOnDataConnectionStateChangedCalled
- && mOnDataConnectionStateChangedWithNetworkTypeCalled) {
- mLock.notify();
- }
- }
- }
- @Override
- public void onDataConnectionStateChanged(int state, int networkType) {
- synchronized(mLock) {
- mOnDataConnectionStateChangedWithNetworkTypeCalled = true;
- if (mOnDataConnectionStateChangedCalled
- && mOnDataConnectionStateChangedWithNetworkTypeCalled) {
- mLock.notify();
- }
- }
- }
- };
- mTelephonyManager.listen(
- mListener, PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
-
- Looper.loop();
- }
- });
-
assertFalse(mOnDataConnectionStateChangedCalled);
assertFalse(mOnDataConnectionStateChangedWithNetworkTypeCalled);
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onDataConnectionStateChanged(int state) {
+ synchronized (mLock) {
+ mOnDataConnectionStateChangedCalled = true;
+ if (mOnDataConnectionStateChangedCalled
+ && mOnDataConnectionStateChangedWithNetworkTypeCalled) {
+ mLock.notify();
+ }
+ }
+ }
+ @Override
+ public void onDataConnectionStateChanged(int state, int networkType) {
+ synchronized (mLock) {
+ mOnDataConnectionStateChangedWithNetworkTypeCalled = true;
+ if (mOnDataConnectionStateChangedCalled
+ && mOnDataConnectionStateChangedWithNetworkTypeCalled) {
+ mLock.notify();
+ }
+ }
+ }
+ };
+ mTelephonyManager.listen(
+ mListener, PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
+ });
synchronized (mLock) {
if (!mOnDataConnectionStateChangedCalled ||
!mOnDataConnectionStateChangedWithNetworkTypeCalled){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertTrue(mOnDataConnectionStateChangedCalled);
assertTrue(mOnDataConnectionStateChangedWithNetworkTypeCalled);
}
@@ -989,35 +833,26 @@
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
-
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onDataActivity(int direction) {
- synchronized(mLock) {
- mOnDataActivityCalled = true;
- mLock.notify();
- }
- }
- };
- mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_DATA_ACTIVITY);
-
- Looper.loop();
- }
- });
-
assertFalse(mOnDataActivityCalled);
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onDataActivity(int direction) {
+ synchronized (mLock) {
+ mOnDataActivityCalled = true;
+ mLock.notify();
+ }
+ }
+ };
+ mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_DATA_ACTIVITY);
+ });
synchronized (mLock) {
if (!mOnDataActivityCalled){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertTrue(mOnDataActivityCalled);
}
@@ -1027,37 +862,27 @@
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
+ assertFalse(mOnDataActivityCalled);
TelephonyManagerTest.grantLocationPermissions();
-
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onCellInfoChanged(List<CellInfo> cellInfo) {
- synchronized(mLock) {
- mOnCellInfoChangedCalled = true;
- mLock.notify();
- }
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onCellInfoChanged(List<CellInfo> cellInfo) {
+ synchronized (mLock) {
+ mOnCellInfoChangedCalled = true;
+ mLock.notify();
}
- };
- mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_CELL_INFO);
-
- Looper.loop();
- }
+ }
+ };
+ mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_CELL_INFO);
});
-
- assertFalse(mOnDataActivityCalled);
- t.start();
-
synchronized (mLock) {
if (!mOnCellInfoChangedCalled){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertTrue(mOnCellInfoChangedCalled);
}
@@ -1067,36 +892,27 @@
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
-
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onUserMobileDataStateChanged(boolean state) {
- synchronized(mLock) {
- mOnUserMobileDataStateChanged = true;
- mLock.notify();
- }
- }
- };
- mTelephonyManager.listen(
- mListener, PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE);
-
- Looper.loop();
- }
- });
-
assertFalse(mOnUserMobileDataStateChanged);
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onUserMobileDataStateChanged(boolean state) {
+ synchronized (mLock) {
+ mOnUserMobileDataStateChanged = true;
+ mLock.notify();
+ }
+ }
+ };
+ mTelephonyManager.listen(
+ mListener, PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE);
+ });
synchronized (mLock) {
if (!mOnUserMobileDataStateChanged){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertTrue(mOnUserMobileDataStateChanged);
}
@@ -1106,45 +922,39 @@
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
+
TelephonyUtils.addTestEmergencyNumber(
InstrumentationRegistry.getInstrumentation(), TEST_EMERGENCY_NUMBER);
- HandlerThread mPhoneStateListenerThread = new HandlerThread("PhoneStateListenerThread");
- mPhoneStateListenerThread.start();
- Handler mPhoneStateListenerHandler = new Handler(mPhoneStateListenerThread.getLooper());
- final CountDownLatch latch = new CountDownLatch(1);
- mPhoneStateListenerHandler.post(new Runnable() {
- @Override
- public void run() {
- mListener = new PhoneStateListener() {
- @Override
- public void onOutgoingEmergencySms(EmergencyNumber emergencyNumber) {
+ assertNull(mOnOutgoingSmsEmergencyNumberChanged);
+
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onOutgoingEmergencySms(EmergencyNumber emergencyNumber) {
+ synchronized (mLock) {
Log.i(TAG, "onOutgoingEmergencySms: emergencyNumber=" + emergencyNumber);
mOnOutgoingSmsEmergencyNumberChanged = emergencyNumber;
- latch.countDown();
+ mLock.notify();
}
- };
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.listen(mListener,
- PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS));
- }
- });
- assertNull(mOnOutgoingSmsEmergencyNumberChanged);
- SmsManager.getDefault().sendTextMessage(
+ }
+ };
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ (tm) -> tm.listen(mListener,
+ PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS));
+ SmsManager.getDefault().sendTextMessage(
TEST_EMERGENCY_NUMBER, null, "testOutgoingSmsListenerCts", null, null);
+ });
try {
- latch.await(5000, TimeUnit.MILLISECONDS);
+ synchronized (mLock) {
+ if (mOnOutgoingSmsEmergencyNumberChanged == null) {
+ mLock.wait(WAIT_TIME);
+ }
+ }
} catch (InterruptedException e) {
Log.e(TAG, "Operation interrupted.");
} finally {
- mPhoneStateListenerHandler.post(new Runnable() {
- @Override
- public void run() {
- mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE);
- }
- });
- mPhoneStateListenerThread.quitSafely();
TelephonyUtils.removeTestEmergencyNumber(
InstrumentationRegistry.getInstrumentation(), TEST_EMERGENCY_NUMBER);
}
@@ -1159,36 +969,27 @@
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
return;
}
-
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onActiveDataSubscriptionIdChanged(int subId) {
- synchronized(mLock) {
- mOnActiveDataSubscriptionIdChanged = true;
- mLock.notify();
- }
- }
- };
- mTelephonyManager.listen(
- mListener, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
-
- Looper.loop();
- }
- });
-
assertFalse(mOnActiveDataSubscriptionIdChanged);
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onActiveDataSubscriptionIdChanged(int subId) {
+ synchronized (mLock) {
+ mOnActiveDataSubscriptionIdChanged = true;
+ mLock.notify();
+ }
+ }
+ };
+ mTelephonyManager.listen(
+ mListener, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
+ });
synchronized (mLock) {
if (!mOnActiveDataSubscriptionIdChanged){
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
+
assertTrue(mOnActiveDataSubscriptionIdChanged);
}
@@ -1199,37 +1000,27 @@
return;
}
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onBarringInfoChanged(BarringInfo barringInfo) {
- synchronized (mLock) {
- mOnBarringInfoChangedCalled = true;
- mBarringInfo = barringInfo;
- mLock.notify();
- }
- }
- };
-
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.listen(mListener, PhoneStateListener.LISTEN_BARRING_INFO));
-
- Looper.loop();
- }
- });
-
assertFalse(mOnBarringInfoChangedCalled);
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onBarringInfoChanged(BarringInfo barringInfo) {
+ synchronized (mLock) {
+ mOnBarringInfoChangedCalled = true;
+ mBarringInfo = barringInfo;
+ mLock.notify();
+ }
+ }
+ };
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ (tm) -> tm.listen(mListener, PhoneStateListener.LISTEN_BARRING_INFO));
+ });
synchronized (mLock) {
if (!mOnBarringInfoChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
assertTrue(mOnBarringInfoChangedCalled);
assertBarringInfoSane(mBarringInfo);
@@ -1299,38 +1090,28 @@
return;
}
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
-
- mListener = new PhoneStateListener() {
- @Override
- public void onRegistrationFailed(CellIdentity cid, String chosenPlmn,
- int domain, int causeCode, int additionalCauseCode) {
- synchronized (mLock) {
- mOnRegistrationFailedCalled = true;
- mLock.notify();
- }
- }
- };
-
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.listen(mListener,
- PhoneStateListener.LISTEN_REGISTRATION_FAILURE));
-
- Looper.loop();
- }
- });
-
assertFalse(mOnBarringInfoChangedCalled);
- t.start();
+ mHandler.post(() -> {
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onRegistrationFailed(CellIdentity cid, String chosenPlmn,
+ int domain, int causeCode, int additionalCauseCode) {
+ synchronized (mLock) {
+ mOnRegistrationFailedCalled = true;
+ mLock.notify();
+ }
+ }
+ };
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ (tm) -> tm.listen(mListener,
+ PhoneStateListener.LISTEN_REGISTRATION_FAILURE));
+ });
synchronized (mLock) {
if (!mOnBarringInfoChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
- t.checkException();
// Assert that in the WAIT_TIME interval, the listener wasn't invoked. While this is
// **technically** a flaky test, in practice this flake should happen approximately never
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
index 6fb9299..cf58926 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -686,7 +686,7 @@
setPreferredDataSubId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
}
- List<SubscriptionInfo> subscriptionInfos = mSm.getActiveAndHiddenSubscriptionInfoList();
+ List<SubscriptionInfo> subscriptionInfos = mSm.getCompleteActiveSubscriptionInfoList();
for (SubscriptionInfo subInfo : subscriptionInfos) {
// Only test on opportunistic subscriptions.
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
index 24a5ed5..cabc0e1 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -46,6 +46,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.PersistableBundle;
+import android.os.Process;
import android.os.RemoteException;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
@@ -54,7 +55,6 @@
import android.telephony.Annotation.RadioPowerState;
import android.telephony.AvailableNetworkInfo;
import android.telephony.CallAttributes;
-import android.telephony.CallForwardingInfo;
import android.telephony.CallQuality;
import android.telephony.CarrierConfigManager;
import android.telephony.CellLocation;
@@ -84,6 +84,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import java.security.MessageDigest;
@@ -530,12 +531,24 @@
mTelephonyManager.getSubscriptionId(defaultAccount);
mTelephonyManager.getCarrierConfig();
ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
- (tm) -> tm.isDataConnectionEnabled());
+ (tm) -> tm.isDataConnectionAllowed());
ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
(tm) -> tm.isAnyRadioPoweredOn());
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.resetIms(tm.getSlotIndex()));
+ // Verify TelephonyManager.getCarrierPrivilegeStatus
+ List<Integer> validCarrierPrivilegeStatus = new ArrayList<>();
+ validCarrierPrivilegeStatus.add(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+ validCarrierPrivilegeStatus.add(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+ validCarrierPrivilegeStatus.add(
+ TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED);
+ validCarrierPrivilegeStatus.add(
+ TelephonyManager.CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES);
+ int carrierPrivilegeStatusResult = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.getCarrierPrivilegeStatus(Process.myUid()));
+ assertTrue(validCarrierPrivilegeStatus.contains(carrierPrivilegeStatusResult));
+
// Verify TelephonyManager.getCarrierPrivilegedPackagesForAllActiveSubscriptions
List<String> resultForGetCarrierPrivilegedApis =
ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
@@ -545,9 +558,14 @@
assertFalse(TextUtils.isEmpty(result));
}
- TelephonyManager.getDefaultRespondViaMessageApplication(getContext(), false);
+ mTelephonyManager.getDefaultRespondViaMessageApplication();
+ mTelephonyManager.getAndUpdateDefaultRespondViaMessageApplication();
}
+ /**
+ * Due to the corresponding API is hidden in R and will be public in S, this test
+ * is commented and will be un-commented in Android S.
+ *
@Test
public void testGetCallForwarding() {
List<Integer> callForwardingReasons = new ArrayList<>();
@@ -579,7 +597,12 @@
assertTrue(callForwardingInfo.getTimeoutSeconds() >= 0);
}
}
+ */
+ /**
+ * Due to the corresponding API is hidden in R and will be public in S, this test
+ * is commented and will be un-commented in Android S.
+ *
@Test
public void testSetCallForwarding() {
List<Integer> callForwardingReasons = new ArrayList<>();
@@ -596,10 +619,12 @@
CallForwardingInfo.STATUS_ACTIVE,
callForwardingReasonToEnable,
TEST_FORWARD_NUMBER,
- 1 /** time seconds */);
+ // time seconds
+ 1);
Log.d(TAG, "[testSetCallForwarding] Enable Call Forwarding. Status: "
- + CallForwardingInfo.STATUS_ACTIVE + " Reason: " + callForwardingReasonToEnable
- + " Number: " + TEST_FORWARD_NUMBER + " Time Seconds: 1");
+ + CallForwardingInfo.STATUS_ACTIVE + " Reason: "
+ + callForwardingReasonToEnable + " Number: " + TEST_FORWARD_NUMBER
+ + " Time Seconds: 1");
ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
(tm) -> tm.setCallForwarding(callForwardingInfoToEnable));
}
@@ -610,7 +635,8 @@
CallForwardingInfo.STATUS_INACTIVE,
callForwardingReasonToDisable,
TEST_FORWARD_NUMBER,
- 1 /** time seconds */);
+ // time seconds
+ 1);
Log.d(TAG, "[testSetCallForwarding] Disable Call Forwarding. Status: "
+ CallForwardingInfo.STATUS_INACTIVE + " Reason: "
+ callForwardingReasonToDisable + " Number: " + TEST_FORWARD_NUMBER
@@ -619,7 +645,12 @@
(tm) -> tm.setCallForwarding(callForwardingInfoToDisable));
}
}
+ */
+ /**
+ * Due to the corresponding API is hidden in R and will be public in S, this test
+ * is commented and will be un-commented in Android S.
+ *
@Test
public void testGetCallWaitingStatus() {
Set<Integer> callWaitingStatus = new HashSet<Integer>();
@@ -632,7 +663,12 @@
mTelephonyManager, (tm) -> tm.getCallWaitingStatus());
assertTrue(callWaitingStatus.contains(status));
}
+ */
+ /**
+ * Due to the corresponding API is hidden in R and will be public in S, this test
+ * is commented and will be un-commented in Android S.
+ *
@Test
public void testSetCallWaitingStatus() {
ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
@@ -640,6 +676,7 @@
ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
(tm) -> tm.setCallWaitingStatus(false));
}
+ */
@Test
public void testCellLocationFinePermission() {
@@ -1448,6 +1485,7 @@
* Verifies that {@link TelephonyManager#getIsimImpu()} does not throw any exception when called
* and has the correct permissions.
*/
+ @Ignore("API moved back to @hide for Android R.")
@Test
public void testGetIsimImpu() {
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
@@ -2520,16 +2558,6 @@
}
@Test
- public void testIsDataCapableExists() {
- if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
- return;
- }
-
- //Simple test to make sure that isDataCapable exists and does not crash.
- mTelephonyManager.isDataCapable();
- }
-
- @Test
public void testDisAllowedNetworkTypes() {
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
return;
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyPermissionPolicyTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyPermissionPolicyTest.java
deleted file mode 100644
index 37228c8..0000000
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyPermissionPolicyTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.telephony.cts;
-
-import static org.junit.Assert.assertTrue;
-
-import android.content.pm.PackageManager;
-import android.util.ArraySet;
-
-import androidx.test.InstrumentationRegistry;
-
-import org.junit.Test;
-
-public class TelephonyPermissionPolicyTest {
- private static final ArraySet<String> KNOWN_TELEPHONY_PACKAGES;
-
- static {
- KNOWN_TELEPHONY_PACKAGES = new ArraySet<>();
- KNOWN_TELEPHONY_PACKAGES.add("com.android.phone");
- KNOWN_TELEPHONY_PACKAGES.add("com.android.stk");
- KNOWN_TELEPHONY_PACKAGES.add("com.android.providers.telephony");
- KNOWN_TELEPHONY_PACKAGES.add("com.android.ons");
- KNOWN_TELEPHONY_PACKAGES.add("com.android.cellbroadcastservice");
- KNOWN_TELEPHONY_PACKAGES.add("com.android.cellbroadcastreceiver");
- KNOWN_TELEPHONY_PACKAGES.add("com.android.shell");
- }
-
- @Test
- public void testIsTelephonyPackagesKnown() {
- final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
- final String[] configuredTelephonyPackages = pm.getTelephonyPackageNames();
- // make sure only known system telephony apks are configured which will be granted special
- // permissions.
- for (String packageName : configuredTelephonyPackages) {
- assertTrue(KNOWN_TELEPHONY_PACKAGES.contains(packageName));
- }
- }
-}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
index 953005e..5e28767 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
@@ -722,8 +722,8 @@
};
final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
- // Latch will count down here (we callback on the state during registration).
try {
+ // First try without the correct permissions.
ImsManager imsManager = getContext().getSystemService(ImsManager.class);
ImsMmTelManager mmTelManager = imsManager.getImsMmTelManager(sTestSub);
mmTelManager.registerImsRegistrationCallback(getContext().getMainExecutor(), callback);
@@ -732,6 +732,7 @@
//expected
}
+ // Latch will count down here (we callback on the state during registration).
try {
automan.adoptShellPermissionIdentity();
ImsManager imsManager = getContext().getSystemService(ImsManager.class);
@@ -761,6 +762,16 @@
assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
assertEquals(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE, waitForIntResult(mQueue));
+ // Ensure null ImsReasonInfo still results in non-null callback value.
+ sServiceConnector.getCarrierService().getImsRegistration().onTechnologyChangeFailed(
+ ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN, null);
+ assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
+ assertEquals(ImsReasonInfo.CODE_UNSPECIFIED, waitForIntResult(mQueue));
+
+ // Ensure null ImsReasonInfo still results in non-null callback.
+ sServiceConnector.getCarrierService().getImsRegistration().onDeregistered(null);
+ assertEquals(ImsReasonInfo.CODE_UNSPECIFIED, waitForIntResult(mQueue));
+
try {
automan.adoptShellPermissionIdentity();
ImsManager imsManager = getContext().getSystemService(ImsManager.class);
@@ -778,7 +789,6 @@
} catch (SecurityException e) {
//expected
}
-
}
@Ignore("RCS APIs not public yet")
@@ -1136,6 +1146,105 @@
}
}
+ /**
+ * We are specifically testing a race case here such that IsAvailable returns the correct
+ * capability status during the callback.
+ */
+ @Test
+ public void testCapabilityStatusWithIsAvailableDuringCallback() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ ImsMmTelManager mmTelManager = imsManager.getImsMmTelManager(sTestSub);
+
+ triggerFrameworkConnectToCarrierImsService();
+
+ // Wait for the framework to set the capabilities on the ImsService
+ sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_MMTEL_CAP_SET);
+
+
+ // Make sure we start off with every capability unavailable
+ sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ MmTelFeature.MmTelCapabilities stdCapabilities = new MmTelFeature.MmTelCapabilities();
+ sServiceConnector.getCarrierService().getMmTelFeature()
+ .notifyCapabilitiesStatusChanged(stdCapabilities);
+
+
+ // Make sure the capabilities match the API getter for capabilities
+ final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+
+ //This lock is to keep the shell permissions from being dropped on a different thread
+ //causing a permission error.
+ Object lockObj = new Object();
+
+ synchronized (lockObj) {
+ try {
+ automan.adoptShellPermissionIdentity();
+ boolean isAvailableBeforeStatusChange = mmTelManager.isAvailable(
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ assertFalse(isAvailableBeforeStatusChange);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+ }
+
+ LinkedBlockingQueue<Boolean> voiceIsAvailable = new LinkedBlockingQueue<>();
+ ImsMmTelManager.CapabilityCallback verifyCapabilityStatusCallaback =
+ new ImsMmTelManager.CapabilityCallback() {
+ @Override
+ public void onCapabilitiesStatusChanged(MmTelFeature.MmTelCapabilities capabilities) {
+ synchronized (lockObj) {
+ try {
+ automan.adoptShellPermissionIdentity();
+ boolean isVoiceAvailable = mmTelManager
+ .isAvailable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+
+ voiceIsAvailable.offer(isVoiceAvailable);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+ }
+ }
+ };
+
+ synchronized (lockObj) {
+ // Latch will count down here (we callback on the state during registration).
+ try {
+ automan.adoptShellPermissionIdentity();
+ mmTelManager.registerMmTelCapabilityCallback(getContext().getMainExecutor(),
+ verifyCapabilityStatusCallaback);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+ }
+
+ // Now enable voice availability
+ Boolean isAvailableDuringRegister = waitForResult(voiceIsAvailable);
+ assertNotNull(isAvailableDuringRegister);
+ assertFalse(isAvailableDuringRegister);
+ sServiceConnector.getCarrierService().getMmTelFeature()
+ .notifyCapabilitiesStatusChanged(new MmTelFeature.MmTelCapabilities(
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE));
+ Boolean isAvailableAfterStatusChange = waitForResult(voiceIsAvailable);
+ assertNotNull(isAvailableAfterStatusChange);
+ assertTrue(isAvailableAfterStatusChange);
+
+ synchronized (lockObj) {
+ try {
+ automan.adoptShellPermissionIdentity();
+ mmTelManager.unregisterMmTelCapabilityCallback(verifyCapabilityStatusCallaback);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+ }
+ }
+
@Test
public void testProvisioningManagerNotifyAutoConfig() throws Exception {
if (!ImsUtils.shouldTestImsService()) {
@@ -1327,6 +1436,49 @@
assertEquals(TEST_CONFIG_VALUE_STRING,
provisioningManager.getProvisioningStringValue(TEST_CONFIG_KEY));
+ automan.adoptShellPermissionIdentity();
+ provisioningManager.unregisterProvisioningChangedCallback(callback);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+ }
+
+ @Ignore("The ProvisioningManager constants were moved back to @hide for now, don't want to "
+ + "completely remove test.")
+ @Test
+ public void testProvisioningManagerConstants() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ triggerFrameworkConnectToCarrierImsService();
+
+ ProvisioningManager provisioningManager =
+ ProvisioningManager.createForSubscriptionId(sTestSub);
+
+ // This is a little bit gross looking, but on P devices, I can not define classes that
+ // extend ProvisioningManager.Callback (because it doesn't exist), so this has to
+ // happen as an anon class here.
+ LinkedBlockingQueue<Pair<Integer, Integer>> mIntQueue = new LinkedBlockingQueue<>();
+ LinkedBlockingQueue<Pair<Integer, String>> mStringQueue = new LinkedBlockingQueue<>();
+ ProvisioningManager.Callback callback = new ProvisioningManager.Callback() {
+ @Override
+ public void onProvisioningIntChanged(int item, int value) {
+ mIntQueue.offer(new Pair<>(item, value));
+ }
+
+ @Override
+ public void onProvisioningStringChanged(int item, String value) {
+ mStringQueue.offer(new Pair<>(item, value));
+ }
+ };
+
+ final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ try {
+ automan.adoptShellPermissionIdentity();
+ provisioningManager.registerProvisioningChangedCallback(getContext().getMainExecutor(),
+ callback);
+
verifyStringKey(provisioningManager, mStringQueue,
ProvisioningManager.KEY_AMR_CODEC_MODE_SET_VALUES, "1,2");
verifyStringKey(provisioningManager, mStringQueue,
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
index 86a48ef..a1816d8 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
@@ -64,7 +64,7 @@
private static final Uri TEST_NUMBER_URI =
Uri.fromParts(PhoneAccount.SCHEME_TEL, "6505551212", null);
private static final Uri LISTENER_URI = Uri.withAppendedPath(Telephony.SimInfo.CONTENT_URI,
- Telephony.SimInfo.IMS_RCS_UCE_ENABLED);
+ Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED);
private static HandlerThread sHandlerThread;
private ContentObserver mUceObserver;
diff --git a/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
index 98dbe52..4d72eae 100644
--- a/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
+++ b/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
@@ -180,15 +180,15 @@
}
}
- private class StartTetheringCallback extends TetheringManager.StartTetheringCallback {
+ private class StartTetheringCallback implements TetheringManager.StartTetheringCallback {
@Override
public void onTetheringStarted() {
// Do nothing, TetherChangeReceiver will wait until it receives the broadcast.
}
@Override
- public void onTetheringFailed(final int resultCode) {
- fail("startTethering fail: " + resultCode);
+ public void onTetheringFailed(final int error) {
+ fail("startTethering fail: " + error);
}
}
diff --git a/tests/tests/tv/Android.bp b/tests/tests/tv/Android.bp
index 640b963..f24cd1e 100644
--- a/tests/tests/tv/Android.bp
+++ b/tests/tests/tv/Android.bp
@@ -27,8 +27,11 @@
"android.test.base.stubs",
],
static_libs: [
+ "androidx.test.core",
"compatibility-device-util-axt",
"ctstestrunner-axt",
+ "testng",
],
- sdk_version: "test_current",
+ // sdk_version: "test_current",
+ platform_apis: true,
}
diff --git a/tests/tests/tv/AndroidManifest.xml b/tests/tests/tv/AndroidManifest.xml
index 8cb2b79..ce93d9a 100644
--- a/tests/tests/tv/AndroidManifest.xml
+++ b/tests/tests/tv/AndroidManifest.xml
@@ -21,6 +21,9 @@
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
+ <uses-permission android:name="android.permission.ACCESS_TV_DESCRAMBLER" />
+ <uses-permission android:name="android.permission.ACCESS_TV_TUNER" />
+ <uses-permission android:name="android.permission.TUNER_RESOURCE_ACCESS" />
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
diff --git a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java
new file mode 100644
index 0000000..4eaafe3
--- /dev/null
+++ b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.cts;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.content.Context;
+import android.media.tv.tuner.Descrambler;
+import android.media.tv.tuner.Tuner;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TunerTest {
+ private static final String TAG = "MediaTunerTest";
+
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ @Test
+ public void testTunerConstructor() throws Exception {
+ if (!hasTuner()) return;
+ Tuner tuner = new Tuner(mContext, "123", 1);
+ assertNotNull(tuner);
+ }
+
+ private boolean hasTuner() {
+ return mContext.getPackageManager().hasSystemFeature("android.hardware.tv.tuner");
+ }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AutofillHighlightTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AutofillHighlightTests.java
index e02506f..a936dfa 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AutofillHighlightTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AutofillHighlightTests.java
@@ -56,7 +56,8 @@
ActivityTestBase.TEST_HEIGHT);
autofilledDrawable.draw(canvas);
- createTest().addLayout(R.layout.simple_white_layout, view -> view.setAutofilled(true))
+ createTest()
+ .addLayout(R.layout.simple_white_layout, view -> view.setAutofilled(true, false))
.runWithVerifier(new GoldenImageVerifier(goldenBitmap, new MSSIMComparer(0.99)));
}
}
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyTest.java b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
index 51288cf..85c4094 100644
--- a/tests/tests/view/src/android/view/cts/PixelCopyTest.java
+++ b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
@@ -796,12 +796,12 @@
assertBitmapNotColor("Left edge", bitmap, edgeColor, 2, bitmap.getHeight() / 2);
assertBitmapColor("Bottom edge", bitmap, edgeColor,
- bitmap.getWidth() / 2, bitmap.getHeight() - 1);
+ bitmap.getWidth() / 2, bitmap.getHeight() - 2);
assertBitmapNotColor("Bottom edge", bitmap, edgeColor,
bitmap.getWidth() / 2, bitmap.getHeight() - 3);
assertBitmapColor("Right edge", bitmap, edgeColor,
- bitmap.getWidth() - 1, bitmap.getHeight() / 2);
+ bitmap.getWidth() - 2, bitmap.getHeight() / 2);
assertBitmapNotColor("Right edge", bitmap, edgeColor,
bitmap.getWidth() - 3, bitmap.getHeight() / 2);
}
diff --git a/tests/tests/view/surfacevalidator/Android.mk b/tests/tests/view/surfacevalidator/Android.mk
index fbb6894..973d374 100644
--- a/tests/tests/view/surfacevalidator/Android.mk
+++ b/tests/tests/view/surfacevalidator/Android.mk
@@ -25,6 +25,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
androidx.test.rules \
+ cts-wm-util \
ub-uiautomator
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
index 4d6bab5..51ef4a0 100644
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
@@ -36,6 +36,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.provider.Settings;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
@@ -49,6 +50,8 @@
import android.view.WindowManager;
import android.widget.FrameLayout;
+import android.server.wm.settings.SettingsSession;
+
import androidx.test.InstrumentationRegistry;
import org.junit.rules.TestName;
@@ -66,6 +69,15 @@
public final SparseArray<Bitmap> failures = new SparseArray<>();
}
+ private static class ImmersiveConfirmationSetting extends SettingsSession<String> {
+ ImmersiveConfirmationSetting() {
+ super(Settings.Secure.getUriFor(
+ Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS),
+ Settings.Secure::getString, Settings.Secure::putString);
+ }
+ }
+ private ImmersiveConfirmationSetting mSettingsSession;
+
private static final String TAG = "CapturedActivity";
private static final int PERMISSION_CODE = 1;
private MediaProjectionManager mProjectionManager;
@@ -100,6 +112,9 @@
// longer duration to capture the expected number of frames
mOnEmbedded = packageManager.hasSystemFeature(PackageManager.FEATURE_EMBEDDED);
+ mSettingsSession = new ImmersiveConfirmationSetting();
+ mSettingsSession.set("confirmed");
+
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN);
// Set the NULL pointer icon so that it won't obstruct the captured image.
@@ -115,6 +130,11 @@
bindMediaProjectionService();
}
+ @Override
+ public void onStop() {
+ mSettingsSession.close();
+ }
+
public void dismissPermissionDialog() {
// The permission dialog will be auto-opened by the activity - find it and accept
UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index 68b0126..aaccdda 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -631,8 +631,7 @@
* Modifications to this test should be reflected in that test as necessary. See
* http://go/modifying-webview-cts.
*/
- // TODO(ntfschr): re-enable when https://crbug.com/1006953 is fixed and dropped into Android.
- public void disabled_testOnSafeBrowsingHitBackToSafety() throws Throwable {
+ public void testOnSafeBrowsingHitBackToSafety() throws Throwable {
if (!NullWebViewUtils.isWebViewAvailable()) {
return;
}
@@ -672,8 +671,7 @@
* Modifications to this test should be reflected in that test as necessary. See
* http://go/modifying-webview-cts.
*/
- // TODO(ntfschr): re-enable when https://crbug.com/1006953 is fixed and dropped into Android.
- public void disabled_testOnSafeBrowsingHitProceed() throws Throwable {
+ public void testOnSafeBrowsingHitProceed() throws Throwable {
if (!NullWebViewUtils.isWebViewAvailable()) {
return;
}
@@ -734,26 +732,22 @@
}
}
- // TODO(ntfschr): re-enable when https://crbug.com/1006953 is fixed and dropped into Android.
- public void disabled_testOnSafeBrowsingMalwareCode() throws Throwable {
+ public void testOnSafeBrowsingMalwareCode() throws Throwable {
testOnSafeBrowsingCode(TEST_SAFE_BROWSING_MALWARE_URL,
WebViewClient.SAFE_BROWSING_THREAT_MALWARE);
}
- // TODO(ntfschr): re-enable when https://crbug.com/1006953 is fixed and dropped into Android.
- public void disabled_testOnSafeBrowsingPhishingCode() throws Throwable {
+ public void testOnSafeBrowsingPhishingCode() throws Throwable {
testOnSafeBrowsingCode(TEST_SAFE_BROWSING_PHISHING_URL,
WebViewClient.SAFE_BROWSING_THREAT_PHISHING);
}
- // TODO(ntfschr): re-enable when https://crbug.com/1006953 is fixed and dropped into Android.
- public void disabled_testOnSafeBrowsingUnwantedSoftwareCode() throws Throwable {
+ public void testOnSafeBrowsingUnwantedSoftwareCode() throws Throwable {
testOnSafeBrowsingCode(TEST_SAFE_BROWSING_UNWANTED_SOFTWARE_URL,
WebViewClient.SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE);
}
- // TODO(ntfschr): re-enable when https://crbug.com/1006953 is fixed and dropped into Android.
- public void disabled_testOnSafeBrowsingBillingCode() throws Throwable {
+ public void testOnSafeBrowsingBillingCode() throws Throwable {
testOnSafeBrowsingCode(TEST_SAFE_BROWSING_BILLING_URL,
WebViewClient.SAFE_BROWSING_THREAT_BILLING);
}
diff --git a/tests/tests/widget/AndroidTest.xml b/tests/tests/widget/AndroidTest.xml
index 47b120b..9bdb58f 100644
--- a/tests/tests/widget/AndroidTest.xml
+++ b/tests/tests/widget/AndroidTest.xml
@@ -22,6 +22,7 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsWidgetTestCases.apk" />
+ <option name="test-file-name" value="CtsWidgetApp.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.widget.cts" />
diff --git a/tests/tests/appop/AppWithLongFeatureId/Android.bp b/tests/tests/widget/app/Android.bp
similarity index 69%
copy from tests/tests/appop/AppWithLongFeatureId/Android.bp
copy to tests/tests/widget/app/Android.bp
index e0034f0..819e4a0 100644
--- a/tests/tests/appop/AppWithLongFeatureId/Android.bp
+++ b/tests/tests/widget/app/Android.bp
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -12,12 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-android_test_helper_app {
- name: "AppWithLongFeatureIdFeature",
-
+android_test {
+ name: "CtsWidgetApp",
+ defaults: ["cts_support_defaults"],
+ sdk_version: "test_current",
+ srcs: [
+ "src/**/*.java",
+ ],
+ static_libs: [
+ "androidx.appcompat_appcompat",
+ ],
test_suites: [
"cts",
"vts",
"general-tests",
- ]
-}
\ No newline at end of file
+ ],
+}
diff --git a/tests/tests/appop/AppWithLongFeatureId/AndroidManifest.xml b/tests/tests/widget/app/AndroidManifest.xml
old mode 100644
new mode 100755
similarity index 76%
copy from tests/tests/appop/AppWithLongFeatureId/AndroidManifest.xml
copy to tests/tests/widget/app/AndroidManifest.xml
index 17d10e9..9c19ce1
--- a/tests/tests/appop/AppWithLongFeatureId/AndroidManifest.xml
+++ b/tests/tests/widget/app/AndroidManifest.xml
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
-
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
@@ -17,9 +16,12 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.app.appops.cts.appwithlongfeatureId">
- <feature android:featureId="1xxxx_xxxx2xxxx_xxxx3xxxx_xxxx4xxxx_xxxx5xxxx_xxxxB" android:label="@string/dummyLabel" />
+ package="android.widget.cts.app">
- <application />
-
+ <application>
+ <activity
+ android:name=".TranslucentActivity"
+ android:exported="true"
+ android:theme="@style/TranslucentTheme" />
+ </application>
</manifest>
diff --git a/tests/tests/appop/AppWithLongFeatureId/AndroidManifest.xml b/tests/tests/widget/app/res/values/styles.xml
similarity index 70%
copy from tests/tests/appop/AppWithLongFeatureId/AndroidManifest.xml
copy to tests/tests/widget/app/res/values/styles.xml
index 17d10e9..a38f6b2 100644
--- a/tests/tests/appop/AppWithLongFeatureId/AndroidManifest.xml
+++ b/tests/tests/widget/app/res/values/styles.xml
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
-
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
@@ -16,10 +15,9 @@
~ limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.app.appops.cts.appwithlongfeatureId">
- <feature android:featureId="1xxxx_xxxx2xxxx_xxxx3xxxx_xxxx4xxxx_xxxx5xxxx_xxxxB" android:label="@string/dummyLabel" />
-
- <application />
-
-</manifest>
+<resources>
+ <style name="TranslucentTheme" parent="Theme.AppCompat.Light.NoActionBar">
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ </style>
+</resources>
diff --git a/tests/tests/widget/app/src/android/widget/cts/app/TranslucentActivity.java b/tests/tests/widget/app/src/android/widget/cts/app/TranslucentActivity.java
new file mode 100644
index 0000000..c9b79b3
--- /dev/null
+++ b/tests/tests/widget/app/src/android/widget/cts/app/TranslucentActivity.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 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.widget.cts.app;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.FragmentManager;
+
+public class TranslucentActivity extends AppCompatActivity {
+ private static final String ACTION_TRANSLUCENT_ACTIVITY_RESUMED =
+ "android.widget.cts.app.TRANSLUCENT_ACTIVITY_RESUMED";
+ private static final String ACTION_TRANSLUCENT_ACTIVITY_FINISH =
+ "android.widget.cts.app.TRANSLUCENT_ACTIVITY_FINISH";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ FragmentManager fragmentManager = getSupportFragmentManager();
+ if (fragmentManager.findFragmentByTag("dialog") == null) {
+ DialogFragment fragment = new SampleFragment();
+ fragment.show(fragmentManager, "dialog");
+ }
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_TRANSLUCENT_ACTIVITY_FINISH);
+ registerReceiver(mFinishActivityReceiver, filter);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ sendBroadcast(new Intent(ACTION_TRANSLUCENT_ACTIVITY_RESUMED));
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ unregisterReceiver(mFinishActivityReceiver);
+ }
+
+ private final BroadcastReceiver mFinishActivityReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ finish();
+ }
+ };
+
+ public static class SampleFragment extends DialogFragment {
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ return new AlertDialog.Builder(getActivity())
+ .setTitle("Title")
+ .setMessage("Message")
+ .setOnDismissListener(dialog -> getActivity().finish())
+ .create();
+ }
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/EditTextTest.java b/tests/tests/widget/src/android/widget/cts/EditTextTest.java
index 29990eb..b6c8548 100644
--- a/tests/tests/widget/src/android/widget/cts/EditTextTest.java
+++ b/tests/tests/widget/src/android/widget/cts/EditTextTest.java
@@ -35,6 +35,7 @@
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.util.Xml;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.EditText;
import android.widget.TextView.BufferType;
@@ -50,6 +51,8 @@
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParser;
+import java.util.List;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class EditTextTest {
@@ -366,6 +369,22 @@
assertEquals(Layout.BREAK_STRATEGY_SIMPLE, editText.getBreakStrategy());
}
+ @UiThreadTest
+ @Test
+ public void testOnInitializeA11yNodeInfo_hasAccessibilityActions() {
+ mEditText1.setText("android");
+ final AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+ mEditText1.onInitializeAccessibilityNodeInfo(info);
+ List<AccessibilityNodeInfo.AccessibilityAction> actionList = info.getActionList();
+ assertTrue("info's isLongClickable should be true",
+ info.isLongClickable());
+ assertTrue("info should have ACTION_LONG_CLICK",
+ actionList.contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK));
+ assertTrue("info should have ACTION_SET_TEXT",
+ actionList.contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT));
+
+ }
+
private class MockEditText extends EditText {
public MockEditText(Context context) {
super(context);
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index 50ed338..eadd4d7 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -53,6 +53,7 @@
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver;
+import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.ImageView;
@@ -494,6 +495,43 @@
}
@Test
+ public void testShowAsDropDown_ClipToScreen_Overlap_OutOfScreen() throws Throwable {
+ final PopupWindow popup = createPopupWindow(createPopupContent(CONTENT_SIZE_DP,
+ CONTENT_SIZE_DP));
+ final View upperLeftAnchor = mActivity.findViewById(R.id.anchor_upper_left);
+
+ popup.setIsClippedToScreen(true);
+ popup.setOverlapAnchor(true);
+ popup.setAnimationStyle(0);
+ popup.setExitTransition(null);
+ popup.setEnterTransition(null);
+
+ final int appBarHeight = mActivity.getActionBar().getHeight();
+ Rect appFrame = new Rect();
+ Window window = mActivity.getWindow();
+ window.getDecorView().getWindowVisibleDisplayFrame(appFrame);
+ final int appFrameTop = appFrame.top;
+ final int appFrameLeft = appFrame.left;
+ final int offsetX = -1 * (mActivity.findViewById(R.id.anchor_upper_left).getWidth());
+ final int offsetY = -1 * (appBarHeight + appFrameTop);
+ final int gravity = Gravity.TOP | Gravity.START;
+
+ int[] viewOnScreenXY = new int[2];
+
+ mActivityRule.runOnUiThread(() -> popup.showAsDropDown(
+ upperLeftAnchor, offsetX, offsetY, gravity));
+ mInstrumentation.waitForIdleSync();
+
+ assertTrue(popup.isShowing());
+
+ popup.getContentView().getLocationOnScreen(viewOnScreenXY);
+ assertEquals(appFrameLeft, viewOnScreenXY[0]);
+ assertEquals(appFrameTop, viewOnScreenXY[1]);
+
+ dismissPopup();
+ }
+
+ @Test
public void testShowAsDropDown_ClipToScreen_TooBig() throws Throwable {
final View rootView = mActivity.findViewById(R.id.anchor_upper_left).getRootView();
final int width = rootView.getWidth() * 2;
diff --git a/tests/tests/widget/src/android/widget/cts/ToastTest.java b/tests/tests/widget/src/android/widget/cts/ToastTest.java
index dc9f732..896eade 100644
--- a/tests/tests/widget/src/android/widget/cts/ToastTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToastTest.java
@@ -16,6 +16,8 @@
package android.widget.cts;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -24,7 +26,11 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.ConditionVariable;
@@ -71,6 +77,13 @@
private static final int ACCESSIBILITY_STATE_WAIT_TIMEOUT_MS = 3000;
private static final long TIME_FOR_UI_OPERATION = 1000L;
private static final long TIME_OUT = 5000L;
+ private static final String ACTION_TRANSLUCENT_ACTIVITY_RESUMED =
+ "android.widget.cts.app.TRANSLUCENT_ACTIVITY_RESUMED";
+ private static final String ACTION_TRANSLUCENT_ACTIVITY_FINISH =
+ "android.widget.cts.app.TRANSLUCENT_ACTIVITY_FINISH";
+ private static final ComponentName COMPONENT_TRANSLUCENT_ACTIVITY =
+ ComponentName.unflattenFromString("android.widget.cts.app/.TranslucentActivity");
+
private Toast mToast;
private Context mContext;
private boolean mLayoutDone;
@@ -650,6 +663,24 @@
assertNotShowCustomToast(view);
}
+ @Test
+ public void testCustomToastBlocked_whenBehindTranslucentActivity() throws Throwable {
+ ConditionVariable activityStarted = registerBlockingReceiver(
+ ACTION_TRANSLUCENT_ACTIVITY_RESUMED);
+ Intent intent = new Intent();
+ intent.setComponent(COMPONENT_TRANSLUCENT_ACTIVITY);
+ intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ activityStarted.block();
+ makeCustomToast();
+ View view = mToast.getView();
+
+ mActivityRule.runOnUiThread(mToast::show);
+
+ assertNotShowCustomToast(view);
+ mContext.sendBroadcast(new Intent(ACTION_TRANSLUCENT_ACTIVITY_FINISH));
+ }
+
@UiThreadTest
@Test
public void testGetWindowParams_whenTextToast_returnsNull() {
@@ -665,6 +696,18 @@
assertNotNull(toast.getWindowParams());
}
+ private ConditionVariable registerBlockingReceiver(String action) {
+ ConditionVariable broadcastReceived = new ConditionVariable(false);
+ IntentFilter filter = new IntentFilter(action);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ broadcastReceived.open();
+ }
+ }, filter);
+ return broadcastReceived;
+ }
+
private void runOnMainAndDrawSync(@NonNull final View toastView,
@Nullable final Runnable runner) {
final CountDownLatch latch = new CountDownLatch(1);
diff --git a/tools/cts-device-info/Android.mk b/tools/cts-device-info/Android.mk
index fc55328..acaaef6 100644
--- a/tools/cts-device-info/Android.mk
+++ b/tools/cts-device-info/Android.mk
@@ -27,6 +27,8 @@
DEVICE_INFO_MIN_SDK := 23
DEVICE_INFO_TARGET_SDK := 23
+LOCAL_MIN_SDK_VERSION := 23
+
DEVICE_INFO_PERMISSIONS :=
DEVICE_INFO_ACTIVITIES := \
diff --git a/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java b/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
index 216d764..4cfd2df 100644
--- a/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
+++ b/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
@@ -490,7 +490,7 @@
charsKeyNames.add(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP.getName());
charsKeyNames.add(CameraCharacteristics.SCALER_CROPPING_TYPE.getName());
charsKeyNames.add(CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS.getName());
- charsKeyNames.add(CameraCharacteristics.SCALER_AVAILABLE_ROTATE_AND_CROP_MODES.getName());
+ charsKeyNames.add(CameraCharacteristics.SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS.getName());
charsKeyNames.add(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1.getName());
charsKeyNames.add(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2.getName());
charsKeyNames.add(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1.getName());