Merge "Modify test cases for takeScreenshot() API" into rvc-dev
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 3bc5bb6..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">
@@ -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/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/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/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/dummyime/Android.bp b/hostsidetests/appsecurity/test-apps/dummyime/Android.bp
index b356368..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 792cd1d..868dc40 100644
--- a/hostsidetests/backup/OtherSoundsSettingsApp/src/android/cts/backup/othersoundssettingsapp/OtherSoundsSettingsTest.java
+++ b/hostsidetests/backup/OtherSoundsSettingsApp/src/android/cts/backup/othersoundssettingsapp/OtherSoundsSettingsTest.java
@@ -23,6 +23,7 @@
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;
@@ -34,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
@@ -51,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 {
@@ -67,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();
}
/**
@@ -81,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);
@@ -114,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);
@@ -154,17 +163,13 @@
assumeTrue(
"Device Under Test does not have a vibrator, skipping.", mVibrator.hasVibrator());
- int originalValue =
- Settings.System.getInt(
- mContentResolver, Settings.System.HAPTIC_FEEDBACK_ENABLED, -1);
+ 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);
@@ -174,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/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/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/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/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/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/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/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 b23f939..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);
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/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/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/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/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/src/com/android/cts/blob/BlobStoreManagerTest.java b/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java
index ec893bd..2c81ca7 100644
--- a/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java
+++ b/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java
@@ -37,8 +37,12 @@
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;
@@ -48,10 +52,12 @@
import org.junit.runner.RunWith;
import java.io.IOException;
+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";
@@ -659,6 +671,35 @@
}
@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.Builder(mContext).build();
blobData.prepare();
@@ -848,6 +889,31 @@
}
}
+ 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);
}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java
index 24ee21c..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;
@@ -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/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 cc4019c..61b5cbc 100644
--- a/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -45,15 +45,11 @@
import android.util.Log;
import com.android.compatibility.common.util.AnrMonitor;
-import com.android.compatibility.common.util.ShellIdentityUtils;
import com.android.compatibility.common.util.SystemUtil;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
import java.util.function.Predicate;
import java.util.function.Supplier;
@@ -440,6 +436,10 @@
assertNotNull(conInf);
}
+ /**
+ * 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];
@@ -467,21 +467,30 @@
(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());
+ 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());
+ mccMncConfigs[1] = config.substring(
+ SHELL_COMMAND_RESULT_CONFIG_NAME_MNC.length());
} else {
otherConfigs.add(config);
}
}
}
+ */
/**
* Simple test for {@link ActivityManager#isUserAMonkey()} - verifies its false.
diff --git a/tests/app/src/android/app/cts/NotificationChannelTest.java b/tests/app/src/android/app/cts/NotificationChannelTest.java
index 2cc965f..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() {
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index 73e02c2..4de36b9 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
@@ -478,50 +492,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 +546,7 @@
// pass
}
}
- return (found == shouldExist) && (isBubble == shouldBeBubble);
+ return found == shouldExist;
}
private void assertNotificationCount(int expectedCount) {
@@ -1371,7 +1383,8 @@
}
public void testCanBubble_ranking() throws Exception {
- if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+ if ((mActivityManager.isLowRamDevice() && !FeatureUtil.isWatch())
+ || FeatureUtil.isAutomotive()) {
return;
}
@@ -2769,8 +2782,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 +2804,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 +2848,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 +2894,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 +2917,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 +2937,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 +2960,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 +3030,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 +3044,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);
@@ -3034,6 +3086,10 @@
public void testNotificationManagerBubblePolicy_flagForShortcut_dynamic_succeeds()
throws Exception {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
ShortcutManager scmanager = mContext.getSystemService(ShortcutManager.class);
@@ -3084,7 +3140,6 @@
boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
sendAndVerifyBubble(1, nb, data, shouldBeBubble);
-
} finally {
// remove the shortcut
scmanager.removeAllDynamicShortcuts();
@@ -3093,6 +3148,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);
@@ -3131,6 +3190,10 @@
public void testNotificationManagerBubblePolicy_flagForShortcut_fails_invalidNotif()
throws Exception {
+ if (FeatureUtil.isAutomotive()) {
+ // Automotive does not support notification bubbles.
+ return;
+ }
// turn on bubbles globally
toggleBubbleSetting(true);
@@ -3145,6 +3208,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 +3219,8 @@
// turn on bubbles globally
toggleBubbleSetting(true);
+ setUpNotifListener();
+
// Make dynamic shortcut
Intent shortcutIntent = new Intent(mContext, SendBubbleActivity.class);
shortcutIntent.setAction(Intent.ACTION_VIEW);
@@ -3196,12 +3265,13 @@
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 +3279,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 +3306,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 +3324,8 @@
// turn off bubbles globally
toggleBubbleSetting(false);
+
+ mListener.resetData();
}
}
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/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/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/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
index 6607c36..bcad582 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
@@ -2538,26 +2538,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 b135615..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"
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 f2be9c7..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
@@ -77,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");
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/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/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/SurfaceControlViewHostTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java
index 2f4c689..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);
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/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 9a73722..3a814db 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
@@ -410,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);
@@ -511,6 +514,13 @@
}
@Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ mMockIme.getTracer().onWindowVisibilityChanged(() -> {
+ super.onWindowVisibilityChanged(visibility);
+ }, visibility);
+ }
+
+ @Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
removeOnLayoutChangeListener(mLayoutListener);
@@ -861,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/src/android/view/inputmethod/cts/InputMethodServiceTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java
index 1a2561a..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;
@@ -199,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);
}
}
@@ -217,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/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/appenumeration/app/source/AndroidManifest-queriesWildcard-shareActivity.xml b/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-shareActivity.xml
new file mode 100644
index 0000000..57efc78
--- /dev/null
+++ b/tests/tests/appenumeration/app/source/AndroidManifest-queriesWildcard-shareActivity.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.queries.wildcard.share">
+
+ <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-shareActivity.xml b/tests/tests/appenumeration/app/target/AndroidManifest-shareActivity.xml
new file mode 100644
index 0000000..87f621a
--- /dev/null
+++ b/tests/tests/appenumeration/app/target/AndroidManifest-shareActivity.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="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/src/android/app/appops/cts/AppOpsLoggingTest.kt b/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt
index e8db5e2..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
@@ -615,23 +613,6 @@
}
/**
- * Realistic end-to-end test for getting cell info
- */
- @Test
- fun getMultiSimSupport() {
- assumeTrue(context.packageManager.hasSystemFeature(FEATURE_TELEPHONY))
-
- val telephonyManager = context.createAttributionContext(TEST_ATTRIBUTION_TAG)
- .getSystemService(TelephonyManager::class.java)
-
- telephonyManager.isMultiSimSupported
-
- assertThat(noted[0].first.op).isEqualTo(OPSTR_READ_PHONE_STATE)
- assertThat(noted[0].first.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
- assertThat(noted[0].second.map { it.methodName }).contains("getMultiSimSupport")
- }
-
- /**
* Realistic end-to-end test for getting wallpaper
*/
@Test
@@ -647,21 +628,6 @@
}
/**
- * Realistic end-to-end test for checking if currently in call
- */
- @Test
- fun isInCall() {
- val telecomManager = context.createAttributionContext(TEST_ATTRIBUTION_TAG)
- .getSystemService(TelecomManager::class.java)
-
- telecomManager.isInCall()
-
- assertThat(noted[0].first.op).isEqualTo(OPSTR_READ_PHONE_STATE)
- assertThat(noted[0].first.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
- assertThat(noted[0].second.map { it.methodName }).contains("isInCall")
- }
-
- /**
* Realistic end-to-end test for starting a permission protected activity
*/
@Test
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 ad16148..bf76d3d 100644
--- a/tests/tests/car/src/android/car/cts/CarUserManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarUserManagerTest.java
@@ -16,6 +16,7 @@
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;
@@ -23,6 +24,8 @@
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,6 +35,7 @@
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;
@@ -46,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;
@@ -79,6 +84,8 @@
private static CarUserManager sCarUserManager;
+ private PackageManager mPackageManager;
+
private static int sInitialUserId = UserHandle.myUserId();
private static int sNewUserId = UserHandle.USER_NULL;
@@ -100,6 +107,8 @@
sNewUserId = createNewUser("CarUserManagerTest", /* isGuestUser= */ false);
Log.i(TAG, "setUp(): myUid=" + myUid() + ", currentUser=" + sInitialUserId
+ ", newUser=" + sNewUserId);
+
+ mPackageManager = sContext.getPackageManager();
}
@AfterClass
@@ -278,6 +287,37 @@
}
}
+ @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, returning its id.
*/
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/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/enabled/AndroidManifest.xml b/tests/tests/gwp-asan/enabled/AndroidManifest.xml
index afd8c9a..acded16 100644
--- a/tests/tests/gwp-asan/enabled/AndroidManifest.xml
+++ b/tests/tests/gwp-asan/enabled/AndroidManifest.xml
@@ -19,13 +19,13 @@
android:targetSandboxVersion="2">
<application android:extractNativeLibs="true"
- android:enableGwpAsan="true">
+ android:gwpAsanMode="always">
<processes>
<process />
<process android:process=":gwp_asan_enabled"
- android:enableGwpAsan="true" />
+ android:gwpAsanMode="always" />
<process android:process=":gwp_asan_disabled"
- android:enableGwpAsan="false" />
+ android:gwpAsanMode="never" />
<process android:process=":gwp_asan_default" />
</processes>
<uses-library android:name="android.test.runner" />
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/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..7aa5f99
--- /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/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 624016d..8daaed0 100644
--- a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java
+++ b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java
@@ -387,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) {
@@ -400,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 a8bcf34..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 onSeekMapFound(MediaParser.SeekMap seekMap) {
+ mSeekMap = seekMap;
mFakeExtractorOutput.seekMap(
new SeekMap() {
@Override
@@ -306,6 +315,10 @@
}
}
+ public MediaParser.SeekMap getSeekMap() {
+ return mSeekMap;
+ }
+
// Internal classes.
private class ExtractorInputAdapter implements ExtractorInput {
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
index 96e1caa..a05b81b 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiHotspot2Test.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiHotspot2Test.java
@@ -18,23 +18,45 @@
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();
@@ -434,4 +456,33 @@
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 2e3f188..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;
@@ -72,12 +84,18 @@
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.concurrent.Callable;
+import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -92,6 +110,7 @@
private WifiManager mWifiManager;
private ConnectivityManager mConnectivityManager;
+ private TetheringManager mTetheringManager;
private WifiLock mWifiLock;
private static MySync mMySync;
private List<ScanResult> mScanResults = null;
@@ -99,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;
@@ -119,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;
@@ -179,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 {
@@ -201,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(
@@ -215,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;
@@ -224,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
@@ -239,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();
}
@@ -357,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.
@@ -508,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;
@@ -558,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,
@@ -649,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());
}
@@ -1057,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);
}
@@ -1158,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;
@@ -1220,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) {
}
}
@@ -1299,7 +1689,7 @@
.build(),
networkCallbackListener);
// now wait for callback
- mLock.wait(DURATION);
+ mLock.wait(TEST_WAIT_DURATION_MS);
} catch (InterruptedException e) {
}
}
@@ -1347,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) {
}
}
@@ -1395,7 +1785,7 @@
try {
mWifiManager.forget(newNetworkId, actionListener);
// now wait for callback
- mLock.wait(DURATION);
+ mLock.wait(TEST_WAIT_DURATION_MS);
} catch (InterruptedException e) {
}
}
@@ -1472,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
@@ -1486,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();
+ }
}
}
}
@@ -1520,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();
@@ -1537,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) {
}
}
@@ -1760,7 +2247,7 @@
.build(),
networkCallbackListener);
// now wait for callback
- mLock.wait(DURATION);
+ mLock.wait(TEST_WAIT_DURATION_MS);
} catch (InterruptedException e) {
}
}
@@ -1940,4 +2427,88 @@
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/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/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 2cc1e81..7dcf97b 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -730,7 +730,7 @@
<!-- @SystemApi 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.
@@ -1680,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.
@@ -1829,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
@@ -2120,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.
@@ -2148,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
@@ -2261,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.
@@ -2287,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 -->
@@ -2419,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. -->
@@ -2657,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.
@@ -3081,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
@@ -3139,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}
@@ -3216,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.
@@ -3740,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" />
@@ -3753,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 -->
@@ -3990,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
@@ -4025,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.
@@ -4697,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.
@@ -4863,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/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/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/PhoneStateListenerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/PhoneStateListenerTest.java
index f0a0ccc..864cbac 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/PhoneStateListenerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/PhoneStateListenerTest.java
@@ -274,6 +274,10 @@
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) {
@@ -294,8 +298,8 @@
}
};
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.listen(mListener,
- PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH));
+ (tm) -> tm.listen(mListener,
+ PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH));
});
synchronized (mLock) {
if (mSignalStrength == null) {
@@ -315,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) {
@@ -342,7 +350,7 @@
};
try {
mTelephonyManager.listen(mListener,
- PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH);
+ PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH);
} catch (SecurityException se) {
synchronized (mLock) {
mSecurityExceptionThrown = true;
@@ -359,6 +367,7 @@
assertThat(mSecurityExceptionThrown).isTrue();
assertTrue(mSignalStrength == null);
}
+ */
@Test
public void testOnSignalStrengthsChanged() throws Throwable {
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 67a8864..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;
@@ -536,6 +537,18 @@
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 9aa8db0..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")
@@ -1426,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/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/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/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());