Merge "CameraITS: Force stop the app before loading scene." into tm-dev
diff --git a/apps/CameraITS/build/scripts/gpylint_rcfile b/apps/CameraITS/build/scripts/gpylint_rcfile
index fe9f3d1..38c1693 100644
--- a/apps/CameraITS/build/scripts/gpylint_rcfile
+++ b/apps/CameraITS/build/scripts/gpylint_rcfile
@@ -61,9 +61,6 @@
# Inject some known modules.
inject-known-modules=no
-# The import path resolver
-resolver=blaze
-
[REPORTS]
diff --git a/apps/CameraITS/tests/scene1_1/test_ae_af.py b/apps/CameraITS/tests/scene1_1/test_ae_af.py
index 09a1470..852c786 100644
--- a/apps/CameraITS/tests/scene1_1/test_ae_af.py
+++ b/apps/CameraITS/tests/scene1_1/test_ae_af.py
@@ -67,8 +67,8 @@
do_awb=three_a_req[2],
mono_camera=mono_camera)
- except error_util.CameraItsError:
- raise AssertionError(f'{k} did not converge.')
+ except error_util.CameraItsError as e_util:
+ raise AssertionError(f'{k} did not converge.') from e_util
logging.debug('AWB gains: %s, xform: %s', str(awb_gains),
str(awb_xform))
diff --git a/apps/CameraITS/tests/scene1_1/test_capture_result.py b/apps/CameraITS/tests/scene1_1/test_capture_result.py
index 304a737..f3a9e9d 100644
--- a/apps/CameraITS/tests/scene1_1/test_capture_result.py
+++ b/apps/CameraITS/tests/scene1_1/test_capture_result.py
@@ -213,7 +213,7 @@
metadata['android.tonemap.curve']['green'],
metadata['android.tonemap.curve']['blue']]
logging.debug('Tonemap: %s', str(curves[0][1::16]))
- for j, c in enumerate(curves):
+ for _, c in enumerate(curves):
if not c:
raise AssertionError('c in curves is empty.')
if not all([np.isclose(c[i], c[i+1], atol=ISCLOSE_ATOL)
diff --git a/apps/CameraITS/tests/scene1_2/test_raw_sensitivity.py b/apps/CameraITS/tests/scene1_2/test_raw_sensitivity.py
index 8c542ab..62a017b 100644
--- a/apps/CameraITS/tests/scene1_2/test_raw_sensitivity.py
+++ b/apps/CameraITS/tests/scene1_2/test_raw_sensitivity.py
@@ -63,7 +63,6 @@
camera_properties_utils.per_frame_control(props) and
not camera_properties_utils.mono_camera(props))
name_with_log_path = os.path.join(self.log_path, NAME)
- camera_fov = float(cam.calc_camera_fov(props))
# Load chart for scene (chart_distance=0 for no chart scaling)
its_session_utils.load_scene(
diff --git a/apps/CameraITS/tests/scene2_a/test_format_combos.py b/apps/CameraITS/tests/scene2_a/test_format_combos.py
index 7568da7..c05301b 100644
--- a/apps/CameraITS/tests/scene2_a/test_format_combos.py
+++ b/apps/CameraITS/tests/scene2_a/test_format_combos.py
@@ -147,7 +147,7 @@
if STOP_AT_FIRST_FAILURE:
raise AssertionError(
f'Capture fail at combo req: {req_str}, fmt: {fmt_combo}, '
- f'burst: {burst_len}')
+ f'burst: {burst_len}') from e
n += 1
num_fail = len(failures)
diff --git a/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py b/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
index e77a702..3959b42 100644
--- a/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
+++ b/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
@@ -148,7 +148,7 @@
camera_properties_utils.skip_unless(
first_api_level >= its_session_utils.ANDROID13_API_LEVEL,
'First API level should be {} or higher. Found {}.'.format(
- its_session_utils.ANDROID13_API_LEVEL, first_api_level))
+ its_session_utils.ANDROID13_API_LEVEL, first_api_level))
supported_stabilization_modes = props[
'android.control.availableVideoStabilizationModes'
diff --git a/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py b/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py
index eca64ef..06f3f12 100644
--- a/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py
+++ b/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py
@@ -182,7 +182,8 @@
for hlg10_param in hlg10_params:
video_recording_obj = cam.do_basic_recording(
- profile_id, quality, _VIDEO_RECORDING_DURATION_SECONDS, 0, hlg10_param)
+ profile_id, quality, _VIDEO_RECORDING_DURATION_SECONDS, 0,
+ hlg10_param)
logging.debug('video_recording_obj: %s', video_recording_obj)
# TODO(ruchamk): Modify video recording object to send videoFrame
# width and height instead of videoSize to avoid string operation
@@ -196,7 +197,8 @@
self.log_path])
logging.debug('Recorded video is available at: %s',
self.log_path)
- video_file_name = video_recording_obj['recordedOutputPath'].split('/')[-1]
+ video_file_name = video_recording_obj[
+ 'recordedOutputPath'].split('/')[-1]
logging.debug('video_file_name: %s', video_file_name)
key_frame_files = []
@@ -208,7 +210,8 @@
last_key_frame_file = video_processing_utils.get_key_frame_to_process(
key_frame_files)
logging.debug('last_key_frame: %s', last_key_frame_file)
- last_key_frame_path = os.path.join(self.log_path, last_key_frame_file)
+ last_key_frame_path = os.path.join(
+ self.log_path, last_key_frame_file)
# Convert lastKeyFrame to numpy array
np_image = image_processing_utils.convert_image_to_numpy_array(
@@ -222,7 +225,7 @@
max_img_value = _MAX_8BIT_IMGS
if hlg10_param:
- max_img_value = _MAX_10BIT_IMGS
+ max_img_value = _MAX_10BIT_IMGS
# Check pass/fail for fov coverage for all fmts in AR_CHECKED
fov_chk_msg = image_fov_utils.check_fov(
@@ -232,7 +235,8 @@
os.path.join(self.log_path, _NAME), quality, width, height)
fov_chk_quality_msg = f'Quality: {quality} {fov_chk_msg}'
failed_fov.append(fov_chk_quality_msg)
- image_processing_utils.write_image(np_image/max_img_value, img_name, True)
+ image_processing_utils.write_image(
+ np_image/max_img_value, img_name, True)
# Check pass/fail for aspect ratio.
ar_chk_msg = image_fov_utils.check_ar(
@@ -242,14 +246,16 @@
img_name = '%s_%s_w%d_h%d_ar.png' % (
os.path.join(self.log_path, _NAME), quality, width, height)
failed_ar.append(ar_chk_msg)
- image_processing_utils.write_image(np_image/max_img_value, img_name, True)
+ image_processing_utils.write_image(
+ np_image/max_img_value, img_name, True)
# Check pass/fail for crop.
if run_crop_test:
# Normalize the circle size to 1/4 of the image size, so that
# circle size won't affect the crop test result
crop_thresh_factor = ((min(ref_fov['w'], ref_fov['h']) / 4.0) /
- max(ref_fov['circle_w'], ref_fov['circle_h']))
+ max(ref_fov['circle_w'],
+ ref_fov['circle_h']))
crop_chk_msg = image_fov_utils.check_crop(
circle, cc_ct_gt, width, height,
f'{quality}', crop_thresh_factor)
diff --git a/apps/CameraITS/tests/scene6/test_zoom.py b/apps/CameraITS/tests/scene6/test_zoom.py
index c828ad5..d4fa21c 100644
--- a/apps/CameraITS/tests/scene6/test_zoom.py
+++ b/apps/CameraITS/tests/scene6/test_zoom.py
@@ -273,13 +273,13 @@
if circle_cropped(circle, size):
logging.debug('zoom %.2f is too large! Skip further captures', z)
break
- except AssertionError:
+ except AssertionError as e:
if z/z_list[0] >= ZOOM_MAX_THRESH:
break
else:
raise AssertionError(
f'No circle was detected for zoom ratio <= {ZOOM_MAX_THRESH}. '
- 'Please take pictures according to instructions carefully!')
+ 'Take pictures according to instructions carefully!') from e
test_data[i] = {'z': z, 'circle': circle, 'r_tol': radius_tol,
'o_tol': offset_tol, 'fl': cap_fl}
diff --git a/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py b/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py
index 713d577..8f199ce 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py
@@ -137,6 +137,8 @@
# Initialize rotation rig
rot_rig['cntl'] = self.rotator_cntl
rot_rig['ch'] = self.rotator_ch
+ if rot_rig['cntl'].lower() != 'arduino':
+ raise AssertionError(f'You must use the arduino controller for {_NAME}.')
# List of video resolutions to test
supported_preview_sizes = cam.get_supported_preview_sizes(self.camera_id)
diff --git a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
index e6eec9f..1939935 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
@@ -337,7 +337,7 @@
" smaller values of 'w', 'h', 'fps', or 'test_length'.")
if replay:
- events, frames, _, h = load_data()
+ events, frames, _, _ = load_data()
else:
with its_session_utils.ItsSession(
device_id=self.dut.serial,
diff --git a/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py b/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
index 9417d18..c834ba3 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
@@ -156,6 +156,8 @@
# Initialize rotation rig
rot_rig['cntl'] = self.rotator_cntl
rot_rig['ch'] = self.rotator_ch
+ if rot_rig['cntl'].lower() != 'arduino':
+ raise AssertionError(f'You must use the arduino controller for {_NAME}.')
# Create list of video qualities to test
supported_video_qualities = cam.get_supported_video_qualities(
diff --git a/apps/CameraITS/utils/image_processing_utils.py b/apps/CameraITS/utils/image_processing_utils.py
index d0bf08e..19d76c3 100644
--- a/apps/CameraITS/utils/image_processing_utils.py
+++ b/apps/CameraITS/utils/image_processing_utils.py
@@ -137,7 +137,7 @@
# Cut out the 4x2b LSBs and put each in bits [1:0] of their own 8b words.
lsbs = img[::, 4::5].reshape(h, w // 4)
lsbs = numpy.right_shift(
- numpy.packbits(numpy.unpackbits(lsbs).reshape(h, w // 4, 4, 2), 3), 6)
+ numpy.packbits(numpy.unpackbits(lsbs).reshape((h, w // 4, 4, 2)), 3), 6)
# Pair the LSB bits group to 0th pixel instead of 3rd pixel
lsbs = lsbs.reshape(h, w // 4, 4)[:, :, ::-1]
lsbs = lsbs.reshape(h, w)
@@ -190,7 +190,7 @@
# Cut out the 2x4b LSBs and put each in bits [3:0] of their own 8b words.
lsbs = img[::, 2::3].reshape(h, w // 2)
lsbs = numpy.right_shift(
- numpy.packbits(numpy.unpackbits(lsbs).reshape(h, w // 2, 2, 4), 3), 4)
+ numpy.packbits(numpy.unpackbits(lsbs).reshape((h, w // 2, 2, 4)), 3), 4)
# Pair the LSB bits group to pixel 0 instead of pixel 1
lsbs = lsbs.reshape(h, w // 2, 2)[:, :, ::-1]
lsbs = lsbs.reshape(h, w)
@@ -243,7 +243,7 @@
img = Image.open(io.BytesIO(jpeg_buffer))
w = img.size[0]
h = img.size[1]
- return numpy.array(img).reshape(h, w, 3) / 255.0
+ return numpy.array(img).reshape((h, w, 3)) / 255.0
def convert_image_to_numpy_array(image_path):
@@ -453,7 +453,7 @@
img = (((img.reshape(h, w, 3) - black_levels) * scale) * gains).clip(0.0, 1.0)
if apply_ccm_raw_to_rgb:
img = numpy.dot(
- img.reshape(w * h, 3), ccm.T).reshape(h, w, 3).clip(0.0, 1.0)
+ img.reshape(w * h, 3), ccm.T).reshape((h, w, 3)).clip(0.0, 1.0)
return img
@@ -938,7 +938,7 @@
ref_image = [0.1, 0.2, 0.3]
lut_max = 65536
lut = numpy.array([i*2 for i in range(lut_max)])
- x = numpy.array(ref_image).reshape(1, 1, 3)
+ x = numpy.array(ref_image).reshape((1, 1, 3))
y = apply_lut_to_image(x, lut).reshape(3).tolist()
y_ref = [i*2 for i in ref_image]
self.assertTrue(numpy.allclose(y, y_ref, atol=1/lut_max))
diff --git a/apps/CameraITS/utils/its_session_utils.py b/apps/CameraITS/utils/its_session_utils.py
index 722f586..4a6cbf9 100644
--- a/apps/CameraITS/utils/its_session_utils.py
+++ b/apps/CameraITS/utils/its_session_utils.py
@@ -134,10 +134,10 @@
try:
socket_lock.bind((ItsSession.IPADDR, ItsSession.LOCK_PORT))
break
- except (socket.error, socket.timeout):
+ except (socket.error, socket.timeout) as socket_issue:
if i == num_retries - 1:
- raise error_util.CameraItsError(self._device_id,
- 'socket lock returns error')
+ raise error_util.CameraItsError(
+ self._device_id, 'socket lock returns error') from socket_issue
else:
time.sleep(retry_wait_time_sec)
@@ -545,8 +545,9 @@
VideoRecordingObject: {
'tag': 'recordingResponse',
'objValue': {
- 'recordedOutputPath': '/storage/emulated/0/Android/data/com.android.cts.verifier'
- '/files/VideoITS/VID_20220324_080414_0_CIF_352x288.mp4',
+ 'recordedOutputPath': '/storage/emulated/0/Android/data/'
+ 'com.android.cts.verifier/files/VideoITS/'
+ 'VID_20220324_080414_0_CIF_352x288.mp4',
'quality': 'preview',
'videoSize': '352x288'
}
@@ -1478,8 +1479,8 @@
try:
build_sdk_version = int(subprocess.check_output(cmd.split()).rstrip())
logging.debug('Build SDK version: %d', build_sdk_version)
- except (subprocess.CalledProcessError, ValueError):
- raise AssertionError('No build_sdk_version.')
+ except (subprocess.CalledProcessError, ValueError) as exp_errors:
+ raise AssertionError('No build_sdk_version.') from exp_errors
return build_sdk_version
diff --git a/apps/CameraITS/utils/sensor_fusion_utils.py b/apps/CameraITS/utils/sensor_fusion_utils.py
index 0f83af9..327b233 100644
--- a/apps/CameraITS/utils/sensor_fusion_utils.py
+++ b/apps/CameraITS/utils/sensor_fusion_utils.py
@@ -146,8 +146,9 @@
time.sleep(CANAKIT_CMD_TIME) # This is critical for relay.
canakit_serial_port.write(cmd_str.encode())
- except IOError:
- raise IOError(f'Port {CANAKIT_VID}:{CANAKIT_PID} is not open!')
+ except IOError as io_error:
+ raise IOError(
+ f'Port {CANAKIT_VID}:{CANAKIT_PID} is not open!') from io_error
def canakit_set_relay_channel_state(canakit_port, ch, state):
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 0b3e811..35afa20 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -105,7 +105,9 @@
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<!-- Needed for Wi-Fi Direct tests from T -->
- <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />
+ <uses-permission
+ android:name="android.permission.NEARBY_WIFI_DEVICES"
+ android:usesPermissionFlags="neverForLocation" />
<!-- READ_LOGS User Consent Test from T -->
<uses-permission android:name="android.permission.READ_LOGS" />
diff --git a/apps/CtsVerifier/res/layout/audio_dev_notify.xml b/apps/CtsVerifier/res/layout/audio_dev_notify.xml
index e8f49ce..6fa178d 100644
--- a/apps/CtsVerifier/res/layout/audio_dev_notify.xml
+++ b/apps/CtsVerifier/res/layout/audio_dev_notify.xml
@@ -38,6 +38,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
+ <Button
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_dev_notification_connect_clearmsgs_btn"
+ android:text="@string/audio_dev_notification_clearmsgs"/>
+
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputDeviceNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputDeviceNotificationsActivity.java
index a6709e7..9a5f314 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputDeviceNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputDeviceNotificationsActivity.java
@@ -81,6 +81,17 @@
mInfoView.setText(mContext.getResources().getString(
R.string.audio_devices_notification_instructions));
+ findViewById(R.id.audio_dev_notification_connect_clearmsgs_btn)
+ .setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ mConnectView.setText("");
+ mConnectReceived = false;
+ mDisconnectView.setText("");
+ mDisconnectReceived = false;
+ calculatePass();
+ }
+ });
+
AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
audioManager.registerAudioDeviceCallback(new TestAudioDeviceCallback(), null);
@@ -90,6 +101,8 @@
setInfoResources(R.string.audio_in_devices_notifications_test,
R.string.audio_in_devices_infotext, -1);
setPassFailButtonClickListeners();
+
+ calculatePass();
}
@Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
index 7399f33..38d99b4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
@@ -129,6 +129,7 @@
AudioDeviceInfo routedDevice = audioRecord.getRoutedDevice();
CharSequence deviceName = routedDevice != null ? routedDevice.getProductName() : "none";
mConnectedPeripheralName = deviceName.toString();
+
int deviceType = routedDevice != null ? routedDevice.getType() : -1;
textView.setText(msg + " - " +
deviceName + " [0x" + Integer.toHexString(deviceType) + "]" +
@@ -156,8 +157,6 @@
R.id.audio_routingnotification_testresult)).setText(
"Test PASSES - No peripheral support");
}
-
- stopRecording();
}
protected void storeTestResults() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputDeviceNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputDeviceNotificationsActivity.java
index c0f98d1..5fb51c4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputDeviceNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputDeviceNotificationsActivity.java
@@ -81,6 +81,17 @@
mInfoView.setText(mContext.getResources().getString(
R.string.audio_devices_notification_instructions));
+ findViewById(R.id.audio_dev_notification_connect_clearmsgs_btn)
+ .setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ mConnectView.setText("");
+ mConnectReceived = false;
+ mDisconnectView.setText("");
+ mDisconnectReceived = false;
+ calculatePass();
+ }
+ });
+
AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
audioManager.registerAudioDeviceCallback(new TestAudioDeviceCallback(), null);
@@ -90,6 +101,8 @@
setInfoResources(R.string.audio_out_devices_notifications_test,
R.string.audio_out_devices_infotext, -1);
setPassFailButtonClickListeners();
+
+ calculatePass();
}
@Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
index e23ee17..591fe9b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
@@ -160,8 +160,6 @@
R.id.audio_routingnotification_testresult)).setText(
"Test PASSES - No peripheral support");
}
-
- stopPlayback();
}
protected void storeTestResults() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioWiredDeviceBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioWiredDeviceBaseActivity.java
index 8348393..97813af 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioWiredDeviceBaseActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioWiredDeviceBaseActivity.java
@@ -35,7 +35,7 @@
private Button mSupportsBtn;
private Button mDoesntSupportBtn;
- protected boolean mSupportsWiredPeripheral;
+ protected boolean mSupportsWiredPeripheral = true;
protected String mConnectedPeripheralName;
protected abstract void enableTestButtons(boolean enabled);
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/InputDeviceInfo.kt b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/InputDeviceInfo.kt
index 2d109ba..a3e391d 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/InputDeviceInfo.kt
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/InputDeviceInfo.kt
@@ -16,9 +16,7 @@
package com.android.compatibility.common.deviceinfo
import android.content.Context
-
import androidx.test.core.app.ApplicationProvider
-
import com.android.compatibility.common.util.DeviceConfigStateManager
import com.android.compatibility.common.util.DeviceInfoStore
@@ -35,10 +33,11 @@
collectInputInfo(store, "input")
}
- private fun readDeviceConfig(namespace: String, name: String): String {
+ private fun readDeviceConfig(namespace: String, name: String, default: String): String {
val context: Context = ApplicationProvider.getApplicationContext()
val stateManager = DeviceConfigStateManager(context, namespace, name)
- return stateManager.get()!!
+ val value = stateManager.get()
+ return if (value != null) value else default
}
/**
@@ -47,10 +46,15 @@
private fun collectInputInfo(store: DeviceInfoStore, groupName: String) {
store.startGroup(groupName)
- val palmRejectionValue = readDeviceConfig("input_native_boot", "palm_rejection_enabled")
+ val palmRejectionValue = readDeviceConfig("input_native_boot", "palm_rejection_enabled", "")
val palmRejectionEnabled = palmRejectionValue == "1" || palmRejectionValue == "true"
store.addResult("palm_rejection_enabled", palmRejectionEnabled)
+ val velocityTrackerStrategyValue = readDeviceConfig(
+ "input_native_boot", "velocitytracker_strategy", "default"
+ )
+ store.addResult("velocitytracker_strategy", velocityTrackerStrategyValue)
+
store.endGroup()
}
}
diff --git a/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java b/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java
index e7d954f..9affccb 100644
--- a/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java
+++ b/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java
@@ -82,6 +82,8 @@
// Uses internal consts defined in BackgroundDexOptService only for testing purpose.
private static final int STATUS_OK = 0;
private static final int STATUS_CANCELLED = 1;
+ // We allow package level failure in dexopt, which will lead into this error state.
+ private static final int STATUS_DEX_OPT_FAILED = 5;
private ITestDevice mDevice;
@@ -124,7 +126,7 @@
() -> getLastExecutionTime().duration >= 0);
int status = getLastDexOptStatus();
- assertThat(status).isAnyOf(STATUS_OK, STATUS_CANCELLED);
+ assertThat(status).isAnyOf(STATUS_OK, STATUS_DEX_OPT_FAILED, STATUS_CANCELLED);
if (status == STATUS_CANCELLED) {
assertThat(checkFinishedPostBootUpdate()).isFalse();
// If cancelled, we can complete it by running it again.
@@ -177,7 +179,7 @@
() -> getLastExecutionTime().duration >= 0);
int status = getLastDexOptStatus();
- assertThat(status).isAnyOf(STATUS_OK, STATUS_CANCELLED);
+ assertThat(status).isAnyOf(STATUS_OK, STATUS_DEX_OPT_FAILED, STATUS_CANCELLED);
if (status == STATUS_CANCELLED) {
// If cancelled, we can complete it by running it again.
completeIdleOptimization();
@@ -204,7 +206,7 @@
assertThat(timeAfter.startTime).isAtLeast(timeBefore.deviceCurrentTime);
assertThat(timeAfter.duration).isAtLeast(0);
int status = getLastDexOptStatus();
- assertThat(status).isEqualTo(STATUS_OK);
+ assertThat(status).isAnyOf(STATUS_OK, STATUS_DEX_OPT_FAILED);
}
private void completeIdleOptimization() throws Exception {
@@ -220,7 +222,7 @@
});
int status = getLastDexOptStatus();
- assertThat(status).isEqualTo(STATUS_OK);
+ assertThat(status).isAnyOf(STATUS_OK, STATUS_DEX_OPT_FAILED);
}
@After
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java
index c7feda6..f07f9d3 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/appops/AppOpsTests.java
@@ -61,12 +61,13 @@
protected void setUp() throws Exception {
super.setUp();
- mTransformedFromOp.clear();
- // The hotword op is allowed to all UIDs on TV and Auto devices.
- if (!(DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)
- || DeviceUtils.hasFeature(getDevice(), FEATURE_LEANBACK_ONLY))) {
- mTransformedFromOp.put(APP_OP_RECORD_AUDIO, APP_OP_RECORD_AUDIO_HOTWORD);
- }
+ // Temporarily commented out until the Trusted Hotword requirement is enforced again.
+ // mTransformedFromOp.clear();
+ // // The hotword op is allowed to all UIDs on TV and Auto devices.
+ // if (!(DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)
+ // || DeviceUtils.hasFeature(getDevice(), FEATURE_LEANBACK_ONLY))) {
+ // mTransformedFromOp.put(APP_OP_RECORD_AUDIO, APP_OP_RECORD_AUDIO_HOTWORD);
+ // }
assertThat(mCtsBuild).isNotNull();
ConfigUtils.removeConfig(getDevice());
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
index 31bb8bf..879d397 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
@@ -304,7 +304,7 @@
EdgeExtensionActivity.class, extras);
final Rect appBounds = getTopAppBounds();
assertColorChangeXIndex(screenshots,
- (appBounds.left + appBounds.right) / 4 * 3, testBounds);
+ appBounds.left + (appBounds.right - appBounds.left) * 3 / 4, testBounds);
}
/**
@@ -355,7 +355,7 @@
EdgeExtensionActivity.class, extras);
final Rect appBounds = getTopAppBounds();
assertColorChangeXIndex(screenshots,
- (appBounds.left + appBounds.right) / 4, testBounds);
+ appBounds.left + (appBounds.right - appBounds.left) / 4, testBounds);
}
/**
@@ -422,9 +422,7 @@
boolean isTransitioning;
do {
getWmState().computeState();
- isTransitioning =
- getWmState().getDefaultDisplayLastTransition().equals("TRANSIT_ACTIVITY_OPEN")
- && getWmState().getDefaultDisplayAppTransitionState()
+ isTransitioning = getWmState().getDefaultDisplayAppTransitionState()
.equals("APP_STATE_RUNNING");
SystemClock.sleep(10);
} while (!isTransitioning);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
index 669594d..e73ae81 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
@@ -756,8 +756,16 @@
final ExecutorService executor = Executors.newSingleThreadExecutor();
boolean[] securityExceptionCaught = new boolean[1];
+ Exception[] illegalArgumentException = new Exception[1];
executor.execute(() -> {
- mInstrumentation.sendPointerSync(eventDown);
+ try {
+ mInstrumentation.sendPointerSync(eventDown);
+ } catch (IllegalArgumentException e) {
+ // InputManagerService throws IllegalArgumentException when input target mismatch.
+ // Store the exception, and raise test failure later to avoid cts thread crash.
+ illegalArgumentException[0] = e;
+ return;
+ }
for (int i = 0; i < 20; i++) {
final long eventTime = SystemClock.uptimeMillis();
final MotionEvent eventMove = MotionEvent.obtain(
@@ -766,8 +774,13 @@
mInstrumentation.sendPointerSync(eventMove);
} catch (SecurityException e) {
securityExceptionCaught[0] = true;
+ return;
+ } catch (IllegalArgumentException e) {
+ illegalArgumentException[0] = e;
+ return;
}
}
+
});
// Launch another activity, should not crash the process.
@@ -783,6 +796,11 @@
// so the failure is thrown in the test thread.
fail("Should be allowed to inject event.");
}
+
+ if (illegalArgumentException[0] != null) {
+ fail("Failed to inject event due to input target mismatch: "
+ + illegalArgumentException[0].getMessage());
+ }
}
private void waitForWindow(String name) {
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
index 6395679..8cc0b8e 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
@@ -582,8 +582,8 @@
NOT_EXPECT_TIMEOUT);
final int touchSlop = getTouchSlop();
- final int startX = 50;
- final int startY = 50;
+ final int startX = editText.getWidth() / 2;
+ final int startY = editText.getHeight() / 2;
final int endX = startX + 2 * touchSlop;
final int endY = startY + 2 * touchSlop;
final int number = 5;
diff --git a/tests/net/src/android/net/cts/LocalSocketTest.java b/tests/net/src/android/net/cts/LocalSocketTest.java
index 39b5dbc..c302f81 100644
--- a/tests/net/src/android/net/cts/LocalSocketTest.java
+++ b/tests/net/src/android/net/cts/LocalSocketTest.java
@@ -30,12 +30,9 @@
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
-import android.os.ParcelFileDescriptor;
-import android.os.SystemClock;
import android.system.Os;
import android.system.OsConstants;
import android.system.StructTimeval;
-import android.system.UnixSocketAddress;
import androidx.test.runner.AndroidJUnit4;
@@ -196,7 +193,7 @@
}
// http://b/31205169
- @Test
+ @Test @IgnoreUpTo(SC_V2) // Crashes on pre-T due to a JNI bug. See http://r.android.com/2096720
public void testSetSoTimeout_readTimeout() throws Exception {
String address = ADDRESS_PREFIX + "_testSetSoTimeout_readTimeout";
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandMultiUserTest.kt b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandMultiUserTest.kt
index cf9dde0..155cf74 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandMultiUserTest.kt
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandMultiUserTest.kt
@@ -237,18 +237,18 @@
val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED)
intentFilter.addDataScheme("package")
- context.registerReceiver(
- broadcastReceiverForPrimaryUser,
- intentFilter,
- null,
- backgroundHandler,
- RECEIVER_EXPORTED
- )
uiAutomation.adoptShellPermissionIdentity(
Manifest.permission.INTERACT_ACROSS_USERS,
Manifest.permission.INTERACT_ACROSS_USERS_FULL
)
try {
+ context.createContextAsUser(primaryUser.userHandle(), 0).registerReceiver(
+ broadcastReceiverForPrimaryUser,
+ intentFilter,
+ null,
+ backgroundHandler,
+ RECEIVER_EXPORTED
+ )
context.createContextAsUser(secondaryUser.userHandle(), 0).registerReceiver(
broadcastReceiverForSecondaryUser,
intentFilter,
diff --git a/tests/tests/graphics/AndroidManifest.xml b/tests/tests/graphics/AndroidManifest.xml
index 6406133..9a1c591 100644
--- a/tests/tests/graphics/AndroidManifest.xml
+++ b/tests/tests/graphics/AndroidManifest.xml
@@ -55,6 +55,23 @@
<activity android:name="android.graphics.drawable.cts.DrawableStubActivity"
android:theme="@style/WhiteBackgroundNoWindowAnimation"
android:screenOrientation="locked"/>
+
+ <activity android:name="android.graphics.cts.EmptyActivity"
+ android:label="Empty Activity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ <activity android:name="android.graphics.cts.EmptyActivity2"
+ android:label="Empty Activity 2"
+ android:exported="true">
+ <intent-filter>
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
+ </intent-filter>
+ </activity>
<activity android:name="android.graphics.drawable.cts.AnimatedImageActivity"
android:theme="@style/WhiteBackgroundNoWindowAnimation"
android:screenOrientation="locked">
diff --git a/tests/tests/graphics/res/xml/valid_themes.xml b/tests/tests/graphics/res/xml/valid_themes.xml
index a7619d4..a7e2304 100644
--- a/tests/tests/graphics/res/xml/valid_themes.xml
+++ b/tests/tests/graphics/res/xml/valid_themes.xml
@@ -19,7 +19,7 @@
<theme color="ffb9577a">
<spritz>ffffff,fffbff,ffecf0,f9dbe2,dcbfc6,c0a4ab,a48a90,887076,6f595e,564147,3e2b31,27171c,000000,ffffff,fffbff,ffecf0,f2dde1,d5c2c6,b9a7aa,9e8c90,827276,6a5b5e,514347,3a2d30,24191c,000000,ffffff,fffbff,ffecf0,ffd9e2,e3bdc6,c6a2ab,aa8891,8d6e76,74565f,5b3f47,422931,2b151c,000000,ffffff,fffbff,f7efef,e8e1e1,ccc5c5,b0aaaa,958f90,7a7575,625d5e,4a4646,332f30,1e1b1b,000000,ffffff,fffbff,f7efef,e8e1e1,ccc5c5,b0aaaa,958f90,7a7575,625d5e,4a4646,332f30,1e1b1b,000000</spritz>
<tonal_spot>ffffff,fffbff,ffecf0,ffd9e2,ffb1c8,e494ad,c67b92,a76178,8c4a60,703348,541d32,3a071d,000000,ffffff,fffbff,ffecf0,ffd9e2,e3bdc6,c6a2ab,aa8891,8d6e76,74565f,5b3f47,422931,2b151c,000000,ffffff,fffbff,ffeee2,ffdcc1,efbd94,d1a27b,b48862,976d4a,7c5635,613f20,48290b,2e1500,000000,ffffff,fffbff,faeeef,ebe0e1,cfc4c5,b3a9aa,988e90,7d7475,645c5e,4c4546,352f30,201a1b,000000,ffffff,fffbff,ffecf0,f2dde1,d5c2c6,b9a7aa,9e8c90,827276,6a5b5e,514347,3a2d30,24191c,000000</tonal_spot>
- <vibrant>ffffff,fffbff,ffecf0,ffd9e2,ffb1c8,ff84ae,ff4896,e5007b,b90063,8e004a,650033,3e001d,000000,ffffff,fffbff,ffedec,ffdad9,f5b7b7,d79c9c,ba8382,9c6968,815252,663b3b,4c2526,331112,000000,ffffff,fffbff,ffede8,ffdbd1,ffb59f,e49982,c67f6a,a76551,8b4e3c,6e3726,532212,370d02,000000,ffffff,fffbff,ffecf0,f2dde1,d5c2c6,b9a7aa,9e8c90,827276,6a5b5e,514347,3a2d30,24191c,000000,ffffff,fffbff,ffecf0,f9dbe2,dcbfc6,c0a4ab,a48a90,887076,6f595e,564147,3e2b31,27171c,000000</vibrant>
+ <vibrant>ffffff,fffbff,ffecf0,ffd9e2,ffb1c8,ff84ae,ff4896,e5007b,b90063,8e004a,650033,3e001d,000000,ffffff,fffbff,ffedec,ffdad9,f5b7b7,d79c9c,ba8382,9c6968,815252,663b3b,4c2526,331112,000000,ffffff,fffbff,ffede8,ffdbd1,ffb59f,e49982,c67f6a,a76551,8b4e3c,6e3726,532212,370d02,000000,ffffff,fffbff,ffecf0,f6dce2,d9c0c6,bca5ab,a18b90,857176,6c5a5e,534247,3c2c30,25181c,000000,ffffff,fffbff,ffecf0,f9dbe2,dcbfc6,c0a4ab,a48a90,887076,6f595e,564147,3e2b31,27171c,000000</vibrant>
<expressive>ffffff,fbfcff,e5f2ff,c8e6ff,8bcefd,6fb2e0,5298c4,337da8,0c648e,004c6d,00344d,001e2e,000000,ffffff,fffbff,ffede6,ffdbcb,f4ba9e,d69f85,b9856c,9b6b53,80543e,653d28,4b2714,311303,000000,ffffff,fcffdd,ebf8ad,dde9a0,c1cd86,a6b16e,8b9656,717b3e,596329,424b13,2c3400,181e00,000000,ffffff,fffbff,ffedec,f4dddd,d7c1c2,bba6a7,9f8c8c,847272,6b5a5b,524343,3b2d2d,241819,000000,ffffff,fffbff,ffedec,fcdbdb,debfc0,c2a4a5,a68a8b,8a7070,715859,584142,3f2b2c,281718,000000</expressive>
<rainbow>ffffff,fffbff,ffecf0,ffd9e2,ffb1c8,f48bae,d57193,b55779,984061,7b2949,5e1132,3e001d,000000,ffffff,fffbff,ffecf0,ffd9e2,e3bdc6,c6a2ab,aa8891,8d6e76,74565f,5b3f47,422931,2b151c,000000,ffffff,fffbff,ffeee2,ffdcc1,efbd94,d1a27b,b48862,976d4a,7c5635,613f20,48290b,2e1500,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
<fruit_salad>ffffff,fffbff,f9ecff,f0dbff,dcb8ff,c598f1,a97ed4,8d64b7,744c9d,5b3383,431a6b,2c0051,000000,ffffff,fffbff,f9ecff,f0dbff,dab9f9,be9edc,a384c0,876aa4,6e528a,553b71,3e2459,280d42,000000,ffffff,fffbff,ffecf0,ffd9e2,ffb1c8,e494ad,c67b92,a76178,8c4a60,703348,541d32,3a071d,000000,ffffff,fffbff,ffecf0,f6dce2,d9c0c6,bca5ab,a18b90,857176,6c5a5e,534247,3c2c30,25181c,000000,ffffff,fffbff,ffecf0,ffd9e2,e3bdc6,c6a2ab,aa8891,8d6e76,74565f,5b3f47,422931,2b151c,000000</fruit_salad>
@@ -27,7 +27,7 @@
<theme color="ffb16407">
<spritz>ffffff,fffbff,ffeee2,f9ddc9,dcc2ae,c0a793,a48c7a,887261,6f5a4a,564334,3d2d1f,27190c,000000,ffffff,fffbff,ffeee2,f2dfd1,d6c3b6,b9a89b,9e8e82,827368,6a5c51,51443a,3a2e25,231a11,000000,ffffff,fffbff,ffeee2,ffdcc1,e2c0a5,c6a58b,a98b72,8d7159,735943,5a422d,412c19,2a1706,000000,ffffff,fffbff,f7efec,e8e1dd,ccc5c2,b0aaa7,95908d,7a7572,625d5b,4a4644,33302e,1e1b19,000000,ffffff,fffbff,f7efec,e8e1dd,ccc5c2,b0aaa7,95908d,7a7572,625d5b,4a4644,33302e,1e1b19,000000</spritz>
<tonal_spot>ffffff,fffbff,ffeee2,ffdcc1,ffb778,e09d60,c28349,a36931,87521c,6b3b04,4c2700,2e1500,000000,ffffff,fffbff,ffeee2,ffdcc1,e2c0a5,c6a58b,a98b72,8d7159,735943,5a422d,412c19,2a1706,000000,ffffff,fcffde,edf6bf,dfe7b2,c3cb98,a8b07e,8d9566,727a4d,5b6238,434a22,2d330e,181e00,000000,ffffff,fffbff,faefe8,ece0da,cfc4be,b3a9a3,988f89,7d746f,655d58,4c4541,352f2b,201b17,000000,ffffff,fffbff,ffeee2,f2dfd1,d6c3b6,b9a89b,9e8e82,827368,6a5c51,51443a,3a2e25,231a11,000000</tonal_spot>
- <vibrant>ffffff,fffbff,ffeee2,ffdcc1,ffb778,fd9000,d77900,b06200,8e4e00,6c3a00,4c2700,2e1500,000000,ffffff,fffbff,ffeedc,ffddb2,e6c08d,c9a574,ad8b5c,907144,76592f,5c421a,432c06,291800,000000,ffffff,fffbff,ffefcf,ffe090,e1c477,c4a85f,a88e48,8c7330,725c1a,584401,3d2e00,241a00,000000,ffffff,fffbff,ffeee2,f2dfd1,d6c3b6,b9a89b,9e8e82,827368,6a5c51,51443a,3a2e25,231a11,000000,ffffff,fffbff,ffeee2,f9ddc9,dcc2ae,c0a793,a48c7a,887261,6f5a4a,564334,3d2d1f,27190c,000000</vibrant>
+ <vibrant>ffffff,fffbff,ffeee2,ffdcc1,ffb778,fd9000,d77900,b06200,8e4e00,6c3a00,4c2700,2e1500,000000,ffffff,fffbff,ffeedc,ffddb2,e6c08d,c9a574,ad8b5c,907144,76592f,5c421a,432c06,291800,000000,ffffff,fffbff,ffefcf,ffe090,e1c477,c4a85f,a88e48,8c7330,725c1a,584401,3d2e00,241a00,000000,ffffff,fffbff,ffeee2,f6decd,d9c2b2,bda797,a18d7e,857364,6c5b4e,534437,3c2e22,25190f,000000,ffffff,fffbff,ffeee2,f9ddc9,dcc2ae,c0a793,a48c7a,887261,6f5a4a,564334,3d2d1f,27190c,000000</vibrant>
<expressive>ffffff,fffbff,f6edff,eaddff,d1bcff,b6a0e8,9b85cb,7f6baf,675395,4f3b7b,382463,220b4d,000000,ffffff,fffbff,fbf2b7,ece4aa,cfc890,b3ad77,98925f,7d7747,656031,4c481c,353107,1f1c00,000000,ffffff,fffbff,ffeed9,ffdeaa,ebc078,cda55f,b08b48,937030,79591b,5e4102,422c00,271900,000000,ffffff,fffbff,feeedd,efe0cf,d3c4b4,b7a99a,9b8f80,807466,675d50,4f4539,382f24,221a10,000000,ffffff,fffbff,ffeedc,f5dfc6,d8c3ab,bba891,a08e77,84735e,6b5c48,524432,3b2e1d,241a0a,000000</expressive>
<rainbow>ffffff,fffbff,ffeee2,ffdcc1,ffb778,ee9743,ce7d2b,ae640f,8e4e00,6c3a00,4c2700,2e1500,000000,ffffff,fffbff,ffeee2,ffdcc1,e2c0a5,c6a58b,a98b72,8d7159,735943,5a422d,412c19,2a1706,000000,ffffff,fcffde,edf6bf,dfe7b2,c3cb98,a8b07e,8d9566,727a4d,5b6238,434a22,2d330e,181e00,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
<fruit_salad>ffffff,fffbff,ffeced,ffd9dd,ffb2bb,f98a9b,d97181,b95767,9b4051,7d293a,5f1125,400012,000000,ffffff,fffbff,ffeced,ffd9dd,ffb2bb,e8949f,c97a85,aa606b,8e4954,72333d,561d28,3b0714,000000,ffffff,fffbff,ffeee2,ffdcc1,ffb778,e09d60,c28349,a36931,87521c,6b3b04,4c2700,2e1500,000000,ffffff,fffbff,ffeee2,f6decd,d9c2b2,bda797,a18d7e,857364,6c5b4e,534437,3c2e22,25190f,000000,ffffff,fffbff,ffeee2,ffdcc1,e2c0a5,c6a58b,a98b72,8d7159,735943,5a422d,412c19,2a1706,000000</fruit_salad>
@@ -35,7 +35,7 @@
<theme color="ff6e7f10">
<spritz>ffffff,fdfee4,f1f3d8,e3e4cb,c6c8b0,abad95,90937c,757862,5d604c,464835,2f3220,1a1d0d,000000,ffffff,fefdec,f2f2e1,e4e3d3,c7c7b7,acac9d,919283,767769,5e5f52,46483b,303126,1b1c12,000000,ffffff,fcffdd,f0f4d0,e2e5c2,c5c9a8,aaae8e,8f9375,74795b,5d6145,45492f,2e321b,1a1d08,000000,ffffff,fcffdd,f4f0ec,e5e2de,c9c6c2,adaba7,92908d,777672,5f5e5b,474744,31302e,1c1c19,000000,ffffff,fcffdd,f4f0ec,e5e2de,c9c6c2,adaba7,92908d,777672,5f5e5b,474744,31302e,1c1c19,000000</spritz>
<tonal_spot>ffffff,fcffdd,eaf8a4,dcea97,c0ce7e,a5b265,8a974e,707c36,586420,414b08,2c3400,181e00,000000,ffffff,fcffdd,f0f4d0,e2e5c2,c5c9a8,aaae8e,8f9375,74795b,5d6145,45492f,2e321b,1a1d08,000000,ffffff,f3fffa,cbfbed,bdecdf,a2d0c3,87b4a8,6d998e,527e74,3a665c,224e45,05372f,00201a,000000,ffffff,fffcf4,f3f1e8,e5e2da,c8c7bf,adaba4,92918a,77766f,5f5f58,474741,31312b,1b1c17,000000,ffffff,fefdec,f2f2e1,e4e3d3,c7c7b7,acac9d,919283,767769,5e5f52,46483b,303126,1b1c12,000000</tonal_spot>
- <vibrant>ffffff,fcffdd,e9f99b,d0f100,b7d300,9db600,859a00,6c7e00,566500,404c00,2c3400,181e00,000000,ffffff,f9ffe9,e4f8c7,d6e9ba,bacd9f,9fb286,85976d,6a7c54,53643e,3c4c28,263514,111f03,000000,ffffff,f6ffef,d0fdc6,c2eeb9,a7d29e,8cb685,729b6c,588053,41673d,2a4f28,133813,002203,000000,ffffff,fefdec,f2f2e1,e4e3d3,c7c7b7,acac9d,919283,767769,5e5f52,46483b,303126,1b1c12,000000,ffffff,fdfee4,f1f3d8,e3e4cb,c6c8b0,abad95,90937c,757862,5d604c,464835,2f3220,1a1d0d,000000</vibrant>
+ <vibrant>ffffff,fcffdd,e9f99b,d0f100,b7d300,9db600,859a00,6c7e00,566500,404c00,2c3400,181e00,000000,ffffff,f9ffe9,e4f8c7,d6e9ba,bacd9f,9fb286,85976d,6a7c54,53643e,3c4c28,263514,111f03,000000,ffffff,f6ffef,d0fdc6,c2eeb9,a7d29e,8cb685,729b6c,588053,41673d,2a4f28,133813,002203,000000,ffffff,fdfee8,f2f2dd,e3e4cf,c7c8b3,abad99,91927f,767766,5e604f,464838,2f3223,1b1d10,000000,ffffff,fdfee4,f1f3d8,e3e4cb,c6c8b0,abad95,90937c,757862,5d604c,464835,2f3220,1a1d0d,000000</vibrant>
<expressive>ffffff,fffbff,ffecf0,ffd9e2,ffb1c8,e991ad,cb7893,ac5e78,904760,733049,581932,3c031d,000000,ffffff,f4fff6,d0fbe1,c2ecd4,a6d0b8,8bb49e,719984,577e6a,406653,284e3c,0f3726,002114,000000,ffffff,f7ffed,d5fcc1,c7eeb3,acd199,91b580,779a67,5d7f4f,466739,2f4e23,19370f,042100,000000,ffffff,fafeef,eff2e4,e0e4d6,c4c8ba,a9ada0,8e9286,73786c,5b6055,44483e,2d3228,191d14,000000,ffffff,f8ffeb,ebf4dd,dde6d0,c1cab4,a6ae9a,8b9480,717966,596150,414939,2b3324,171e10,000000</expressive>
<rainbow>ffffff,fcffdd,e9f99b,d9ec7b,bdd062,a2b44a,879932,6d7d17,566500,404c00,2c3400,181e00,000000,ffffff,fcffdd,f0f4d0,e2e5c2,c5c9a8,aaae8e,8f9375,74795b,5d6145,45492f,2e321b,1a1d08,000000,ffffff,f3fffa,cbfbed,bdecdf,a2d0c3,87b4a8,6d998e,527e74,3a665c,224e45,05372f,00201a,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
<fruit_salad>ffffff,fffbff,ffeede,ffddb8,ffb960,e59c37,c7821d,a66800,865300,653e00,472a00,2b1700,000000,ffffff,fffbff,ffeede,ffddb8,f8bb71,daa059,bc8642,9e6c2a,825513,653e00,472a00,2b1700,000000,ffffff,fcffdd,eaf8a4,dcea97,c0ce7e,a5b265,8a974e,707c36,586420,414b08,2c3400,181e00,000000,ffffff,fdfee8,f2f2dd,e3e4cf,c7c8b3,abad99,91927f,767766,5e604f,464838,2f3223,1b1d10,000000,ffffff,fcffdd,f0f4d0,e2e5c2,c5c9a8,aaae8e,8f9375,74795b,5d6145,45492f,2e321b,1a1d08,000000</fruit_salad>
@@ -43,7 +43,7 @@
<theme color="ff008673">
<spritz>ffffff,f3fffa,e2f5ee,d4e7e0,b8cbc4,9dafa9,83958f,687a74,51625d,3a4a46,23342f,0e1e1b,000000,ffffff,f4fffa,e9f3ef,dbe5e0,bec9c5,a3ada9,89938f,6e7875,57605d,3f4946,293230,141d1b,000000,ffffff,f3fffa,dbf7ee,cde8e0,b1ccc4,96b1a9,7c968f,627b74,4a635d,334b45,1d352f,06201b,000000,ffffff,fdfcfa,f2f0ef,e3e2e1,c7c6c5,ababaa,91918f,767675,5e5e5d,464746,2f3130,1b1c1b,000000,ffffff,fdfcfa,f2f0ef,e3e2e1,c7c6c5,ababaa,91918f,767675,5e5e5d,464746,2f3130,1b1c1b,000000</spritz>
<tonal_spot>ffffff,f3fffa,b6ffed,a0f2de,84d6c2,69baa7,4d9f8d,2e8373,056b5b,005144,00382f,00201a,000000,ffffff,f3fffa,dbf7ee,cde8e0,b1ccc4,96b1a9,7c968f,627b74,4a635d,334b45,1d352f,06201b,000000,ffffff,fcfcff,e5f2ff,c8e6ff,abcae4,90afc8,7594ac,5b7a91,436278,2b4a5f,113348,001e2f,000000,ffffff,fafdfa,eff1ef,e0e3e1,c4c7c5,a9acaa,8e918f,737775,5c5f5d,444746,2e3130,191c1b,000000,ffffff,f4fffa,e9f3ef,dbe5e0,bec9c5,a3ada9,89938f,6e7875,57605d,3f4946,293230,141d1b,000000</tonal_spot>
- <vibrant>ffffff,f3fffa,b6ffed,00fedc,00dfc1,00c1a6,00a38c,008572,006b5b,005144,00382f,00201a,000000,ffffff,f1fffe,c9faf8,bbecea,a0cfce,85b4b2,6b9998,507e7d,386665,1e4e4d,003736,00201f,000000,ffffff,f6feff,d1f8ff,a9eefa,8dd1dd,72b6c1,579ba6,3a808b,1b6772,004f58,00363d,001f24,000000,ffffff,f4fffa,e9f3ef,dbe5e0,bec9c5,a3ada9,89938f,6e7875,57605d,3f4946,293230,141d1b,000000,ffffff,f3fffa,e2f5ee,d4e7e0,b8cbc4,9dafa9,83958f,687a74,51625d,3a4a46,23342f,0e1e1b,000000</vibrant>
+ <vibrant>ffffff,f3fffa,b6ffed,00fedc,00dfc1,00c1a6,00a38c,008572,006b5b,005144,00382f,00201a,000000,ffffff,f1fffe,c9faf8,bbecea,a0cfce,85b4b2,6b9998,507e7d,386665,1e4e4d,003736,00201f,000000,ffffff,f6feff,d1f8ff,a9eefa,8dd1dd,72b6c1,579ba6,3a808b,1b6772,004f58,00363d,001f24,000000,ffffff,f3fffa,e6f4ee,d7e6e0,bbcac4,a0aea9,86948f,6b7975,54615d,3c4946,26332f,111e1b,000000,ffffff,f3fffa,e2f5ee,d4e7e0,b8cbc4,9dafa9,83958f,687a74,51625d,3a4a46,23342f,0e1e1b,000000</vibrant>
<expressive>ffffff,fffbff,ffeee2,ffdcc1,ffb779,e59b57,c68140,a76728,8b5011,6c3a00,4c2700,2e1500,000000,ffffff,fafdff,def4ff,c0e9fb,a5cdde,8ab1c2,7096a7,557b8b,3d6473,244c5a,063543,001f29,000000,ffffff,f1ffff,bbfcff,a8eff2,8cd2d5,70b7ba,559c9f,388183,19686b,004f52,003739,002021,000000,ffffff,f4fefd,e8f3f2,dae5e3,bec9c8,a3adac,889392,6e7877,566060,3f4948,293232,141d1d,000000,ffffff,f1fffe,e2f5f3,d3e6e5,b8cac9,9dafae,829493,687979,506261,394a49,233333,0e1e1e,000000</expressive>
<rainbow>ffffff,f3fffa,b6ffed,78f8dd,59dbc1,35bfa6,00a38c,008572,006b5b,005144,00382f,00201a,000000,ffffff,f3fffa,dbf7ee,cde8e0,b1ccc4,96b1a9,7c968f,627b74,4a635d,334b45,1d352f,06201b,000000,ffffff,fcfcff,e5f2ff,c8e6ff,abcae4,90afc8,7594ac,5b7a91,436278,2b4a5f,113348,001e2f,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
<fruit_salad>ffffff,f9ffe7,dafca7,c6f08a,abd471,90b759,779c41,5d8128,466810,324f00,213600,111f00,000000,ffffff,f9ffe7,ddfbaf,cfeda2,b3d088,98b56f,7e9a57,647e3f,4d662a,364e14,213600,111f00,000000,ffffff,f3fffa,b6ffed,a0f2de,84d6c2,69baa7,4d9f8d,2e8373,056b5b,005144,00382f,00201a,000000,ffffff,f3fffa,e6f4ee,d7e6e0,bbcac4,a0aea9,86948f,6b7975,54615d,3c4946,26332f,111e1b,000000,ffffff,f3fffa,dbf7ee,cde8e0,b1ccc4,96b1a9,7c968f,627b74,4a635d,334b45,1d352f,06201b,000000</fruit_salad>
@@ -51,7 +51,7 @@
<theme color="ff007fb4">
<spritz>ffffff,fbfcff,e6f2fe,d8e4ef,bcc8d3,a1adb7,86929d,6c7781,546069,3d4851,26323a,121d25,000000,ffffff,fbfcff,ebf1f8,dde3ea,c1c7ce,a6acb2,8b9198,70777d,595f65,41484d,2b3136,161c21,000000,ffffff,fbfcff,e5f2ff,d2e5f5,b7c9d8,9cadbd,8193a2,677886,4f606e,384956,21323f,0b1d29,000000,ffffff,fefcfc,f2f0f1,e4e2e3,c7c6c7,acabac,919091,767677,5e5e5f,464748,303031,1b1c1c,000000,ffffff,fefcfc,f2f0f1,e4e2e3,c7c6c7,acabac,919091,767677,5e5e5f,464748,303031,1b1c1c,000000</spritz>
<tonal_spot>ffffff,fbfcff,e5f2ff,c8e6ff,94cdf6,78b2da,5d97be,407ca1,246488,004c6d,00344d,001e2e,000000,ffffff,fbfcff,e5f2ff,d2e5f5,b7c9d8,9cadbd,8193a2,677886,4f606e,384956,21323f,0b1d29,000000,ffffff,fffbff,f6edff,e9ddff,cdc0e8,b2a5cc,978bb1,7c7095,63597c,4b4163,342b4b,1f1635,000000,ffffff,fcfcff,f0f0f3,e2e2e5,c5c6c9,aaabae,8f9193,747679,5d5e61,454749,2e3133,191c1e,000000,ffffff,fbfcff,ebf1f8,dde3ea,c1c7ce,a6acb2,8b9198,70777d,595f65,41484d,2b3136,161c21,000000</tonal_spot>
- <vibrant>ffffff,fbfcff,e5f2ff,c8e6ff,87ceff,0eb6ff,009ad9,007eb2,006590,004c6d,00344d,001e2e,000000,ffffff,fdfcff,ebf1ff,d4e3ff,b3c8e9,98accc,7e92b1,637795,4c5f7c,344863,1d314b,051c35,000000,ffffff,fefbff,efefff,dce1ff,b8c4fa,9da9dd,838ec1,6874a4,505c8b,384472,212e5a,0a1844,000000,ffffff,fbfcff,ebf1f8,dde3ea,c1c7ce,a6acb2,8b9198,70777d,595f65,41484d,2b3136,161c21,000000,ffffff,fbfcff,e6f2fe,d8e4ef,bcc8d3,a1adb7,86929d,6c7781,546069,3d4851,26323a,121d25,000000</vibrant>
+ <vibrant>ffffff,fbfcff,e5f2ff,c8e6ff,87ceff,0eb6ff,009ad9,007eb2,006590,004c6d,00344d,001e2e,000000,ffffff,fdfcff,ebf1ff,d4e3ff,b3c8e9,98accc,7e92b1,637795,4c5f7c,344863,1d314b,051c35,000000,ffffff,fefbff,efefff,dce1ff,b8c4fa,9da9dd,838ec1,6874a4,505c8b,384472,212e5a,0a1844,000000,ffffff,fbfcff,e9f2fb,dbe4ed,bfc8d0,a3acb5,89929a,6e777f,575f67,3f484f,293138,141d23,000000,ffffff,fbfcff,e6f2fe,d8e4ef,bcc8d3,a1adb7,86929d,6c7781,546069,3d4851,26323a,121d25,000000</vibrant>
<expressive>ffffff,fcffdd,e9f99a,dbeb8e,bfce75,a4b35c,8a9845,6f7c2d,586416,414c00,2c3400,191e00,000000,ffffff,fffbff,ffebfa,fed7f9,e0bbdd,c4a0c1,a886a6,8c6c8a,735572,593d59,412742,2a122c,000000,ffffff,fdfcff,eaf1ff,d2e4ff,a7c9f6,8caed9,7293bd,5778a1,3f6088,25496f,073257,001c37,000000,ffffff,fdfcff,edf1fa,dfe2eb,c3c6cf,a7abb4,8d9199,72767e,5a5f66,43474e,2c3137,171c22,000000,ffffff,fdfcff,eaf1ff,dbe3f1,bfc7d5,a4acb9,89919e,6f7783,575f6b,3f4753,29313c,141c26,000000</expressive>
<rainbow>ffffff,fbfcff,e5f2ff,c8e6ff,87ceff,55b4ed,3399d1,007eb2,006590,004c6d,00344d,001e2e,000000,ffffff,fbfcff,e5f2ff,d2e5f5,b7c9d8,9cadbd,8193a2,677886,4f606e,384956,21323f,0b1d29,000000,ffffff,fffbff,f6edff,e9ddff,cdc0e8,b2a5cc,978bb1,7c7095,63597c,4b4163,342b4b,1f1635,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
<fruit_salad>ffffff,f2fffc,b1fff7,71f7ec,50dbd0,25beb5,00a299,00847d,006a64,00504b,003734,00201e,000000,ffffff,f2fffc,b1fff7,9df2e9,81d5cd,65b9b2,489e97,28837c,006a64,00504b,003734,00201e,000000,ffffff,fbfcff,e5f2ff,c8e6ff,94cdf6,78b2da,5d97be,407ca1,246488,004c6d,00344d,001e2e,000000,ffffff,fbfcff,e9f2fb,dbe4ed,bfc8d0,a3acb5,89929a,6e777f,575f67,3f484f,293138,141d23,000000,ffffff,fbfcff,e5f2ff,d2e5f5,b7c9d8,9cadbd,8193a2,677886,4f606e,384956,21323f,0b1d29,000000</fruit_salad>
@@ -59,7 +59,7 @@
<theme color="ff8267c2">
<spritz>ffffff,fffbff,f6edff,e8dff2,cbc3d5,afa8b9,958e9e,797383,615c6b,494453,332e3c,1d1a26,000000,ffffff,fffbff,f5eefa,e7e0eb,cac4cf,afa9b4,948f99,79747e,615d66,49454e,322f37,1d1a22,000000,ffffff,fffbff,f6edff,e8def8,ccc2db,b0a7bf,958da4,7a7289,625b70,4a4458,332d41,1e192b,000000,ffffff,fffbff,f4eff1,e6e1e3,c9c5c7,aeaaac,939092,787577,605e5f,484648,313031,1c1b1d,000000,ffffff,fffbff,f4eff1,e6e1e3,c9c5c7,aeaaac,939092,787577,605e5f,484648,313031,1c1b1d,000000</spritz>
<tonal_spot>ffffff,fffbff,f6edff,e9ddff,d0bcfe,b5a1e1,9987c4,7e6ca8,66558e,4e3d75,37265d,210f47,000000,ffffff,fffbff,f6edff,e8def8,ccc2db,b0a7bf,958da4,7a7289,625b70,4a4458,332d41,1e192b,000000,ffffff,fffbff,ffecef,ffd9e2,f0b8c7,d29dac,b58391,986977,7e525f,633b47,4a2531,31101c,000000,ffffff,fffbff,f5eff4,e6e1e6,cac5ca,aeaaae,938f94,787579,605d61,48464a,323033,1c1b1e,000000,ffffff,fffbff,f5eefa,e7e0eb,cac4cf,afa9b4,948f99,79747e,615d66,49454e,322f37,1d1a22,000000</tonal_spot>
- <vibrant>ffffff,fffbff,f6edff,e9ddff,d1bcff,b89bff,a078ff,884fff,7212ff,5700c9,3c0090,23005b,000000,ffffff,fffbff,fbecff,f4daff,d7bde4,bba2c8,a088ac,846e90,6c5778,533f5f,3b2947,251431,000000,ffffff,fffbff,ffebfa,ffd6fa,e9b6e6,cc9cc9,b082ae,936792,7a5079,603960,472348,2f0d32,000000,ffffff,fffbff,f5eefa,e7e0eb,cac4cf,afa9b4,948f99,79747e,615d66,49454e,322f37,1d1a22,000000,ffffff,fffbff,f6edff,e8dff2,cbc3d5,afa8b9,958e9e,797383,615c6b,494453,332e3c,1d1a26,000000</vibrant>
+ <vibrant>ffffff,fffbff,f6edff,e9ddff,d1bcff,b89bff,a078ff,884fff,7212ff,5700c9,3c0090,23005b,000000,ffffff,fffbff,fbecff,f4daff,d7bde4,bba2c8,a088ac,846e90,6c5778,533f5f,3b2947,251431,000000,ffffff,fffbff,ffebfa,ffd6fa,e9b6e6,cc9cc9,b082ae,936792,7a5079,603960,472348,2f0d32,000000,ffffff,fffbff,f6eefd,e7e0ee,cbc4d2,afa9b7,948e9c,797481,615c69,494551,322f3a,1d1a24,000000,ffffff,fffbff,f6edff,e8dff2,cbc3d5,afa8b9,958e9e,797383,615c6b,494453,332e3c,1d1a26,000000</vibrant>
<expressive>ffffff,f3fffa,b7ffed,94f4de,78d7c2,5bbba7,3da08d,168572,006b5b,005144,00382f,00201a,000000,ffffff,fffbff,ffecf4,ffd8ec,e9b9d3,cc9eb7,b0849c,936a81,795369,5f3c51,46263a,2f1124,000000,ffffff,fffbff,feebff,f8d8ff,e1b9ed,c49ed0,a984b5,8c6998,73527f,5a3b66,42244e,2b0e38,000000,ffffff,fffbff,f8edf8,eadfea,cdc3ce,b2a8b2,978e98,7b737d,635c65,4b454d,342e36,1f1a21,000000,ffffff,fffbff,fbecfe,ecdeef,d0c2d3,b4a7b7,998d9d,7d7281,655b69,4d4351,362d3a,201925,000000</expressive>
<rainbow>ffffff,fffbff,f6edff,e9ddff,d1bcff,b79cf7,9c82da,8167bd,684fa3,50378a,391e72,23005b,000000,ffffff,fffbff,f6edff,e8def8,ccc2db,b0a7bf,958da4,7a7289,625b70,4a4458,332d41,1e192b,000000,ffffff,fffbff,ffecef,ffd9e2,f0b8c7,d29dac,b58391,986977,7e525f,633b47,4a2531,31101c,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
<fruit_salad>ffffff,fcfcff,e8f1ff,cfe5ff,99cbff,68b1f4,4a96d8,277bbb,00629e,004a78,003355,001d34,000000,ffffff,fcfcff,e8f1ff,cfe5ff,9dcbfb,82afdf,6794c2,4b7aa6,31628d,124a73,003355,001d34,000000,ffffff,fffbff,f6edff,e9ddff,d0bcfe,b5a1e1,9987c4,7e6ca8,66558e,4e3d75,37265d,210f47,000000,ffffff,fffbff,f6eefd,e7e0ee,cbc4d2,afa9b7,948e9c,797481,615c69,494551,322f3a,1d1a24,000000,ffffff,fffbff,f6edff,e8def8,ccc2db,b0a7bf,958da4,7a7289,625b70,4a4458,332d41,1e192b,000000</fruit_salad>
diff --git a/tests/tests/graphics/src/android/graphics/cts/AnimatorLeakTest.java b/tests/tests/graphics/src/android/graphics/cts/AnimatorLeakTest.java
new file mode 100644
index 0000000..b21edd5
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/AnimatorLeakTest.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.graphics.cts;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.support.test.uiautomator.UiDevice;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import junit.framework.Assert;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AnimatorLeakTest {
+
+ @Rule
+ public ActivityTestRule<EmptyActivity> mActivityRule =
+ new ActivityTestRule<>(EmptyActivity.class, false, true);
+ public ActivityTestRule<EmptyActivity2> mActivityRule2 =
+ new ActivityTestRule<>(EmptyActivity2.class, false, false);
+
+ boolean mPaused = false;
+ boolean mPausedSet = false;
+ boolean mFinitePaused = false;
+ boolean mFinitePausedSet = false;
+ boolean mResumed = false;
+
+ @After
+ public void cleanup() {
+ Animator.setAnimatorPausingEnabled(true);
+ }
+
+ /**
+ * The approach of this test is to start animators in the main activity for the test.
+ * That activity is forced into the background and the test checks whether the animators
+ * are paused appropriately. The activity is then forced back into the foreground again
+ * and the test checks whether the animators previously paused are resumed. There are also
+ * checks to make sure that animators which should not have been paused are handled
+ * correctly.
+ */
+ @Test
+ public void testPauseResume() {
+ // Latches used to wait for each of the appropriate lifecycle events
+ final CountDownLatch animatorStartedLatch = new CountDownLatch(1);
+ // There are 2 animators which should be paused and resumed, thus a countdown of 2
+ final CountDownLatch animatorPausedLatch = new CountDownLatch(2);
+ final CountDownLatch animatorResumedLatch = new CountDownLatch(2);
+
+ // The first of these (infinite) should get paused, the second (finite) should not
+ ValueAnimator infiniteAnimator = ValueAnimator.ofFloat(0f, 1f).setDuration(1000);
+ infiniteAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ ValueAnimator finiteAnimator = ValueAnimator.ofFloat(0f, 1f).setDuration(5000);
+
+ // Now create infinite and finite AnimatorSets
+ // As above, the infinite set should get paused, the finite one should not
+ ValueAnimator infiniteAnimator1 = ValueAnimator.ofFloat(0f, 1f).setDuration(1000);
+ infiniteAnimator1.setRepeatCount(ValueAnimator.INFINITE);
+ AnimatorSet infiniteSet = new AnimatorSet();
+ infiniteSet.play(infiniteAnimator1);
+ ValueAnimator finiteAnimator1 = ValueAnimator.ofFloat(0f, 1f).setDuration(5000);
+ AnimatorSet finiteSet = new AnimatorSet();
+ finiteSet.play(finiteAnimator1);
+
+ // This listener tracks which animators get paused and resumed
+ AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ // Wait until animators start to trigger the lifecycle changes
+ animatorStartedLatch.countDown();
+ }
+
+ @Override
+ public void onAnimationPause(Animator animation) {
+ if (animation == infiniteAnimator) {
+ mPaused = true;
+ } else if (animation == infiniteSet) {
+ mPausedSet = true;
+ } else if (animation == finiteAnimator) {
+ mFinitePaused = true;
+ // end it to avoid having it interfere with future resume latch
+ animation.end();
+ return;
+ } else if (animation == finiteSet) {
+ mFinitePausedSet = true;
+ // end it to avoid having it interfere with future resume latch
+ animation.end();
+ return;
+ }
+ animatorPausedLatch.countDown();
+ }
+
+ @Override
+ public void onAnimationResume(Animator animation) {
+ mResumed = true;
+ animatorResumedLatch.countDown();
+ }
+ };
+ infiniteAnimator.addListener(listener);
+ infiniteAnimator.addPauseListener(listener);
+ finiteAnimator.addPauseListener(listener);
+ infiniteSet.addPauseListener(listener);
+ finiteSet.addPauseListener(listener);
+
+ getInstrumentation().runOnMainSync(new Runnable() {
+ public void run() {
+ Animator.setBackgroundPauseDelay(500);
+ try {
+ infiniteAnimator.start();
+ finiteAnimator.start();
+ infiniteSet.start();
+ finiteSet.start();
+ } catch (Throwable throwable) {
+ }
+ }
+ });
+ try {
+ // Wait until the animators are running to start changing the activity lifecycle
+ animatorStartedLatch.await(5, TimeUnit.SECONDS);
+
+ // First, test that animators are *not* paused when an activity goes to the background
+ // if there is another activity in the same process which is now in the foreground.
+ mActivityRule2.launchActivity(null);
+ animatorPausedLatch.await(1, TimeUnit.SECONDS);
+ Assert.assertFalse("Animator was paused", mPaused);
+ mActivityRule2.finishActivity();
+
+ // Send the activity to the background. This should cause the animators to be paused
+ // after Animator.getBackgroundPauseDelay()
+ UiDevice uiDevice = UiDevice.getInstance(getInstrumentation());
+ uiDevice.pressHome();
+
+ animatorPausedLatch.await(5, TimeUnit.SECONDS);
+
+ // It is not possible (or obvious) how to bring the activity back into the foreground.
+ // However, AnimationHandler pauses/resumes all animators for the process based on
+ // *any* visible activities in that process. So it is sufficient to launch a second
+ // activity, which should resume the animators paused when the first activity went
+ // into the background.
+ mActivityRule2.launchActivity(null);
+ animatorResumedLatch.await(5, TimeUnit.SECONDS);
+ } catch (Exception e) { }
+ Assert.assertTrue("Animator was not paused", mPaused);
+ Assert.assertTrue("AnimatorSet was not paused", mPausedSet);
+ Assert.assertFalse("Non-infinite Animator was paused", mFinitePaused);
+ Assert.assertFalse("Non-infinite AnimatorSet was paused", mFinitePausedSet);
+ Assert.assertTrue("Animator was not resumed", mResumed);
+ Assert.assertTrue("AnimatorSet was not resumed", mResumed);
+ }
+
+ /**
+ * The approach of this test is to start animators in the main activity for the test.
+ * That activity is forced into the background and the test checks whether the animators
+ * are paused appropriately. The activity is then forced back into the foreground again
+ * and the test checks whether the animators previously paused are resumed. There are also
+ * checks to make sure that animators which should not have been paused are handled
+ * correctly.
+ */
+ @Test
+ public void testPauseDisablement() {
+ // Latches used to wait for each of the appropriate lifecycle events
+ final CountDownLatch animatorStartedLatch = new CountDownLatch(1);
+ // There are 2 animators which should be paused and resumed, thus a countdown of 2
+ final CountDownLatch animatorPausedLatch = new CountDownLatch(1);
+ final CountDownLatch animatorResumedLatch = new CountDownLatch(1);
+
+ // The first of these (infinite) should get paused, the second (finite) should not
+ ValueAnimator infiniteAnimator = ValueAnimator.ofFloat(0f, 1f).setDuration(1000);
+ infiniteAnimator.setRepeatCount(ValueAnimator.INFINITE);
+
+ // This listener tracks which animators get paused and resumed
+ AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ // Wait until animators start to trigger the lifecycle changes
+ animatorStartedLatch.countDown();
+ }
+
+ @Override
+ public void onAnimationPause(Animator animation) {
+ mPaused = true;
+ animatorPausedLatch.countDown();
+ }
+
+ @Override
+ public void onAnimationResume(Animator animation) {
+ mResumed = true;
+ animatorResumedLatch.countDown();
+ }
+ };
+ infiniteAnimator.addListener(listener);
+ infiniteAnimator.addPauseListener(listener);
+
+ getInstrumentation().runOnMainSync(new Runnable() {
+ public void run() {
+ Animator.setBackgroundPauseDelay(500);
+ Animator.setAnimatorPausingEnabled(false);
+ try {
+ infiniteAnimator.start();
+ } catch (Throwable throwable) {
+ }
+ }
+ });
+ try {
+ // Wait until the animators are running to start changing the activity lifecycle
+ animatorStartedLatch.await(5, TimeUnit.SECONDS);
+
+ // Send the activity to the background. This should cause the animators to be paused
+ // after Animator.getBackgroundPauseDelay()
+ UiDevice uiDevice = UiDevice.getInstance(getInstrumentation());
+ uiDevice.pressHome();
+
+ animatorPausedLatch.await(2, TimeUnit.SECONDS);
+
+ // It is not possible (or obvious) how to bring the activity back into the foreground.
+ // However, AnimationHandler pauses/resumes all animators for the process based on
+ // *any* visible activities in that process. So it is sufficient to launch a second
+ // activity, which should resume the animators paused when the first activity went
+ // into the background.
+ mActivityRule2.launchActivity(null);
+ animatorResumedLatch.await(2, TimeUnit.SECONDS);
+ } catch (Exception e) { }
+ Assert.assertFalse("Animator paused when pausing disabled", mPaused);
+ Assert.assertFalse("Animator resumed when pausing disabled", mResumed);
+ }
+
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/EmptyActivity.java b/tests/tests/graphics/src/android/graphics/cts/EmptyActivity.java
new file mode 100644
index 0000000..5ae6cd3
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/EmptyActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.graphics.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+/**
+ * Empty activity
+ */
+public final class EmptyActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Button b = new Button(this);
+ b.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
+ b.setText("My Button 1111");
+ setContentView(b);
+ }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/EmptyActivity2.java b/tests/tests/graphics/src/android/graphics/cts/EmptyActivity2.java
new file mode 100644
index 0000000..da0b8a6
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/EmptyActivity2.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.graphics.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+/**
+ * Empty activity - this one exists in addition to EmptyActivity when an app
+ * needs two launch 2 separate activities.
+ */
+public final class EmptyActivity2 extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Button b = new Button(this);
+ b.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
+ b.setText("My Button 22222");
+ setContentView(b);
+ }
+}
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
index 68d80e3..73ba7c3 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
@@ -41,7 +41,6 @@
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTimestamp;
-import android.media.AudioTrack;
import android.media.Image;
import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
@@ -4611,7 +4610,7 @@
assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
- // starts video playback
+ // Starts video playback
mMediaCodecPlayer.startThread();
sleepUntil(() ->
mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
@@ -4626,82 +4625,97 @@
// Keep buffering video content but stop buffering audio content -> audio underrun
mMediaCodecPlayer.simulateAudioUnderrun(true);
- // Loop to wait for audio underrun
- // TODO(b/200280965): Find a more appropriate delay based on partner feedback
+
+ // Wait for audio underrun
final int audioUnderrunTimeoutMs = 1000; // Arbitrary upper time limit on loop time duration
long startTimeMs = System.currentTimeMillis();
- AudioTimestamp previousTimestamp;
- while ((previousTimestamp = mMediaCodecPlayer.getTimestamp()) == null) {
- assertTrue(String.format("No audio timestamp after %d milliseconds",
+ AudioTimestamp currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ AudioTimestamp underrunAudioTimestamp;
+ do {
+ assertTrue(String.format("No audio underrun after %d milliseconds",
System.currentTimeMillis() - startTimeMs),
System.currentTimeMillis() - startTimeMs < audioUnderrunTimeoutMs);
+ underrunAudioTimestamp = currentAudioTimestamp;
Thread.sleep(50);
- }
- AudioTimestamp underrunAudioTimestamp;
- while ((underrunAudioTimestamp = mMediaCodecPlayer.getTimestamp()) != previousTimestamp) {
- assertTrue(String.format("No audio underrun after %d milliseconds",
- audioUnderrunTimeoutMs),
- System.currentTimeMillis() - startTimeMs < audioUnderrunTimeoutMs);
- previousTimestamp = underrunAudioTimestamp;
- Thread.sleep(50);
- }
- // Loop to wait until video playback stalls
- long previousVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
- long underrunVideoTimeUs;
- startTimeMs = System.currentTimeMillis();
- // TODO(b/200280965): Find a more appropriate delay based on partner feedback
+ currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ } while (currentAudioTimestamp.framePosition != underrunAudioTimestamp.framePosition);
+
+
+ // Wait until video playback stalls
final int videoUnderrunTimeoutMs = 1000;
- while ((underrunVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs()) != previousVideoTimeUs) {
+ startTimeMs = System.currentTimeMillis();
+ long currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+ long underrunVideoTimeUs = -1;
+ do {
assertTrue(String.format("No video underrun after %d milliseconds",
videoUnderrunTimeoutMs),
System.currentTimeMillis() - startTimeMs < videoUnderrunTimeoutMs);
- previousVideoTimeUs = underrunVideoTimeUs;
+ underrunVideoTimeUs = currentVideoTimeUs;
Thread.sleep(50);
- }
+ currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+ } while (currentVideoTimeUs != underrunVideoTimeUs);
- final int underrunVideoRenderedTimestampIndex =
+ // Retrieve index for the video rendered frame at the time of underrun
+ int underrunVideoRenderedTimestampIndex =
mMediaCodecPlayer.getRenderedVideoFrameTimestampList().size() - 1;
+
// Resume audio buffering with a negative offset, in order to simulate a desynchronisation.
// TODO(b/202710709): Use timestamp relative to last played video frame before pause
mMediaCodecPlayer.setAudioTrackOffsetMs(-100);
mMediaCodecPlayer.simulateAudioUnderrun(false);
- // Loop to wait until audio playback resumes
+ // Wait until audio playback resumes
+ final int audioResumeTimeoutMs = 1000;
startTimeMs = System.currentTimeMillis();
- AudioTimestamp postResumeTimestamp;
- while ((postResumeTimestamp = mMediaCodecPlayer.getTimestamp()) == underrunAudioTimestamp) {
+ currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ AudioTimestamp postResumeAudioTimestamp;
+ do {
assertTrue(String.format("Audio has not resumed after %d milliseconds",
- audioUnderrunTimeoutMs),
- System.currentTimeMillis() - startTimeMs < audioUnderrunTimeoutMs);
+ audioResumeTimeoutMs),
+ System.currentTimeMillis() - startTimeMs < audioResumeTimeoutMs);
+ postResumeAudioTimestamp = currentAudioTimestamp;
Thread.sleep(50);
- }
+ currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ } while(currentAudioTimestamp.framePosition == postResumeAudioTimestamp.framePosition);
- long resumeAudioSystemTime = interpolateSystemTimeAt(
- underrunAudioTimestamp.framePosition + 1, postResumeTimestamp,
- mMediaCodecPlayer.getAudioTrack());
-
- // Now that audio playback has resumed, loop to wait until video playback resumes
+ // Now that audio playback has resumed, wait until video playback resumes
// We care about the timestamp of the first output frame, rather than the exact time the
// video resumed, which is why we only start polling after we are sure audio playback has
// resumed.
- long resumeVideoTimeUs = 0;
+ final int videoResumeTimeoutMs = 1000;
startTimeMs = System.currentTimeMillis();
- while ((resumeVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs()) == underrunVideoTimeUs) {
+ currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+ long resumeVideoTimeUs = -1;
+ do {
assertTrue(String.format("Video has not resumed after %d milliseconds",
- videoUnderrunTimeoutMs),
- System.currentTimeMillis() - startTimeMs < videoUnderrunTimeoutMs);
+ videoResumeTimeoutMs),
+ System.currentTimeMillis() - startTimeMs < videoResumeTimeoutMs);
+ resumeVideoTimeUs = currentVideoTimeUs;
Thread.sleep(50);
- }
+ currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+ } while (currentVideoTimeUs == resumeVideoTimeUs);
- final ImmutableList<Long> renderedSystemTimeList =
- mMediaCodecPlayer.getRenderedVideoFrameSystemTimeList();
- final long resumeVideoFrameSystemTime = mMediaCodecPlayer
- .getRenderedVideoFrameSystemTimeList().get(underrunVideoRenderedTimestampIndex + 1);
- final long vsync = (long) (1000 / frameRate);
- final long avSyncOffset = resumeAudioSystemTime + 100 - resumeVideoFrameSystemTime;
- assertTrue(String.format("Audio and video tracks are more than %d milliseconds out of sync",
- vsync),
- Math.abs(avSyncOffset) <= vsync);
+ // The system time when rendering the first audio frame after the resume
+ long playbackRateFps = mMediaCodecPlayer.getAudioTrack().getPlaybackRate();
+ long playedFrames = postResumeAudioTimestamp.framePosition
+ - underrunAudioTimestamp.framePosition + 1;
+ double elapsedTimeNs = playedFrames * (1000.0 * 1000.0 * 1000.0 / playbackRateFps);
+ long resumeAudioSystemTimeNs = postResumeAudioTimestamp.nanoTime - (long) elapsedTimeNs;
+ long resumeAudioSystemTimeMs = resumeAudioSystemTimeNs / 1000 / 1000;
+
+ // The system time when rendering the first video frame after the resume
+ long resumeVideoSystemTimeMs = mMediaCodecPlayer.getRenderedVideoFrameSystemTimeList()
+ .get(underrunVideoRenderedTimestampIndex + 1) / 1000 / 1000;
+
+ // Verify that audio and video are in-sync after resume time
+ // Note: Because a -100ms PTS gap is introduced, the video should resume 100ms later
+ resumeAudioSystemTimeMs += 100;
+ long vsyncMs = 1000 / frameRate;
+ long avSyncOffsetMs = resumeAudioSystemTimeMs - resumeVideoSystemTimeMs;
+ assertTrue(String.format(
+ "Audio is %d milliseconds out of sync of video (audio:%d video:%d)",
+ avSyncOffsetMs, resumeAudioSystemTimeMs, resumeVideoSystemTimeMs),
+ Math.abs(avSyncOffsetMs) <= vsyncMs);
}
/**
@@ -4745,18 +4759,6 @@
}
/**
- * Returns the system time of the frame {@code framePosition} from {@code timestamp}, for a
- * specific {@code AudioTrack}.
- */
- private static long interpolateSystemTimeAt(long framePosition, AudioTimestamp timestamp,
- AudioTrack audioTrack) {
- final long playbackRateFps = audioTrack.getPlaybackRate(); // Frames per second
- final long playedFrames = timestamp.framePosition - framePosition;
- final double elapsedTimeNs = playedFrames * (1000000000.0 / playbackRateFps);
- return timestamp.nanoTime - (long) elapsedTimeNs;
- }
-
- /**
* Returns list of CodecCapabilities advertising support for the given MIME type.
*/
private static List<CodecCapabilities> getCodecCapabilitiesForMimeType(String mimeType) {
diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionAttributionTest.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionAttributionTest.kt
index 57efe74..31e5449 100644
--- a/tests/tests/permission3/src/android/permission3/cts/PermissionAttributionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/PermissionAttributionTest.kt
@@ -29,11 +29,9 @@
import com.android.compatibility.common.util.CtsDownstreamingTest
import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
-import com.android.modules.utils.build.SdkLevel
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
-import org.junit.Assume.assumeFalse
import org.junit.Before
import org.junit.Test
import java.util.concurrent.TimeUnit
@@ -41,19 +39,16 @@
/**
* Tests permission attribution for location providers.
*/
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+// Tests converted to GTS since these are GMS requirements not CDD.
+// These will be moved to GTS in U.
+@CtsDownstreamingTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
class PermissionAttributionTest : BasePermissionHubTest() {
private val micLabel = packageManager.getPermissionGroupInfo(
android.Manifest.permission_group.MICROPHONE, 0).loadLabel(packageManager).toString()
val locationManager = context.getSystemService(LocationManager::class.java)!!
private var wasEnabled = false
- // Permission history is not available on Auto devices running S or below.
- @Before
- fun assumeNotAutoBelowT() {
- assumeFalse(isAutomotive && !SdkLevel.isAtLeastT())
- }
-
@Before
fun installAppLocationProviderAndAllowMockLocation() {
installPackage(APP_APK_PATH, grantRuntimePermissions = true)
@@ -79,7 +74,6 @@
}
}
- @CtsDownstreamingTest
@Test
fun testLocationProviderAttributionForMicrophone() {
enableAppAsLocationProvider()
diff --git a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
index f23faae..fe9037a 100644
--- a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
+++ b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
@@ -295,7 +295,7 @@
// indicator
uiDevice.openQuickSettings()
assertPrivacyChipAndIndicatorsPresent(
- useMic || useHotword,
+ useMic,
useCamera,
chainUsage,
safetyCenterEnabled
@@ -390,11 +390,13 @@
chainUsage: Boolean,
safetyCenterEnabled: Boolean = false
) {
- // Ensure the privacy chip is present
- eventually {
- val privacyChip = uiDevice.findObject(UiSelector().resourceId(PRIVACY_CHIP_ID))
- assertTrue("view with id $PRIVACY_CHIP_ID not found", privacyChip.exists())
- privacyChip.click()
+ // Ensure the privacy chip is present (or not)
+ val chipFound = isChipPresent()
+ if (useMic || useCamera) {
+ assertTrue("Did not find chip", chipFound)
+ } else { // hotword
+ assertFalse("Found chip, but did not expect to", chipFound)
+ return
}
eventually {
@@ -455,6 +457,21 @@
assertEquals("Expected only one shell view", 1, shellView.size)
}
+ private fun isChipPresent(): Boolean {
+ var chipFound = false
+ try {
+ eventually {
+ val privacyChip = uiDevice.findObject(By.res(PRIVACY_CHIP_ID))
+ assertNotNull("view with id $PRIVACY_CHIP_ID not found", privacyChip)
+ privacyChip.click()
+ chipFound = true
+ }
+ } catch (e: Exception) {
+ // Handle more gracefully after
+ }
+ return chipFound
+ }
+
private fun pressBack() {
uiDevice.pressBack()
waitForIdle()