Merge "Add test for augmented FillRequest#getInlineSuggestionsRequest" into rvc-dev
diff --git a/apps/CameraITS/pymodules/its/cv2image.py b/apps/CameraITS/pymodules/its/cv2image.py
index d62172c..b2e9e2f 100644
--- a/apps/CameraITS/pymodules/its/cv2image.py
+++ b/apps/CameraITS/pymodules/its/cv2image.py
@@ -31,6 +31,7 @@
CHART_SCALE_STOP = 1.35
CHART_SCALE_STEP = 0.025
+FOV_THRESH_SUPER_TELE = 45
FOV_THRESH_TELE = 60
FOV_THRESH_WFOV = 90
diff --git a/apps/CameraITS/tests/scene3/scene3.pdf b/apps/CameraITS/tests/scene3/scene3.pdf
index 4c787b1..0db93f8 100644
--- a/apps/CameraITS/tests/scene3/scene3.pdf
+++ b/apps/CameraITS/tests/scene3/scene3.pdf
Binary files differ
diff --git a/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py b/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py
index 75b7a5d..94e5c6b 100644
--- a/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py
+++ b/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py
@@ -36,6 +36,50 @@
TRANS_REF_MATRIX = np.array([0, 0, 0])
+def select_ids_to_test(ids, props, chart_distance):
+ """Determine the best 2 cameras to test for the rig used.
+
+ Cameras are pre-filtered to only include supportable cameras.
+ Supportable cameras are: YUV(RGB), RAW(Bayer)
+
+ Args:
+ ids: unicode string; physical camera ids
+ props: dict; physical camera properties dictionary
+ chart_distance: float; distance to chart in meters
+ Returns:
+ test_ids to be tested
+ """
+ chart_distance = abs(chart_distance)*100 # convert M to CM
+ test_ids = []
+ for i in ids:
+ sensor_size = props[i]['android.sensor.info.physicalSize']
+ focal_l = props[i]['android.lens.info.availableFocalLengths'][0]
+ diag = math.sqrt(sensor_size['height'] ** 2 +
+ sensor_size['width'] ** 2)
+ fov = round(2 * math.degrees(math.atan(diag / (2 * focal_l))), 2)
+ print 'Camera: %s, FoV: %.2f, chart_distance: %.1fcm' % (
+ i, fov, chart_distance)
+ # determine best combo with rig used or recommend different rig
+ if its.cv2image.FOV_THRESH_TELE < fov < its.cv2image.FOV_THRESH_WFOV:
+ test_ids.append(i) # RFoV camera
+ elif fov < its.cv2image.FOV_THRESH_SUPER_TELE:
+ print 'Skipping camera. Not appropriate multi-camera testing.'
+ continue # super-TELE camera
+ elif (fov <= its.cv2image.FOV_THRESH_TELE and
+ np.isclose(chart_distance, its.cv2image.CHART_DISTANCE_RFOV, rtol=0.1)):
+ test_ids.append(i) # TELE camera in RFoV rig
+ elif (fov >= its.cv2image.FOV_THRESH_WFOV and
+ np.isclose(chart_distance, its.cv2image.CHART_DISTANCE_WFOV, rtol=0.1)):
+ test_ids.append(i) # WFoV camera in WFoV rig
+ else:
+ print 'Skipping camera. Not appropriate for test rig.'
+
+ e_msg = 'Error: started with 2+ cameras, reduced to <2. Wrong test rig?'
+ e_msg += '\ntest_ids: %s' % str(test_ids)
+ assert len(test_ids) >= 2, e_msg
+ return test_ids[0:2]
+
+
def determine_valid_out_surfaces(cam, props, fmt, cap_camera_ids, sizes):
"""Determine a valid output surfaces for captures.
@@ -331,7 +375,11 @@
props = cam.get_camera_properties()
its.caps.skip_unless(its.caps.read_3a(props) and
its.caps.per_frame_control(props) and
- its.caps.logical_multi_camera(props))
+ its.caps.logical_multi_camera(props) and
+ its.caps.backward_compatible(props))
+ debug = its.caps.debug_mode()
+ avail_fls = props['android.lens.info.availableFocalLengths']
+ pose_reference = props['android.lens.poseReference']
# Convert chart_distance for lens facing back
if props['android.lens.facing'] == LENS_FACING_BACK:
@@ -339,37 +387,40 @@
print 'lens facing BACK'
chart_distance *= -1
- # Find physical camera IDs and those that support RGB raw
+ # find physical camera IDs
ids = its.caps.logical_multi_camera_physical_ids(props)
- props_physical = {}
+ physical_props = {}
physical_ids = []
physical_raw_ids = []
for i in ids:
- # Find YUV capable physical cameras
- prop = cam.get_camera_properties_by_id(i)
- sub_camera_pose_reference = prop['android.lens.poseReference']
- if sub_camera_pose_reference == UNDEFINED_REFERENCE:
+ physical_props[i] = cam.get_camera_properties_by_id(i)
+ if physical_props[i]['android.lens.poseReference'] == UNDEFINED_REFERENCE:
continue
- physical_ids.append(i)
- props_physical[i] = prop
- # Find first 2 RAW+RGB capable physical cameras
- if (its.caps.raw16(prop) and not its.caps.mono_camera(props)
- and len(physical_raw_ids) < 2):
+ # find YUV+RGB capable physical cameras
+ if (its.caps.backward_compatible(physical_props[i]) and
+ not its.caps.mono_camera(physical_props[i])):
+ physical_ids.append(i)
+ # find RAW+RGB capable physical cameras
+ if (its.caps.backward_compatible(physical_props[i]) and
+ not its.caps.mono_camera(physical_props[i]) and
+ its.caps.raw16(physical_props[i])):
physical_raw_ids.append(i)
- debug = its.caps.debug_mode()
- avail_fls = props['android.lens.info.availableFocalLengths']
- pose_reference = props['android.lens.poseReference']
-
- # Find highest resolution image and determine formats
+ # determine formats and select cameras
fmts = ['yuv']
+ if len(physical_raw_ids) >= 2:
+ fmts.insert(0, 'raw') # add RAW to analysis if enough cameras
+ print 'Selecting RAW+RGB supported cameras'
+ physical_raw_ids = select_ids_to_test(physical_raw_ids,
+ physical_props,
+ chart_distance)
+ print 'Selecting YUV+RGB cameras'
its.caps.skip_unless(len(physical_ids) >= 2)
- if len(physical_raw_ids) == 2:
- fmts.insert(0, 'raw') # insert in first location in list
- else:
- physical_ids = ids[0:2]
+ physical_ids = select_ids_to_test(physical_ids,
+ physical_props,
+ chart_distance)
- # do captures for different formats
+ # do captures for valid formats
caps = {}
for i, fmt in enumerate(fmts):
physical_sizes = {}
@@ -379,7 +430,7 @@
capture_cam_ids = physical_raw_ids
for physical_id in capture_cam_ids:
- configs = props_physical[physical_id]['android.scaler.streamConfigurationMap']\
+ configs = physical_props[physical_id]['android.scaler.streamConfigurationMap']\
['availableStreamConfigurations']
if fmt == 'raw':
fmt_codes = 0x20
@@ -395,7 +446,7 @@
out_surfaces = determine_valid_out_surfaces(
cam, props, fmt, capture_cam_ids, physical_sizes)
caps = take_images(
- cam, caps, props_physical, fmt, capture_cam_ids, out_surfaces, debug)
+ cam, caps, physical_props, fmt, capture_cam_ids, out_surfaces, debug)
# process images for correctness
for j, fmt in enumerate(fmts):
@@ -414,7 +465,7 @@
for i in capture_cam_ids:
# process image
img = its.image.convert_capture_to_rgb_image(
- caps[(fmt, i)], props=props_physical[i])
+ caps[(fmt, i)], props=physical_props[i])
size[i] = (caps[fmt, i]['width'], caps[fmt, i]['height'])
# save images if debug
@@ -431,7 +482,7 @@
img = img.astype(np.uint8)
# load parameters for each physical camera
- ical = props_physical[i]['android.lens.intrinsicCalibration']
+ ical = physical_props[i]['android.lens.intrinsicCalibration']
assert len(ical) == 5, 'android.lens.instrisicCalibration incorrect.'
k[i] = np.array([[ical[0], ical[4], ical[2]],
[0, ical[1], ical[3]],
@@ -440,13 +491,13 @@
print 'Camera %s' % i
print ' k:', k[i]
- rotation = np.array(props_physical[i]['android.lens.poseRotation'])
+ rotation = np.array(physical_props[i]['android.lens.poseRotation'])
if j == 0:
print ' rotation:', rotation
assert len(rotation) == 4, 'poseRotation has wrong # of params.'
r[i] = rotation_matrix(rotation)
- t[i] = np.array(props_physical[i]['android.lens.poseTranslation'])
+ t[i] = np.array(physical_props[i]['android.lens.poseTranslation'])
if j == 0:
print ' translation:', t[i]
assert len(t[i]) == 3, 'poseTranslation has wrong # of params.'
@@ -469,8 +520,8 @@
print 'r:', r[i]
# Correct lens distortion to image (if available)
- if its.caps.distortion_correction(props_physical[i]) and fmt == 'raw':
- distort = np.array(props_physical[i]['android.lens.distortion'])
+ if its.caps.distortion_correction(physical_props[i]) and fmt == 'raw':
+ distort = np.array(physical_props[i]['android.lens.distortion'])
assert len(distort) == 5, 'distortion has wrong # of params.'
cv2_distort = np.array([distort[0], distort[1],
distort[3], distort[4],
@@ -490,7 +541,7 @@
# Undo zoom to image (if applicable). Assume that the maximum
# physical YUV image size is close to active array size.
if fmt == 'yuv':
- ar = props_physical[i]['android.sensor.info.activeArraySize']
+ ar = physical_props[i]['android.sensor.info.activeArraySize']
arw = ar['right'] - ar['left']
arh = ar['bottom'] - ar['top']
cr = caps[(fmt, i)]['metadata']['android.scaler.cropRegion']
@@ -504,7 +555,7 @@
circle[i][2] = circle[i][2] / zoom_ratio
# Find focal length & sensor size
- fl[i] = props_physical[i]['android.lens.info.availableFocalLengths'][0]
+ fl[i] = physical_props[i]['android.lens.info.availableFocalLengths'][0]
sensor_diag[i] = math.sqrt(size[i][0] ** 2 + size[i][1] ** 2)
i_ref, i_2nd = define_reference_camera(pose_reference, cam_reference)
diff --git a/apps/CtsVerifier/res/layout/organization_info.xml b/apps/CtsVerifier/res/layout/organization_info.xml
index 320fb8c..4921012 100644
--- a/apps/CtsVerifier/res/layout/organization_info.xml
+++ b/apps/CtsVerifier/res/layout/organization_info.xml
@@ -37,16 +37,6 @@
android:windowSoftInputMode="adjustPan"
android:padding="16dp"
android:layout_weight="1"/>
- <EditText android:id="@+id/organization_color_edit_text"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:hint="@string/provisioning_byod_organization_color_hint"
- android:gravity="top|start"
- android:digits="#0123456789abcdefABCDEF"
- android:inputType="textCapCharacters"
- android:windowSoftInputMode="adjustPan"
- android:padding="16dp"
- android:layout_weight="1" />
</LinearLayout>
<LinearLayout
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 078d24e..85aa307 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -3258,18 +3258,15 @@
<string name="provisioning_byod_organization_info">Organization Info</string>
<string name="provisioning_byod_organization_name_hint">Name</string>
- <string name="provisioning_byod_organization_color_hint">#FF00FF</string>
<string name="provisioning_byod_set_organization_info_button_text">Set</string>
<string name="provisioning_byod_organization_info_instructions">
This test verifies that the Organization Info was set correctly.
You can only do this test after you have done "select work lock" test.\n
1. Enter your organization name.\n
- 2. Enter a valid color code.\n
- 3. Press the Set button to set organization Info.\n
- 4. Press the Go button to open a dialog to confirm work credentials.\n
+ 2. Press the Set button to set organization Info.\n
+ 3. Press the Go button to open a dialog to confirm work credentials.\n
(If this device has a separate app for work settings, ignore the Go button and open the work lock screen manually to confirm, if necessary.)\n
- 5. Verify that the background color of the resulting dialog is as set by you.\n
- 6. Verify that the header text has organization name as set by you.\n
+ 4. Verify that the header text has organization name as set by you.\n
</string>
<string name="provisioning_byod_no_secure_lockscreen">No work lockscreen password set. Please run \"Select work lock test\" and rerun this test</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
index 66ff174..0f76f61 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -27,7 +27,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -367,7 +366,6 @@
} else if (ACTION_CLEAR_NOTIFICATION.equals(action)) {
mNotificationManager.cancel(NOTIFICATION_ID);
} else if (ACTION_TEST_SELECT_WORK_CHALLENGE.equals(action)) {
- mDevicePolicyManager.setOrganizationColor(mAdminReceiverComponent, Color.BLUE);
mDevicePolicyManager.setOrganizationName(mAdminReceiverComponent, getResources()
.getString(R.string.provisioning_byod_confirm_work_credentials_header));
startActivity(new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD));
@@ -389,10 +387,6 @@
.getStringExtra(OrganizationInfoTestActivity.EXTRA_ORGANIZATION_NAME);
mDevicePolicyManager.setOrganizationName(mAdminReceiverComponent, organizationName);
}
- final int organizationColor = intent.getIntExtra(
- OrganizationInfoTestActivity.EXTRA_ORGANIZATION_COLOR,
- mDevicePolicyManager.getOrganizationColor(mAdminReceiverComponent));
- mDevicePolicyManager.setOrganizationColor(mAdminReceiverComponent, organizationColor);
} else if (ACTION_TEST_PARENT_PROFILE_PASSWORD.equals(action)) {
startActivity(new Intent(DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD));
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/OrganizationInfoTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/OrganizationInfoTestActivity.java
index 7c5f374..6bf5cae 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/OrganizationInfoTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/OrganizationInfoTestActivity.java
@@ -17,11 +17,9 @@
package com.android.cts.verifier.managedprovisioning;
import android.content.Intent;
-import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
-import android.widget.Toast;
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
@@ -33,9 +31,6 @@
implements View.OnClickListener {
public static final String EXTRA_ORGANIZATION_NAME = "extra_organization_name";
- public static final String EXTRA_ORGANIZATION_COLOR = "extra_organization_color";
-
- private int mOrganizationColor;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -57,25 +52,10 @@
R.id.organization_name_edit_text);
Intent intent = new Intent(ByodHelperActivity.ACTION_SET_ORGANIZATION_INFO);
intent.putExtra(EXTRA_ORGANIZATION_NAME, organizationNameEditText.getText().toString());
- if (isOrganizationColorSet()) {
- intent.putExtra(EXTRA_ORGANIZATION_COLOR, mOrganizationColor);
- }
startActivity(intent);
} else if (view.getId() == R.id.go_button) {
Intent intent = new Intent(ByodHelperActivity.ACTION_LAUNCH_CONFIRM_WORK_CREDENTIALS);
startActivity(intent);
}
}
-
- private boolean isOrganizationColorSet() {
- EditText organizationColorEditText = (EditText) findViewById(
- R.id.organization_color_edit_text);
- try {
- mOrganizationColor = Color.parseColor(organizationColorEditText.getText().toString());
- } catch (Exception e) {
- Toast.makeText(this, "Not a valid Color value", Toast.LENGTH_SHORT).show();
- return false;
- }
- return true;
- }
}
diff --git a/hostsidetests/adb/Android.mk b/hostsidetests/adb/Android.mk
new file mode 100644
index 0000000..292bc18
--- /dev/null
+++ b/hostsidetests/adb/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_COMPATIBILITY_SUITE := cts vts10 general-tests
+LOCAL_CTS_TEST_PACKAGE := android.host.adb
+LOCAL_MODULE := CtsAdbHostTestCases
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_MODULE_TAGS := optional
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
+LOCAL_JAVA_RESOURCE_FILES := $(HOST_OUT_EXECUTABLES)/check_ms_os_desc
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
diff --git a/hostsidetests/adb/AndroidTest.xml b/hostsidetests/adb/AndroidTest.xml
new file mode 100755
index 0000000..46fcc98
--- /dev/null
+++ b/hostsidetests/adb/AndroidTest.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration description="Config for the CTS adb host tests">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="bionic" />
+ <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" />
+
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="CtsAdbHostTestCases.jar" />
+ </test>
+</configuration>
diff --git a/hostsidetests/adb/OWNERS b/hostsidetests/adb/OWNERS
new file mode 100644
index 0000000..7529cb9
--- /dev/null
+++ b/hostsidetests/adb/OWNERS
@@ -0,0 +1 @@
+include platform/system/core:/janitors/OWNERS
diff --git a/hostsidetests/adb/src/android/adb/cts/AdbHostTest.java b/hostsidetests/adb/src/android/adb/cts/AdbHostTest.java
new file mode 100644
index 0000000..f388cc3
--- /dev/null
+++ b/hostsidetests/adb/src/android/adb/cts/AdbHostTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.adb.cts;
+
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IDeviceTest;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class AdbHostTest extends DeviceTestCase implements IDeviceTest {
+ // TODO: there are too many copies of this in CTS!
+ public static File copyResourceToTempFile(String resName) throws IOException {
+ InputStream is = AdbHostTest.class.getResourceAsStream(resName);
+ File tf = File.createTempFile("AdbHostTest", ".tmp");
+ FileOutputStream os = new FileOutputStream(tf);
+ byte[] buf = new byte[8192];
+ int length;
+ while ((length = is.read(buf)) != -1) {
+ os.write(buf, 0, length);
+ }
+ os.flush();
+ os.close();
+ tf.deleteOnExit();
+ return tf;
+ }
+
+ public void testHasMsOsDescriptors() throws Exception {
+ File check_ms_os_desc = copyResourceToTempFile("/check_ms_os_desc");
+ check_ms_os_desc.setExecutable(true);
+
+ // ANDROID_SERIAL is already set correctly in our environment.
+ ProcessBuilder pb = new ProcessBuilder(check_ms_os_desc.getAbsolutePath());
+ pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
+ pb.redirectErrorStream(true);
+ Process p = pb.start();
+ int result = p.waitFor();
+ BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
+ String line;
+ StringBuilder output = new StringBuilder();
+ while ((line = br.readLine()) != null) {
+ output.append(line + "\n");
+ }
+ assertTrue("check_ms_os_desc failed:\n" + output, result == 0);
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk
index 543f310..3360f07 100644
--- a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgrade.apk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgrade.apk
index c801897..0996efe 100644
--- a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgrade.apk
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86/CtsShimPrivUpgrade.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java b/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java
index b1d07e2..1e57012 100644
--- a/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java
@@ -50,6 +50,7 @@
import android.os.Environment;
import android.os.UserHandle;
import android.os.storage.StorageManager;
+import android.provider.MediaStore;
import android.support.test.uiautomator.UiDevice;
import android.test.InstrumentationTestCase;
import android.util.Log;
@@ -196,6 +197,8 @@
// Rename to ensure that stats are updated
video.renameTo(new File(dir, System.nanoTime() + ".PnG"));
+ MediaStore.waitForIdle(getContext().getContentResolver());
+
final ExternalStorageStats afterRename = stats.queryExternalStatsForUser(UUID_DEFAULT, user);
assertMostlyEquals(17 * MB_IN_BYTES, afterRename.getTotalBytes() - before.getTotalBytes());
diff --git a/hostsidetests/graphics/gpuprofiling/app/Android.bp b/hostsidetests/graphics/gpuprofiling/app/Android.bp
index 134e0cc..6c05ece 100644
--- a/hostsidetests/graphics/gpuprofiling/app/Android.bp
+++ b/hostsidetests/graphics/gpuprofiling/app/Android.bp
@@ -17,6 +17,7 @@
srcs: [
"android_graphics_cts_GpuProfilingData.cpp",
],
+ test_suites: ["cts"],
compile_multilib: "both",
multilib: {
lib32: {
diff --git a/hostsidetests/incrementalinstall/src/android/incrementalinstall/cts/IncrementalInstallTest.java b/hostsidetests/incrementalinstall/src/android/incrementalinstall/cts/IncrementalInstallTest.java
index 5f24e6c..d847e3c 100644
--- a/hostsidetests/incrementalinstall/src/android/incrementalinstall/cts/IncrementalInstallTest.java
+++ b/hostsidetests/incrementalinstall/src/android/incrementalinstall/cts/IncrementalInstallTest.java
@@ -99,6 +99,7 @@
public void setup() throws Exception {
assumeTrue(hasIncrementalFeature());
mBuildHelper = new CompatibilityBuildHelper(getBuild());
+ assumeTrue(adbBinarySupportsIncremental());
uninstallApp(TEST_APP_PACKAGE_NAME);
assertFalse(isPackageInstalled(TEST_APP_PACKAGE_NAME));
}
@@ -402,4 +403,9 @@
private boolean hasIncrementalFeature() throws Exception {
return hasDeviceFeature(FEATURE_INCREMENTAL_DELIVERY);
}
+
+ private boolean adbBinarySupportsIncremental() throws Exception {
+ return !installWithAdbInstaller(TEST_APP_BASE_APK_NAME).contains(
+ "Unknown option --incremental");
+ }
}
diff --git a/hostsidetests/securitybulletin/AndroidTest.xml b/hostsidetests/securitybulletin/AndroidTest.xml
index 42b22c9..fe1e89c 100644
--- a/hostsidetests/securitybulletin/AndroidTest.xml
+++ b/hostsidetests/securitybulletin/AndroidTest.xml
@@ -158,6 +158,7 @@
<!--__________________-->
<!-- Bulletin 2018-01 -->
<!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+ <option name="push" value="CVE-2018-9527->/data/local/tmp/CVE-2018-9527" />
<!--__________________-->
<!-- Bulletin 2018-02 -->
@@ -188,7 +189,6 @@
<!--__________________-->
<!-- Bulletin 2018-11 -->
<!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2018-9536->/data/local/tmp/CVE-2018-9536" />
<option name="push" value="CVE-2018-9539->/data/local/tmp/CVE-2018-9539" />
<!--__________________-->
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9536/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9527/Android.bp
similarity index 73%
rename from hostsidetests/securitybulletin/securityPatch/CVE-2018-9536/Android.bp
rename to hostsidetests/securitybulletin/securityPatch/CVE-2018-9527/Android.bp
index 16f9474..c6b3bd9 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9536/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9527/Android.bp
@@ -13,15 +13,9 @@
// limitations under the License.
cc_test {
- name: "CVE-2018-9536",
+ name: "CVE-2018-9527",
defaults: ["cts_hostsidetests_securitybulletin_defaults"],
srcs: ["poc.cpp"],
- include_dirs: [
- "external/aac/libFDK/include",
- "external/aac/libSYS/include",
- "cts/hostsidetests/securitybulletin/securityPatch/includes",
- ],
- shared_libs: [
- "libbluetooth"
- ],
+ include_dirs: ["./external/tremolo"],
+ shared_libs: ["libvorbisidec"],
}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9527/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9527/poc.cpp
new file mode 100644
index 0000000..fa32eb8
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9527/poc.cpp
@@ -0,0 +1,104 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <string.h>
+#include <stdlib.h>
+#define REF_COUNT 1
+#define DECODE_PACKET 1
+
+extern "C" {
+#include <Tremolo/codec_internal.h>
+
+int _vorbis_unpack_books(vorbis_info *vi, oggpack_buffer *opb);
+int _vorbis_unpack_info(vorbis_info *vi, oggpack_buffer *opb);
+int _vorbis_unpack_comment(vorbis_comment *vc, oggpack_buffer *opb);
+}
+
+const uint8_t packInfoData[] = { 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0xBB, 0x00,
+ 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xBB, 0x01, 0xFF, 0xFF, 0xFF, 0xFF };
+
+unsigned char unpackBookData[] = { 0x00, 0x42, 0x43, 0x56, 0x1E, 0x00, 0x10,
+ 0x00, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x10, 0x0A, 0xFF, 0x00, 0x00,
+ 0x00, 0x06, 0xD0, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x1D, 0x00, 0x00, 0x00,
+ 0x2C, 0x00, 0x03, 0x3C, 0x51, 0x04, 0x34, 0x4F, 0x04, 0x00, 0x40, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xCB, 0x00, 0x40, 0x00, 0x00, 0x01, 0x4F, 0xF4,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0xFF };
+
+unsigned char bufData[] = { 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xE7,
+ 0x00, 0x00, 0xE9, 0x00 };
+
+static void makeBitReader(const void *data, size_t size, ogg_buffer *buf,
+ ogg_reference *ref, oggpack_buffer *bits) {
+ buf->data = (uint8_t *) data;
+ buf->size = size;
+ buf->refcount = REF_COUNT;
+
+ ref->buffer = buf;
+ ref->length = size;
+ oggpack_readinit(bits, ref);
+}
+
+int main() {
+ ogg_buffer buf;
+ ogg_reference ref;
+ oggpack_buffer bits;
+
+ memset(&buf, 0, sizeof(ogg_buffer));
+ memset(&ref, 0, sizeof(ogg_reference));
+ memset(&bits, 0, sizeof(oggpack_buffer));
+
+ makeBitReader(packInfoData, sizeof(packInfoData), &buf, &ref, &bits);
+
+ vorbis_info *mVi = new vorbis_info;
+ vorbis_info_init(mVi);
+
+ int ret = _vorbis_unpack_info(mVi, &bits);
+ if (!ret) {
+ memset(&buf, 0, sizeof(ogg_buffer));
+ memset(&ref, 0, sizeof(ogg_reference));
+ memset(&bits, 0, sizeof(oggpack_buffer));
+
+ makeBitReader(unpackBookData, sizeof(unpackBookData), &buf, &ref,
+ &bits);
+
+ ret = _vorbis_unpack_books(mVi, &bits);
+ if (!ret) {
+ ogg_packet pack;
+ memset(&pack, 0, sizeof(ogg_packet));
+ memset(&buf, 0, sizeof(ogg_buffer));
+ memset(&ref, 0, sizeof(ogg_reference));
+
+ vorbis_dsp_state *mState = new vorbis_dsp_state;
+ vorbis_dsp_init(mState, mVi);
+
+ buf.data = bufData;
+ buf.size = sizeof(bufData);
+ buf.refcount = REF_COUNT;
+
+ ref.buffer = &buf;
+ ref.length = buf.size;
+
+ pack.packet = &ref;
+ pack.bytes = ref.length;
+
+ vorbis_dsp_synthesis(mState, &pack, DECODE_PACKET);
+ }
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9536/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9536/poc.cpp
deleted file mode 100644
index 47d20e6..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9536/poc.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <dirent.h>
-#include <dlfcn.h>
-#include <signal.h>
-#include <string>
-#include <common.h>
-#include <FDK_bitbuffer.h>
-#define MAX_PATH_LENGTH 1035
-
-int main() {
- FILE *fp;
- char path[MAX_PATH_LENGTH];
- void *libHandle;
- static int (*real_FDK_getBitCnt)(HANDLE_FDK_BITBUF) = NULL;
- fp = popen("find / -name libbluetooth.so 2>/dev/null ", "r");
- if (fp == NULL) {
- return EXIT_SUCCESS;
- }
- while (fgets(path, sizeof(path) - 1, fp) != NULL) {
- path[strlen(path) - 1] = '\0'; /* remove \n */
-
- libHandle = dlopen(path, RTLD_LAZY);
- if (libHandle) {
- real_FDK_getBitCnt = (int (*)(
- HANDLE_FDK_BITBUF))dlsym(libHandle, "FDK_getBitCnt");
- dlclose(libHandle);
- if (real_FDK_getBitCnt) {
- pclose(fp);
- /* The symbol of function is present, it means there is no fix patch */
- return EXIT_VULNERABLE;
- }
- }
- }
- pclose(fp);
- return EXIT_SUCCESS;
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
index c4ae6b5..c403fcf 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -40,21 +40,21 @@
* existing test methods
******************************************************************************/
+ /**
+ * b/112159345
+ * Vulnerability Behaviour: SIGSEGV in self
+ **/
+ @SecurityTest(minPatchLevel = "2018-01")
+ @Test
+ public void testPocCVE_2018_9527() throws Exception {
+ AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2018-9527", null, getDevice());
+ }
/******************************************************************************
* To prevent merge conflicts, add tests for P below this comment, before any
* existing test methods
******************************************************************************/
- /**
- * b/112662184
- * Vulnerability Behaviour: EXIT_VULNERABLE (113)
- **/
- @SecurityTest(minPatchLevel = "2018-11")
- @Test
- public void testPocCVE_2018_9536() throws Exception {
- AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2018-9536", getDevice(), 60);
- }
/******************************************************************************
* To prevent merge conflicts, add tests for Q below this comment, before any
diff --git a/hostsidetests/stagedinstall/Android.bp b/hostsidetests/stagedinstall/Android.bp
index 96ab887..75ea48e 100644
--- a/hostsidetests/stagedinstall/Android.bp
+++ b/hostsidetests/stagedinstall/Android.bp
@@ -62,6 +62,8 @@
":StagedInstallTestAppSamePackageNameAsApex",
":StagedInstallTestApexV2_SdkTargetP",
":StagedInstallTestCorruptedApex_b146895998",
+ ":StagedInstallTestApexV2_NoApkSignature",
+ ":StagedInstallTestApexV2_UnsignedPayload",
],
static_libs: [
"androidx.test.runner",
@@ -448,3 +450,43 @@
filename: "corrupted_b146895998.apex",
installable: false,
}
+
+prebuilt_apex {
+ name: "StagedInstallTestApexV2_NoApkSignature",
+ arch: {
+ arm: {
+ src: "testdata/apex/arm/com.android.apex.cts.shim.v2_unsigned_apk_container.apex",
+ },
+ arm64: {
+ src: "testdata/apex/arm/com.android.apex.cts.shim.v2_unsigned_apk_container.apex",
+ },
+ x86: {
+ src: "testdata/apex/x86/com.android.apex.cts.shim.v2_unsigned_apk_container.apex",
+ },
+ x86_64: {
+ src: "testdata/apex/x86/com.android.apex.cts.shim.v2_unsigned_apk_container.apex",
+ },
+ },
+ filename: "com.android.apex.cts.shim.v2_unsigned_apk_container.apex",
+ installable: false,
+}
+
+prebuilt_apex {
+ name: "StagedInstallTestApexV2_UnsignedPayload",
+ arch: {
+ arm: {
+ src: "testdata/apex/arm/com.android.apex.cts.shim.v2_unsigned_payload.apex",
+ },
+ arm64: {
+ src: "testdata/apex/arm/com.android.apex.cts.shim.v2_unsigned_payload.apex",
+ },
+ x86: {
+ src: "testdata/apex/x86/com.android.apex.cts.shim.v2_unsigned_payload.apex",
+ },
+ x86_64: {
+ src: "testdata/apex/x86/com.android.apex.cts.shim.v2_unsigned_payload.apex",
+ },
+ },
+ filename: "com.android.apex.cts.shim.v2_unsigned_payload.apex",
+ installable: false,
+}
diff --git a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
index c5c3a09..4f5b06c 100644
--- a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
@@ -147,6 +147,13 @@
/*isApex*/true, "com.android.apex.cts.shim.v2_sdk_target_p.apex");
private static final TestApp CorruptedApex_b146895998 = new TestApp(
"StagedInstallTestCorruptedApex_b146895998", "", 1, true, "corrupted_b146895998.apex");
+ private static final TestApp Apex2NoApkSignature = new TestApp(
+ "StagedInstallTestApexV2_NoApkSignature", SHIM_PACKAGE_NAME, 1,
+ /*isApex*/true, "com.android.apex.cts.shim.v2_unsigned_apk_container.apex");
+ private static final TestApp Apex2UnsignedPayload = new TestApp(
+ "StagedInstallTestApexV2_UnsignedPayload", SHIM_PACKAGE_NAME, 1,
+ /*isApex*/true, "com.android.apex.cts.shim.v2_unsigned_payload.apex");
+
@Before
public void adoptShellPermissions() {
InstrumentationRegistry
@@ -1070,6 +1077,27 @@
assertThat(sessionInfo).isStagedSessionFailed();
}
+ /**
+ * Should fail to pass apk signature check
+ */
+ @Test
+ public void testApexWithUnsignedApkFailsVerification() throws Exception {
+ assertThat(stageSingleApk(Apex2NoApkSignature).getErrorMessage())
+ .contains("INSTALL_PARSE_FAILED_NO_CERTIFICATES");
+ }
+
+ /**
+ * Should fail to verify apex with unsigned payload
+ */
+ @Test
+ public void testApexWithUnsignedPayloadFailsVerification() throws Exception {
+ int sessionId = stageSingleApk(Apex2UnsignedPayload).assertSuccessful().getSessionId();
+ PackageInstaller.SessionInfo sessionInfo = waitForBroadcast(sessionId);
+ assertThat(sessionInfo).isStagedSessionFailed();
+ assertThat(sessionInfo.getStagedSessionErrorMessage())
+ .contains("AVB footer verification failed");
+ }
+
private static long getInstalledVersion(String packageName) {
Context context = InstrumentationRegistry.getInstrumentation().getContext();
PackageManager pm = context.getPackageManager();
diff --git a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
index 5054be4..91e83b2 100644
--- a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
@@ -537,6 +537,22 @@
runPhase("testCorruptedApexFailsVerification_b146895998");
}
+ /**
+ * Should fail to pass apk signature check
+ */
+ @Test
+ public void testApexWithUnsignedApkFailsVerification() throws Exception {
+ runPhase("testApexWithUnsignedApkFailsVerification");
+ }
+
+ /**
+ * Should fail to verify apex with unsigned payload
+ */
+ @Test
+ public void testApexWithUnsignedPayloadFailsVerification() throws Exception {
+ runPhase("testApexWithUnsignedPayloadFailsVerification");
+ }
+
private boolean isUpdatingApexSupported() throws Exception {
final String updatable = getDevice().getProperty("ro.apex.updatable");
return updatable != null && updatable.equals("true");
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v1.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v1.apex
index 0a77a65..093770b 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v1.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v1.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2.apex
index 30f0e61..b45c93a 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_file.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_file.apex
index cdbd503..2c7fb51 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_file.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_file.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_folder.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_folder.apex
index b4a2d37..4829ab7 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_folder.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_additional_folder.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex
new file mode 100644
index 0000000..8f18159
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_certificate.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_certificate.apex
index 5970eb9..15c9ebf 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_certificate.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_certificate.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_package_name.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_package_name.apex
index 8300cd7..027cc9f 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_package_name.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_package_name.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_no_hashtree.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_no_hashtree.apex
index 99c1d2e..88f4355 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_no_hashtree.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_no_hashtree.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sdk_target_p.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sdk_target_p.apex
index 7c147ad..4b4bc9c 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sdk_target_p.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sdk_target_p.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob.apex
index 3b0e8c3..db36942 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot.apex
index 45480c1..94726c8 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
index e8bf987..59f3c88 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_unsigned_apk_container.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_unsigned_apk_container.apex
new file mode 100644
index 0000000..1187674
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_unsigned_apk_container.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_unsigned_payload.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_unsigned_payload.apex
new file mode 100644
index 0000000..f6f8719
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_unsigned_payload.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_post_install_hook.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_post_install_hook.apex
index 8b20f9d..d04bf00a 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_post_install_hook.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_post_install_hook.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_pre_install_hook.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
index 454002d..9b418a0 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_wrong_sha.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_wrong_sha.apex
index 8e64b73..cee12d8 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_wrong_sha.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_wrong_sha.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3.apex
index acf3be2..73320d5 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob.apex
index b7a2d02..0358430 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob_rot.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob_rot.apex
index 07e3977..4b467f7 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob_rot.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob_rot.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v1.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v1.apex
index 0a6ec9b..085c1a9 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v1.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v1.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2.apex
index c9555a4..9ead68e 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_file.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_file.apex
index c6f6730..2c7fb51 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_file.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_file.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_folder.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_folder.apex
index cb40709..4829ab7 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_folder.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_additional_folder.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex
new file mode 100644
index 0000000..8f18159
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_certificate.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_certificate.apex
index 061f00d..15c9ebf 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_certificate.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_certificate.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_package_name.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_package_name.apex
index 89d687d..75efea3 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_package_name.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_package_name.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_no_hashtree.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_no_hashtree.apex
index c505cab..61e6bff 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_no_hashtree.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_no_hashtree.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sdk_target_p.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sdk_target_p.apex
index 961021f..4e28d6a 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sdk_target_p.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sdk_target_p.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob.apex
index 482d3d8..a084b94 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot.apex
index c461d9f..b8badc5 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
index cfdc9f0..0cced96 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_unsigned_apk_container.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_unsigned_apk_container.apex
new file mode 100644
index 0000000..5962142
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_unsigned_apk_container.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_unsigned_payload.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_unsigned_payload.apex
new file mode 100644
index 0000000..17f4d68
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_unsigned_payload.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_post_install_hook.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_post_install_hook.apex
index 9f22e23..d04bf00a 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_post_install_hook.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_post_install_hook.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_pre_install_hook.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
index 6300caf..9b418a0 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_wrong_sha.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_wrong_sha.apex
index 02dec8a..cee12d8 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_wrong_sha.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_wrong_sha.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3.apex
index 030e57d..03f1ecb 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob.apex
index 3957085..3113f25 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob_rot.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob_rot.apex
index 017096e..8c911bb 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob_rot.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob_rot.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/arm/CtsShimTargetPSdk.apk b/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/arm/CtsShimTargetPSdk.apk
index 065528c..5cd12d2 100644
--- a/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/arm/CtsShimTargetPSdk.apk
+++ b/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/arm/CtsShimTargetPSdk.apk
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/x86/CtsShimTargetPSdk.apk b/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/x86/CtsShimTargetPSdk.apk
index 065528c..5cd12d2 100644
--- a/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/x86/CtsShimTargetPSdk.apk
+++ b/hostsidetests/stagedinstall/testdata/apk/CtsShimTargetPSdk/x86/CtsShimTargetPSdk.apk
Binary files differ
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index f2dc01c..5651690 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -1885,15 +1885,17 @@
}
// Base64 encoded proto com.android.service.nano.StringListParamProto,
// which contains two strings "font_scale" and "screen_auto_brightness_adj".
- final String ENCODED = "ChpzY3JlZW5fYXV0b19icmlnaHRuZXNzX2FkagoKZm9udF9zY2FsZQ";
- final String FONT_SCALE = "font_scale";
+ final String encoded = "ChpzY3JlZW5fYXV0b19icmlnaHRuZXNzX2FkagoKZm9udF9zY2FsZQ";
+ final String font_scale = "font_scale";
SettingSnapshot snapshot = null;
// Set whitelist through device config.
Thread.sleep(WAIT_TIME_SHORT);
getDevice().executeShellCommand(
- "device_config put settings_stats SystemFeature__float_whitelist " + ENCODED);
+ "device_config put settings_stats SystemFeature__float_whitelist " + encoded);
Thread.sleep(WAIT_TIME_SHORT);
+ // Set font_scale value
+ getDevice().executeShellCommand("settings put system font_scale 1.5");
// Get SettingSnapshot as a simple gauge metric.
StatsdConfig.Builder config = createConfigBuilder();
@@ -1916,17 +1918,18 @@
assertThat(atoms.size()).isAtLeast(2);
for (Atom atom : atoms) {
SettingSnapshot settingSnapshot = atom.getSettingSnapshot();
- if (FONT_SCALE.equals(settingSnapshot.getName())) {
+ if (font_scale.equals(settingSnapshot.getName())) {
snapshot = settingSnapshot;
break;
}
}
- // Get font_scale value.
- final float fontScale = Float.parseFloat(
- getDevice().executeShellCommand("settings get system font_scale"));
+
Thread.sleep(WAIT_TIME_SHORT);
// Test the data of atom.
assertNotNull(snapshot);
+ // Get font_scale value and test value type.
+ final float fontScale = Float.parseFloat(
+ getDevice().executeShellCommand("settings get system font_scale"));
assertThat(snapshot.getType()).isEqualTo(
SettingSnapshot.SettingsValueType.ASSIGNED_FLOAT_TYPE);
assertThat(snapshot.getBoolValue()).isEqualTo(false);
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedDisplayTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedDisplayTest.java
index 721028a..0fd37c2 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedDisplayTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedDisplayTest.java
@@ -257,7 +257,7 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mActivityView = new ActivityView(this);
+ mActivityView = new ActivityView(this, null, 0, false, true);
setContentView(mActivityView);
}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/DisplayUtils.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/DisplayUtils.java
index e11c60e..862b7b8 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/DisplayUtils.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/DisplayUtils.java
@@ -16,7 +16,7 @@
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
-import static android.view.Display.FLAG_PRIVATE;
+import static android.view.Display.DEFAULT_DISPLAY;
import android.app.Activity;
import android.content.Context;
@@ -29,7 +29,6 @@
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Window;
-import android.view.WindowManager;
import com.android.compatibility.common.util.TestUtils;
@@ -37,7 +36,7 @@
* Utilities needed when interacting with the display
*/
public class DisplayUtils {
- private static final int DISPLAY_ADDED_TIMOUT_MS = 5000;
+ private static final int DISPLAY_ADDED_TIMEOUT_MS = 5000;
public static int getStatusBarHeight(Activity activity) {
final Rect rect = new Rect();
@@ -76,7 +75,11 @@
}
/**
- * Creates a virtual display and waits until it's in display list.
+ * Creates a virtual display having same size with default display and waits until it's
+ * in display list. The density of the virtual display is based on
+ * {@link DisplayMetrics#xdpi} so that the threshold of gesture detection is same as
+ * the default display's.
+ *
* @param context
* @param isPrivate if this display is a private display.
* @return virtual display.
@@ -110,17 +113,15 @@
Context.DISPLAY_SERVICE);
displayManager.registerDisplayListener(listener, null);
- final WindowManager windowManager = (WindowManager) context.getSystemService(
- Context.WINDOW_SERVICE);
final DisplayMetrics metrics = new DisplayMetrics();
- windowManager.getDefaultDisplay().getRealMetrics(metrics);
+ displayManager.getDisplay(DEFAULT_DISPLAY).getRealMetrics(metrics);
final Display display = createDisplay(context, metrics.widthPixels,
- metrics.heightPixels, metrics.densityDpi, isPrivate);
+ metrics.heightPixels, (int) metrics.xdpi, isPrivate);
try {
TestUtils.waitOn(waitObject,
() -> displayManager.getDisplay(display.getDisplayId()) != null,
- DISPLAY_ADDED_TIMOUT_MS,
+ DISPLAY_ADDED_TIMEOUT_MS,
String.format("wait for virtual display %d adding", display.getDisplayId()));
} finally {
displayManager.unregisterDisplayListener(listener);
diff --git a/tests/app/Android.bp b/tests/app/Android.bp
index aaabca6..ed63def 100644
--- a/tests/app/Android.bp
+++ b/tests/app/Android.bp
@@ -81,6 +81,41 @@
}
android_test {
+ name: "CtsDownloadManagerInstaller",
+ defaults: ["cts_defaults"],
+ libs: [
+ "android.test.runner.stubs",
+ "org.apache.http.legacy",
+ "android.test.base.stubs",
+ ],
+ static_libs: [
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ "ctstestserver",
+ "mockito-target-minus-junit4",
+ "androidx.test.rules",
+ "platform-test-annotations",
+ "androidx.test.rules",
+ ],
+ srcs: [
+ "DownloadManagerInstallerTest/src/**/*.java",
+ "src/android/app/cts/DownloadManagerTestBase.java",
+ ],
+ resource_dirs: ["app/res"],
+ asset_dirs: ["app/assets"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts10",
+ "general-tests",
+ ],
+ sdk_version: "test_current",
+ min_sdk_version: "14",
+ manifest: "DownloadManagerInstallerTest/AndroidManifest.xml",
+ test_config: "DownloadManagerInstallerTest/AndroidTest.xml",
+}
+
+android_test {
name: "CtsAppExitTestCases",
defaults: ["cts_defaults"],
libs: [
diff --git a/tests/app/DownloadManagerInstallerTest/AndroidManifest.xml b/tests/app/DownloadManagerInstallerTest/AndroidManifest.xml
new file mode 100644
index 0000000..cb0b73b
--- /dev/null
+++ b/tests/app/DownloadManagerInstallerTest/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.app.cts.downloads.installer">
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
+
+ <application android:usesCleartextTraffic="true"
+ android:networkSecurityConfig="@xml/network_security_config">
+ <uses-library android:name="android.test.runner" />
+ <uses-library android:name="org.apache.http.legacy" android:required="false" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.app.cts.downloads.installer" />
+
+</manifest>
diff --git a/tests/app/DownloadManagerInstallerTest/AndroidTest.xml b/tests/app/DownloadManagerInstallerTest/AndroidTest.xml
new file mode 100644
index 0000000..51b26eb
--- /dev/null
+++ b/tests/app/DownloadManagerInstallerTest/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for DownloadManagerInstallerTest">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="framework" />
+ <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" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsDownloadManagerInstaller.apk" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="appops set android.app.cts.downloads.installer REQUEST_INSTALL_PACKAGES allow" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="package" value="android.app.cts.downloads.installer" />
+ </test>
+
+</configuration>
diff --git a/tests/app/DownloadManagerInstallerTest/src/android/app/cts/DownloadManagerInstallerTest.java b/tests/app/DownloadManagerInstallerTest/src/android/app/cts/DownloadManagerInstallerTest.java
new file mode 100644
index 0000000..5b9e0fe
--- /dev/null
+++ b/tests/app/DownloadManagerInstallerTest/src/android/app/cts/DownloadManagerInstallerTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.DownloadManager;
+import android.content.IntentFilter;
+import android.net.Uri;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+
+@RunWith(AndroidJUnit4.class)
+public class DownloadManagerInstallerTest extends DownloadManagerTestBase {
+
+ @Test
+ public void testSetDestinationUri_otherAppObbDir() throws Exception {
+ File obbDir = mContext.getObbDir();
+
+ String otherAppObbPath = obbDir.getPath().replace(mContext.getPackageName(),
+ "android.app.cts.some_random_package");
+ File destPath = new File(otherAppObbPath);
+ destPath.mkdirs();
+
+ File destFile = new File(destPath, "test.obb");
+ deleteFromShell(destFile);
+
+ final DownloadCompleteReceiver receiver = new DownloadCompleteReceiver();
+ try {
+ IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
+ mContext.registerReceiver(receiver, intentFilter);
+
+ DownloadManager.Request requestPublic = new DownloadManager.Request(getGoodUrl());
+ requestPublic.setDestinationUri(Uri.fromFile(destFile));
+ long id = mDownloadManager.enqueue(requestPublic);
+
+ int allDownloads = getTotalNumberDownloads();
+ assertEquals(1, allDownloads);
+
+ receiver.waitForDownloadComplete(SHORT_TIMEOUT, id);
+ assertSuccessfulDownload(id, destFile);
+
+ assertRemoveDownload(id, 0);
+ } finally {
+ mContext.unregisterReceiver(receiver);
+ }
+ }
+}
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index d8b9e2a..322069b 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -125,6 +125,7 @@
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -744,6 +745,7 @@
ShortcutManager scManager =
(ShortcutManager) mContext.getSystemService(Context.SHORTCUT_SERVICE);
scManager.removeAllDynamicShortcuts();
+ scManager.removeLongLivedShortcuts(Collections.singletonList(SHARE_SHORTCUT_ID));
}
/**
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
index 9bbc779..65df6fb 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
@@ -214,7 +214,8 @@
public static final MockImeSessionRule sMockImeSessionRule = new MockImeSessionRule(
InstrumentationRegistry.getTargetContext(),
InstrumentationRegistry.getInstrumentation().getUiAutomation(),
- new ImeSettings.Builder().setInlineSuggestionsEnabled(true));
+ new ImeSettings.Builder().setInlineSuggestionsEnabled(true)
+ .setInlineSuggestionViewContentDesc(InlineUiBot.SUGGESTION_STRIP_DESC));
protected static final RequiredFeatureRule sRequiredFeatureRule =
new RequiredFeatureRule(PackageManager.FEATURE_AUTOFILL);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java
index b0747a5..f67bd5c 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SimpleSaveActivityTest.java
@@ -1575,24 +1575,24 @@
}
@Test
- public void testExplicitySaveButton() throws Exception {
- explicitySaveButtonTest(false, 0);
+ public void testExplicitlySaveButton() throws Exception {
+ explicitlySaveButtonTest(false, 0);
}
@Test
- public void testExplicitySaveButtonWhenAppClearFields() throws Exception {
- explicitySaveButtonTest(true, 0);
+ public void testExplicitlySaveButtonWhenAppClearFields() throws Exception {
+ explicitlySaveButtonTest(true, 0);
}
@Test
- public void testExplicitySaveButtonOnly() throws Exception {
- explicitySaveButtonTest(false, SaveInfo.FLAG_DONT_SAVE_ON_FINISH);
+ public void testExplicitlySaveButtonOnly() throws Exception {
+ explicitlySaveButtonTest(false, SaveInfo.FLAG_DONT_SAVE_ON_FINISH);
}
/**
* Tests scenario where service explicitly indicates which button is used to save.
*/
- private void explicitySaveButtonTest(boolean clearFieldsOnSubmit, int flags) throws Exception {
+ private void explicitlySaveButtonTest(boolean clearFieldsOnSubmit, int flags) throws Exception {
final boolean testBitmap = false;
startActivity();
mActivity.setAutoCommit(false);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineUiBot.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineUiBot.java
index 13f7ce8..1d1803a 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineUiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineUiBot.java
@@ -33,11 +33,9 @@
public final class InlineUiBot extends UiBot {
private static final String TAG = "AutoFillInlineCtsUiBot";
- //TODO: Change magic constant
- private static final String RESOURCE_ID_SUGGESTION_STRIP = "message";
+ public static final String SUGGESTION_STRIP_DESC = "MockIme Inline Suggestion View";
- private static final BySelector SUGGESTION_STRIP_SELECTOR =
- By.res("android", RESOURCE_ID_SUGGESTION_STRIP);
+ private static final BySelector SUGGESTION_STRIP_SELECTOR = By.desc(SUGGESTION_STRIP_DESC);
public InlineUiBot() {
this(UI_TIMEOUT);
diff --git a/tests/framework/base/windowmanager/jetpack/Android.bp b/tests/framework/base/windowmanager/jetpack/Android.bp
new file mode 100644
index 0000000..860f63c
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/Android.bp
@@ -0,0 +1,52 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_library_import {
+ name: "cts_window-sidecar_nodeps",
+ aars: ["window-sidecar-release.aar"],
+ sdk_version: "current",
+}
+
+java_library {
+ name: "cts_window-sidecar",
+ sdk_version: "current",
+ static_libs: [
+ "cts_window-sidecar_nodeps",
+ ],
+ installable: false,
+}
+
+android_test {
+ name: "CtsWindowManagerJetpackTestCases",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "compatibility-device-util-axt",
+ "platform-test-annotations",
+ ],
+ libs: [
+ "androidx.window.extensions",
+ "android.test.base.stubs",
+ "cts_window-sidecar",
+ ],
+ test_suites: [
+ "cts",
+ "vts",
+ "vts10",
+ "general-tests",
+ ],
+ sdk_version: "test_current",
+}
diff --git a/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml b/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
new file mode 100644
index 0000000..a664f0b
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.server.wm.jetpack"
+ android:targetSandboxVersion="2">
+
+ <application android:label="CtsWindowManagerJetpackTestCases">
+ <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="android.server.wm.jetpack.TestActivity" />
+ <activity android:name="android.server.wm.jetpack.TestConfigChangeHandlingActivity"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen"
+ />
+ </application>
+
+ <!-- self-instrumenting test package. -->
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="CTS tests of Jetpack Window Manager"
+ android:targetPackage="android.server.wm.jetpack" >
+ </instrumentation>
+</manifest>
diff --git a/tests/framework/base/windowmanager/jetpack/AndroidTest.xml b/tests/framework/base/windowmanager/jetpack/AndroidTest.xml
new file mode 100644
index 0000000..d4d2af2
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<configuration description="Config for CTS Jetpack WindowManager test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="framework"/>
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="CtsWindowManagerJetpackTestCases.apk"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="android.server.wm.jetpack"/>
+ </test>
+</configuration>
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionTest.java
new file mode 100644
index 0000000..4e67f8a
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionTest.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeFalse;
+
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.server.wm.jetpack.wrapper.TestDeviceState;
+import android.server.wm.jetpack.wrapper.TestDisplayFeature;
+import android.server.wm.jetpack.wrapper.TestInterfaceCompat;
+import android.server.wm.jetpack.wrapper.TestWindowLayoutInfo;
+
+import androidx.annotation.NonNull;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+
+import com.google.common.collect.BoundType;
+import com.google.common.collect.Range;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+/**
+ * Tests for the {@link androidx.window.extensions} implementation provided on the device (and only
+ * if one is available).
+ *
+ * Build/Install/Run:
+ * atest CtsWindowManagerJetpackTestCases:ExtensionTest
+ */
+// TODO(b/155343832) add a foldable presubmit target.
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class ExtensionTest extends JetpackExtensionTestBase {
+ private ActivityTestRule<TestActivity> mActivityTestRule = new ActivityTestRule<>(
+ TestActivity.class, false /* initialTouchMode */, true /* launchActivity */);
+ private ActivityTestRule<TestConfigChangeHandlingActivity> mConfigHandlingActivityTestRule =
+ new ActivityTestRule<>(TestConfigChangeHandlingActivity.class,
+ false /* initialTouchMode */, false /* launchActivity */);
+
+ /**
+ * This chain rule will launch TestActivity before each test starts, and cleanup both activities
+ * after each test finishes.
+ */
+ @Rule
+ public TestRule chain =
+ RuleChain.outerRule(mActivityTestRule).around(mConfigHandlingActivityTestRule);
+
+ private TestActivity mActivity;
+ private TestInterfaceCompat mExtension;
+ private IBinder mWindowToken;
+
+ @Before
+ public void setUp() {
+ mActivity = mActivityTestRule.getActivity();
+ ExtensionUtils.assumeSupportedDevice(mActivity);
+
+ mExtension = ExtensionUtils.getInterfaceCompat(mActivity);
+ assertThat(mExtension).isNotNull();
+ mWindowToken = getActivityWindowToken(mActivity);
+ assertThat(mWindowToken).isNotNull();
+ }
+
+ @Test
+ public void testExtensionProvider_hasValidVersion() {
+ ExtensionUtils.assertValidVersion();
+ }
+
+ @Test
+ public void testExtensionInterface_setExtensionCallback() {
+ // Make sure that the method can be called without exception.
+ mExtension.setExtensionCallback(new TestInterfaceCompat.TestInterfaceCallback() {
+ @Override
+ public void onDeviceStateChanged(@NonNull TestDeviceState newDeviceState) {}
+
+ @Override
+ public void onWindowLayoutChanged(@NonNull IBinder windowToken,
+ @NonNull TestWindowLayoutInfo newLayout) {}
+ });
+ }
+
+ @Test
+ public void testExtensionInterface_getWindowLayoutInfo() {
+ // No display feature to compare, finish test early.
+ assumeHasDisplayFeatures();
+
+ // Layout must happen after launch
+ assertThat(mActivity.waitForLayout()).isTrue();
+ TestWindowLayoutInfo windowLayoutInfo = mExtension.getWindowLayoutInfo(mWindowToken);
+ assertThat(windowLayoutInfo).isNotNull();
+
+ for (TestDisplayFeature displayFeature : windowLayoutInfo.getDisplayFeatures()) {
+ int featureType = displayFeature.getType();
+ assertThat(featureType).isAtLeast(TestDisplayFeature.TYPE_FOLD);
+ assertThat(featureType).isAtMost(TestDisplayFeature.TYPE_HINGE);
+
+ Rect featureRect = displayFeature.getBounds();
+ assertThat(featureRect.width() == 0 && featureRect.height() == 0).isFalse();
+ assertThat(featureRect.left).isAtLeast(0);
+ assertThat(featureRect.top).isAtLeast(0);
+ assertThat(featureRect.right).isAtLeast(0);
+ assertThat(featureRect.bottom).isAtLeast(0);
+ assertThat(featureRect.right).isAtMost(mActivity.getWidth());
+ assertThat(featureRect.bottom).isAtMost(mActivity.getHeight());
+ }
+ }
+
+ @Test
+ public void testExtensionInterface_onWindowLayoutChangeListenerAdded() {
+ // Make sure that the method can be called without exception.
+ mExtension.onWindowLayoutChangeListenerAdded(mWindowToken);
+ }
+
+ @Test
+ public void testExtensionInterface_onWindowLayoutChangeListenerRemoved() {
+ // Make sure that the method can be called without exception.
+ mExtension.onWindowLayoutChangeListenerRemoved(mWindowToken);
+ }
+
+ @Test
+ public void testExtensionInterface_getDeviceState() {
+ TestDeviceState deviceState = mExtension.getDeviceState();
+ assertThat(deviceState).isNotNull();
+
+ assertThat(deviceState.getPosture()).isIn(Range.range(
+ TestDeviceState.POSTURE_UNKNOWN, BoundType.CLOSED,
+ TestDeviceState.POSTURE_FLIPPED, BoundType.CLOSED));
+ }
+
+ @Test
+ public void testExtensionInterface_onDeviceStateListenersChanged() {
+ TestDeviceState deviceState1 = mExtension.getDeviceState();
+ mExtension.onDeviceStateListenersChanged(false /* isEmpty */);
+ TestDeviceState deviceState2 = mExtension.getDeviceState();
+ mExtension.onDeviceStateListenersChanged(true /* isEmpty */);
+ TestDeviceState deviceState3 = mExtension.getDeviceState();
+
+ assertThat(deviceState1).isEqualTo(deviceState2);
+ assertThat(deviceState1).isEqualTo(deviceState3);
+ }
+
+ @Test
+ public void testGetWindowLayoutInfo_configChanged_windowLayoutUpdates() {
+ // No display feature to compare, finish test early.
+ assumeHasDisplayFeatures();
+
+ TestConfigChangeHandlingActivity configHandlingActivity =
+ mConfigHandlingActivityTestRule.launchActivity(new Intent());
+ TestInterfaceCompat extension =
+ ExtensionUtils.getInterfaceCompat(configHandlingActivity);
+ assertThat(extension).isNotNull();
+ IBinder configHandlingActivityWindowToken = getActivityWindowToken(configHandlingActivity);
+ assertThat(configHandlingActivityWindowToken).isNotNull();
+
+ configHandlingActivity.resetLayoutCounter();
+ configHandlingActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+
+ configHandlingActivity.waitForLayout();
+ TestWindowLayoutInfo portraitWindowLayoutInfo =
+ extension.getWindowLayoutInfo(configHandlingActivityWindowToken);
+
+ configHandlingActivity.resetLayoutCounter();
+ configHandlingActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+
+ // Layout must happen after orientation change.
+ assertThat(configHandlingActivity.waitForLayout()).isTrue();
+ TestWindowLayoutInfo landscapeWindowLayoutInfo =
+ extension.getWindowLayoutInfo(configHandlingActivityWindowToken);
+
+ assertThat(portraitWindowLayoutInfo).isNotEqualTo(landscapeWindowLayoutInfo);
+ }
+
+ @Test
+ public void testGetWindowLayoutInfo_windowRecreated_windowLayoutUpdates() {
+ // No display feature to compare, finish test early.
+ assumeHasDisplayFeatures();
+
+ mActivity.resetLayoutCounter();
+ mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+
+ mActivity.waitForLayout();
+ TestWindowLayoutInfo portraitWindowLayoutInfo =
+ mExtension.getWindowLayoutInfo(mWindowToken);
+
+ TestActivity.resetResumeCounter();
+ mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ TestActivity.waitForOnResume();
+
+ mWindowToken = getActivityWindowToken(mActivity);
+ assertThat(mWindowToken).isNotNull();
+
+ mActivity.waitForLayout();
+ TestWindowLayoutInfo landscapeWindowLayoutInfo =
+ mExtension.getWindowLayoutInfo(mWindowToken);
+
+ assertThat(portraitWindowLayoutInfo).isNotEqualTo(landscapeWindowLayoutInfo);
+ }
+
+ /** Skips devices that have no display feature to compare. */
+ private void assumeHasDisplayFeatures() {
+ TestWindowLayoutInfo windowLayoutInfo = mExtension.getWindowLayoutInfo(mWindowToken);
+ assertThat(windowLayoutInfo).isNotNull();
+ List<TestDisplayFeature> displayFeatures = windowLayoutInfo.getDisplayFeatures();
+ assumeFalse(displayFeatures == null || displayFeatures.isEmpty());
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionUtils.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionUtils.java
new file mode 100644
index 0000000..82b049e
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionUtils.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeFalse;
+
+import android.content.Context;
+import android.server.wm.jetpack.wrapper.extensionwrapperimpl.TestExtensionCompat;
+import android.server.wm.jetpack.wrapper.sidecarwrapperimpl.TestSidecarCompat;
+import android.server.wm.jetpack.wrapper.TestInterfaceCompat;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+import androidx.window.extensions.ExtensionProvider;
+import androidx.window.sidecar.SidecarProvider;
+
+/** Helper class to get the vendor provided Extension/Sidecar implementation. */
+final class ExtensionUtils {
+ private static final String TAG = "TestInterfaceProvider";
+
+ /** Skips devices that don't implement the wm extension library. */
+ static void assumeSupportedDevice(Context context) {
+ assumeFalse(TextUtils.isEmpty(getVersion()) && getInterfaceCompat(context) == null);
+ }
+
+ /** Asserts that the vendor provided version is in the correct format and range. */
+ static void assertValidVersion() {
+ if (getExtensionVersion() != null) {
+ String versionStr = getExtensionVersion();
+ assertThat(Version.isValidVersion(versionStr)).isTrue();
+ assertThat(Version.parse(versionStr)).isAtLeast(Version.VERSION_1_0);
+ } else if (getSidecarVersion() != null) {
+ String versionStr = getSidecarVersion();
+ assertThat(Version.isValidVersion(versionStr)).isTrue();
+ assertThat(Version.parse(versionStr)).isEqualTo(Version.VERSION_0_1);
+ }
+ }
+
+ /**
+ * Gets the vendor provided Extension implementation if available. If not available, gets the
+ * Sidecar implementation (deprecated). If neither is available, returns {@code null}.
+ */
+ @Nullable
+ static TestInterfaceCompat getInterfaceCompat(Context context) {
+ if (!TextUtils.isEmpty(getExtensionVersion())) {
+ return getExtensionInterfaceCompat(context);
+ } else if (!TextUtils.isEmpty(getSidecarVersion())) {
+ return getSidecarInterfaceCompat(context);
+ }
+ return null;
+ }
+
+ @Nullable
+ private static String getVersion() {
+ if (!TextUtils.isEmpty(getExtensionVersion())) {
+ return getExtensionVersion();
+ } else if (!TextUtils.isEmpty(getSidecarVersion())) {
+ return getSidecarVersion();
+ }
+ return null;
+ }
+
+ @Nullable
+ private static String getExtensionVersion() {
+ try {
+ return ExtensionProvider.getApiVersion();
+ } catch (NoClassDefFoundError e) {
+ Log.d(TAG, "Extension version not found");
+ return null;
+ } catch (UnsupportedOperationException e) {
+ Log.d(TAG, "Stub Extension");
+ return null;
+ }
+ }
+
+ @Nullable
+ private static TestExtensionCompat getExtensionInterfaceCompat(Context context) {
+ try {
+ return TestExtensionCompat.create(ExtensionProvider.getExtensionImpl(context));
+ } catch (NoClassDefFoundError e) {
+ Log.d(TAG, "Extension implementation not found");
+ return null;
+ } catch (UnsupportedOperationException e) {
+ Log.d(TAG, "Stub Extension");
+ return null;
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Nullable
+ private static String getSidecarVersion() {
+ try {
+ return SidecarProvider.getApiVersion();
+ } catch (NoClassDefFoundError e) {
+ Log.d(TAG, "Sidecar version not found");
+ return null;
+ } catch (UnsupportedOperationException e) {
+ Log.d(TAG, "Stub Sidecar");
+ return null;
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Nullable
+ private static TestSidecarCompat getSidecarInterfaceCompat(Context context) {
+ try {
+ return TestSidecarCompat.create(SidecarProvider.getSidecarImpl(context));
+ } catch (NoClassDefFoundError e) {
+ Log.d(TAG, "Sidecar implementation not found");
+ return null;
+ } catch (UnsupportedOperationException e) {
+ Log.d(TAG, "Stub Sidecar");
+ return null;
+ }
+ }
+
+ private ExtensionUtils() {}
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/JetpackExtensionTestBase.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/JetpackExtensionTestBase.java
new file mode 100644
index 0000000..d460241
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/JetpackExtensionTestBase.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack;
+
+import android.app.Activity;
+import android.os.IBinder;
+
+/** Base class for all tests in the module. Copied from androidx.window.WindowTestBase. */
+class JetpackExtensionTestBase {
+ static IBinder getActivityWindowToken(Activity activity) {
+ return activity.getWindow().getAttributes().token;
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/TestActivity.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/TestActivity.java
new file mode 100644
index 0000000..44f5306
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/TestActivity.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test activity that can verify whether the layout changes. Copied from
+ * androidx.window.TestActivity.
+ */
+public class TestActivity extends Activity implements View.OnLayoutChangeListener {
+
+ private int mRootViewId;
+ private CountDownLatch mLayoutLatch;
+ private static CountDownLatch sResumeLatch = new CountDownLatch(1);
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final View contentView = new View(this);
+ mRootViewId = View.generateViewId();
+ contentView.setId(mRootViewId);
+ setContentView(contentView);
+
+ resetLayoutCounter();
+ getWindow().getDecorView().addOnLayoutChangeListener(this);
+ }
+
+ int getWidth() {
+ return findViewById(mRootViewId).getWidth();
+ }
+
+ int getHeight() {
+ return findViewById(mRootViewId).getHeight();
+ }
+
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ mLayoutLatch.countDown();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ sResumeLatch.countDown();
+ }
+
+ /**
+ * Resets layout counter when waiting for a layout to happen before calling
+ * {@link #waitForLayout()}.
+ */
+ void resetLayoutCounter() {
+ mLayoutLatch = new CountDownLatch(1);
+ }
+
+ /**
+ * Blocks and waits for the next layout to happen. {@link #resetLayoutCounter()} must be called
+ * before calling this method.
+ * @return {@code true} if the layout happened before the timeout count reached zero and
+ * {@code false} if the waiting time elapsed before the layout happened.
+ */
+ boolean waitForLayout() {
+ try {
+ return mLayoutLatch.await(3, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Resets layout counter when waiting for a layout to happen before calling
+ * {@link #waitForOnResume()}.
+ */
+ static void resetResumeCounter() {
+ sResumeLatch = new CountDownLatch(1);
+ }
+
+ /**
+ * Same as {@link #waitForLayout()}, but waits for onResume() to be called for any activity of
+ * this class. This can be used to track activity re-creation.
+ * @return {@code true} if the onResume() happened before the timeout count reached zero and
+ * {@code false} if the waiting time elapsed before the onResume() happened.
+ */
+ static boolean waitForOnResume() {
+ try {
+ return sResumeLatch.await(3, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/TestConfigChangeHandlingActivity.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/TestConfigChangeHandlingActivity.java
new file mode 100644
index 0000000..37b163a
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/TestConfigChangeHandlingActivity.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack;
+
+/**
+ * Activity that handles orientation configuration change. Copied from
+ * androidx.window.TestConfigChangeHandlingActivity.
+ */
+public final class TestConfigChangeHandlingActivity extends TestActivity {
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/Version.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/Version.java
new file mode 100644
index 0000000..a9978c0
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/Version.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack;
+
+import android.text.TextUtils;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.math.BigInteger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+/**
+ * Class encapsulating a version with major, minor, patch and description values. Copied from
+ * androidx.window.Version.
+ */
+final class Version implements Comparable<Version> {
+ static final Version UNKNOWN = new Version(0, 0, 0, "");
+ static final Version VERSION_0_1 = new Version(0, 1, 0, "");
+ static final Version VERSION_1_0 = new Version(1, 0, 0, "");
+ static final Version CURRENT = VERSION_1_0;
+
+ private static final String VERSION_PATTERN_STRING =
+ "(\\d+)(?:\\.(\\d+))(?:\\.(\\d+))(?:-(.+))?";
+
+ private final int mMajor;
+ private final int mMinor;
+ private final int mPatch;
+ private final String mDescription;
+ // Cached BigInteger value of the version.
+ private BigInteger mBigInteger;
+
+ private Version(int major, int minor, int patch, String description) {
+ mMajor = major;
+ mMinor = minor;
+ mPatch = patch;
+ mDescription = description;
+ }
+
+ /**
+ * Parses a string to a version object.
+ *
+ * @param versionString string in the format "1.2.3" or "1.2.3-Description"
+ * (major.minor.patch[-description])
+ * @return the parsed Version object or {@code null}> if the versionString format is invalid.
+ */
+ @Nullable
+ static Version parse(String versionString) {
+ if (TextUtils.isEmpty(versionString)) {
+ return null;
+ }
+
+ Matcher matcher = Pattern.compile(VERSION_PATTERN_STRING).matcher(versionString);
+ if (!matcher.matches()) {
+ return null;
+ }
+
+ int major = Integer.parseInt(matcher.group(1));
+ int minor = Integer.parseInt(matcher.group(2));
+ int patch = Integer.parseInt(matcher.group(3));
+ String description = matcher.group(4) != null ? matcher.group(4) : "";
+ return new Version(major, minor, patch, description);
+ }
+
+ /** Checks whether the version is in the correct format. */
+ static boolean isValidVersion(String versionString) {
+ Matcher matcher = Pattern.compile(VERSION_PATTERN_STRING).matcher(versionString);
+ return matcher.matches();
+ }
+
+ int getMajor() {
+ return mMajor;
+ }
+
+ int getMinor() {
+ return mMinor;
+ }
+
+ int getPatch() {
+ return mPatch;
+ }
+
+ String getDescription() {
+ return mDescription;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder(getMajor())
+ .append(".")
+ .append(getMinor())
+ .append(".")
+ .append(getPatch());
+ if (!TextUtils.isEmpty(getDescription())) {
+ sb.append("-").append(getDescription());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * To compare the major, minor and patch version with another.
+ *
+ * @param other The version to compare to this one.
+ * @return 0 if it have the same major minor and patch version; less than 0 if this version
+ * sorts ahead of <var>other</var>; greater than 0 if this version sorts after <var>other</var>.
+ */
+ @Override
+ public int compareTo(@NonNull Version other) {
+ return toBigInteger().compareTo(other.toBigInteger());
+ }
+
+ @NonNull
+ private BigInteger toBigInteger() {
+ if (mBigInteger == null) {
+ mBigInteger = BigInteger.valueOf(mMajor)
+ .shiftLeft(32)
+ .or(BigInteger.valueOf(mMinor))
+ .shiftLeft(32)
+ .or(BigInteger.valueOf(mPatch));
+ }
+ return mBigInteger;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Version)) {
+ return false;
+ }
+
+ Version otherVersionObj = (Version) obj;
+
+ // The equals checking ignores the description.
+ return mMajor == otherVersionObj.mMajor
+ && mMinor == otherVersionObj.mMinor
+ && mPatch == otherVersionObj.mPatch;
+ }
+
+ @Override
+ public int hashCode() {
+ // The hash code ignores the description.
+ int result = 17;
+ result = result * 31 + mMajor;
+ result = result * 31 + mMinor;
+ result = result * 31 + mPatch;
+ return result;
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/TestDeviceState.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/TestDeviceState.java
new file mode 100644
index 0000000..499b4da
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/TestDeviceState.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.wrapper;
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Test interface for {@link androidx.window.extensions.ExtensionDeviceState} and
+ * {@link androidx.window.sidecar.SidecarDeviceState} that serves as an API compatibility wrapper.
+ *
+ * @see android.server.wm.jetpack.wrapper.extensionwrapperimpl.TestExtensionDeviceState
+ * @see android.server.wm.jetpack.wrapper.sidecarwrapperimpl.TestSidecarDeviceState
+ */
+public interface TestDeviceState {
+
+ /** Copied from {@link androidx.window.extensions.ExtensionDeviceState}. */
+ public static final int POSTURE_UNKNOWN = 0;
+ public static final int POSTURE_CLOSED = 1;
+ public static final int POSTURE_HALF_OPENED = 2;
+ public static final int POSTURE_OPENED = 3;
+ public static final int POSTURE_FLIPPED = 4;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ POSTURE_UNKNOWN,
+ POSTURE_CLOSED,
+ POSTURE_HALF_OPENED,
+ POSTURE_OPENED,
+ POSTURE_FLIPPED
+ })
+ @interface Posture{}
+
+ /** Gets the current posture of the foldable device. */
+ @Posture
+ int getPosture();
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/TestDisplayFeature.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/TestDisplayFeature.java
new file mode 100644
index 0000000..8eb0774
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/TestDisplayFeature.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.wrapper;
+
+import android.graphics.Rect;
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Test interface for {@link androidx.window.extensions.ExtensionDisplayFeature} and
+ * {@link androidx.window.sidecar.SidecarDisplayFeature} that serves as an API compatibility
+ * wrapper.
+ *
+ * @see android.server.wm.jetpack.wrapper.extensionwrapperimpl.TestExtensionDisplayFeature
+ * @see android.server.wm.jetpack.wrapper.sidecarwrapperimpl.TestSidecarDisplayFeature
+ */
+public interface TestDisplayFeature {
+
+ /**
+ * A fold in the flexible screen without a physical gap.
+ */
+ public static final int TYPE_FOLD = 1;
+
+ /**
+ * A physical separation with a hinge that allows two display panels to fold.
+ */
+ public static final int TYPE_HINGE = 2;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ TYPE_FOLD,
+ TYPE_HINGE,
+ })
+ @interface Type{}
+
+ /** Gets the bounding rect of the display feature in window coordinate space. */
+ Rect getBounds();
+
+ /** Gets the type of the display feature. */
+ int getType();
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/TestInterfaceCompat.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/TestInterfaceCompat.java
new file mode 100644
index 0000000..749d8c5
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/TestInterfaceCompat.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.wrapper;
+
+import android.os.IBinder;
+import android.server.wm.jetpack.wrapper.extensionwrapperimpl.TestExtensionCompat;
+import android.server.wm.jetpack.wrapper.sidecarwrapperimpl.TestSidecarCompat;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Test interface for {@link androidx.window.extensions.ExtensionInterface} and
+ * {@link androidx.window.sidecar.SidecarInterface} that serves as an API compatibility wrapper.
+ *
+ * @see TestExtensionCompat
+ * @see TestSidecarCompat
+ */
+public interface TestInterfaceCompat {
+
+ /**
+ * Registers the support library as the callback for the extension. This interface will be used
+ * to report all extension changes to the support library.
+ */
+ void setExtensionCallback(@NonNull TestInterfaceCallback callback);
+
+ /**
+ * Gets current information about the display features present within the application window.
+ */
+ TestWindowLayoutInfo getWindowLayoutInfo(@NonNull IBinder windowToken);
+
+ /**
+ * Notifies extension that a listener for display feature layout changes was registered for the
+ * given window token.
+ */
+ void onWindowLayoutChangeListenerAdded(@NonNull IBinder windowToken);
+
+ /**
+ * Notifies extension that a listener for display feature layout changes was removed for the
+ * given window token.
+ */
+ void onWindowLayoutChangeListenerRemoved(@NonNull IBinder windowToken);
+
+ /**
+ * Gets current device state.
+ * @see #onDeviceStateListenersChanged(boolean)
+ */
+ TestDeviceState getDeviceState();
+
+ /**
+ * Notifies the extension that a device state change listener was updated.
+ * @param isEmpty flag indicating if the list of device state change listeners is empty.
+ */
+ void onDeviceStateListenersChanged(boolean isEmpty);
+
+ /**
+ * Callback that will be registered with the WindowManager library, and that the extension
+ * should use to report all state changes.
+ */
+ interface TestInterfaceCallback {
+ /**
+ * Called by extension when the device state changes.
+ */
+ void onDeviceStateChanged(@NonNull TestDeviceState newDeviceState);
+
+ /**
+ * Called by extension when the feature layout inside the window changes.
+ */
+ void onWindowLayoutChanged(@NonNull IBinder windowToken,
+ @NonNull TestWindowLayoutInfo newLayout);
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/TestWindowLayoutInfo.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/TestWindowLayoutInfo.java
new file mode 100644
index 0000000..5e4621d
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/TestWindowLayoutInfo.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.wrapper;
+
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Test interface for {@link androidx.window.extensions.ExtensionWindowLayoutInfo} and
+ * {@link androidx.window.sidecar.SidecarWindowLayoutInfo} that serves as an API compatibility
+ * wrapper.
+ *
+ * @see android.server.wm.jetpack.wrapper.extensionwrapperimpl.TestExtensionWindowLayoutInfo
+ * @see android.server.wm.jetpack.wrapper.sidecarwrapperimpl.TestSidecarWindowLayoutInfo
+ */
+public interface TestWindowLayoutInfo {
+ /** Gets the list of display features present within the window. */
+ @Nullable
+ List<TestDisplayFeature> getDisplayFeatures();
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/extensionwrapperimpl/TestExtensionCompat.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/extensionwrapperimpl/TestExtensionCompat.java
new file mode 100644
index 0000000..3f4d72d
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/extensionwrapperimpl/TestExtensionCompat.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.wrapper.extensionwrapperimpl;
+
+import android.os.IBinder;
+import android.server.wm.jetpack.wrapper.TestDeviceState;
+import android.server.wm.jetpack.wrapper.TestInterfaceCompat;
+import android.server.wm.jetpack.wrapper.TestWindowLayoutInfo;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.window.extensions.ExtensionDeviceState;
+import androidx.window.extensions.ExtensionInterface;
+import androidx.window.extensions.ExtensionWindowLayoutInfo;
+
+/** Compatibility wrapper for extension versions v1.0+. */
+public final class TestExtensionCompat implements TestInterfaceCompat {
+
+ @Nullable
+ public static TestExtensionCompat create(@Nullable ExtensionInterface extensionInterface) {
+ return extensionInterface == null ? null : new TestExtensionCompat(extensionInterface);
+ }
+
+ @NonNull
+ private final ExtensionInterface mExtensionInterface;
+
+ private TestExtensionCompat(@NonNull ExtensionInterface extensionInterface) {
+ mExtensionInterface = extensionInterface;
+ }
+
+ @Override
+ public void setExtensionCallback(@NonNull TestInterfaceCallback callback) {
+ mExtensionInterface.setExtensionCallback(new ExtensionInterface.ExtensionCallback() {
+ @Override
+ public void onDeviceStateChanged(@NonNull ExtensionDeviceState newDeviceState) {
+ callback.onDeviceStateChanged(TestExtensionDeviceState.create(newDeviceState));
+ }
+
+ @Override
+ public void onWindowLayoutChanged(@NonNull IBinder windowToken,
+ @NonNull ExtensionWindowLayoutInfo newLayout) {
+ callback.onWindowLayoutChanged(
+ windowToken,
+ TestExtensionWindowLayoutInfo.create(newLayout));
+ }
+ });
+ }
+
+ @Override
+ public TestWindowLayoutInfo getWindowLayoutInfo(@NonNull IBinder windowToken) {
+ return TestExtensionWindowLayoutInfo.create(
+ mExtensionInterface.getWindowLayoutInfo(windowToken));
+ }
+
+ @Override
+ public void onWindowLayoutChangeListenerAdded(@NonNull IBinder windowToken) {
+ mExtensionInterface.onWindowLayoutChangeListenerAdded(windowToken);
+ }
+
+ @Override
+ public void onWindowLayoutChangeListenerRemoved(@NonNull IBinder windowToken) {
+ mExtensionInterface.onWindowLayoutChangeListenerRemoved(windowToken);
+ }
+
+ @Override
+ public TestDeviceState getDeviceState() {
+ return TestExtensionDeviceState.create(mExtensionInterface.getDeviceState());
+ }
+
+ @Override
+ public void onDeviceStateListenersChanged(boolean isEmpty) {
+ mExtensionInterface.onDeviceStateListenersChanged(isEmpty);
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/extensionwrapperimpl/TestExtensionDeviceState.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/extensionwrapperimpl/TestExtensionDeviceState.java
new file mode 100644
index 0000000..60362b4
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/extensionwrapperimpl/TestExtensionDeviceState.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.wrapper.extensionwrapperimpl;
+
+import android.server.wm.jetpack.wrapper.TestDeviceState;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.window.extensions.ExtensionDeviceState;
+
+import com.google.common.base.Preconditions;
+
+/** Compatibility wrapper for extension versions v1.0+. */
+final class TestExtensionDeviceState implements TestDeviceState {
+
+ @Nullable
+ static TestExtensionDeviceState create(@Nullable ExtensionDeviceState extensionDeviceState) {
+ return extensionDeviceState == null
+ ? null
+ : new TestExtensionDeviceState(extensionDeviceState);
+ }
+
+ private final ExtensionDeviceState mExtensionDeviceState;
+
+ private TestExtensionDeviceState(@NonNull ExtensionDeviceState extensionDeviceState) {
+ mExtensionDeviceState = Preconditions.checkNotNull(extensionDeviceState);
+ }
+
+ @Override
+ public int getPosture() {
+ return mExtensionDeviceState.getPosture();
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return mExtensionDeviceState.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof TestExtensionDeviceState)) {
+ return false;
+ }
+ final TestExtensionDeviceState other = (TestExtensionDeviceState) obj;
+ return mExtensionDeviceState.equals(other.mExtensionDeviceState);
+ }
+
+ @Override
+ public int hashCode() {
+ return mExtensionDeviceState.hashCode();
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/extensionwrapperimpl/TestExtensionDisplayFeature.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/extensionwrapperimpl/TestExtensionDisplayFeature.java
new file mode 100644
index 0000000..abc7d4d
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/extensionwrapperimpl/TestExtensionDisplayFeature.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.wrapper.extensionwrapperimpl;
+
+import android.graphics.Rect;
+import android.server.wm.jetpack.wrapper.TestDisplayFeature;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.window.extensions.ExtensionDisplayFeature;
+
+/** Compatibility wrapper for extension versions v1.0+. */
+final class TestExtensionDisplayFeature implements TestDisplayFeature {
+
+ @Nullable
+ static TestExtensionDisplayFeature create(
+ @Nullable ExtensionDisplayFeature extensionDisplayFeature) {
+ return extensionDisplayFeature == null
+ ? null
+ : new TestExtensionDisplayFeature(extensionDisplayFeature);
+ }
+
+ private final ExtensionDisplayFeature mExtensionDisplayFeature;
+
+ private TestExtensionDisplayFeature(@NonNull ExtensionDisplayFeature extensionDisplayFeature) {
+ mExtensionDisplayFeature = extensionDisplayFeature;
+ }
+
+ @Override
+ public Rect getBounds() {
+ return mExtensionDisplayFeature.getBounds();
+ }
+
+ @Override
+ public int getType() {
+ return mExtensionDisplayFeature.getType();
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return mExtensionDisplayFeature.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof TestExtensionDisplayFeature)) {
+ return false;
+ }
+ final TestExtensionDisplayFeature other = (TestExtensionDisplayFeature) obj;
+ return mExtensionDisplayFeature.equals(other.mExtensionDisplayFeature);
+ }
+
+ @Override
+ public int hashCode() {
+ return mExtensionDisplayFeature.hashCode();
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/extensionwrapperimpl/TestExtensionWindowLayoutInfo.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/extensionwrapperimpl/TestExtensionWindowLayoutInfo.java
new file mode 100644
index 0000000..e31a29d
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/extensionwrapperimpl/TestExtensionWindowLayoutInfo.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.wrapper.extensionwrapperimpl;
+
+
+import android.server.wm.jetpack.wrapper.TestDisplayFeature;
+import android.server.wm.jetpack.wrapper.TestWindowLayoutInfo;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.window.extensions.ExtensionDisplayFeature;
+import androidx.window.extensions.ExtensionWindowLayoutInfo;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** Compatibility wrapper for extension versions v1.0+. */
+final class TestExtensionWindowLayoutInfo implements TestWindowLayoutInfo {
+
+ @Nullable
+ static TestExtensionWindowLayoutInfo create(
+ @Nullable ExtensionWindowLayoutInfo extensionWindowLayoutInfo) {
+ return extensionWindowLayoutInfo == null
+ ? null
+ : new TestExtensionWindowLayoutInfo(extensionWindowLayoutInfo);
+ }
+
+ private final ExtensionWindowLayoutInfo mExtensionWindowLayoutInfo;
+
+ private TestExtensionWindowLayoutInfo(ExtensionWindowLayoutInfo extensionWindowLayoutInfo) {
+ mExtensionWindowLayoutInfo = extensionWindowLayoutInfo;
+ }
+
+ @Nullable
+ @Override
+ public List<TestDisplayFeature> getDisplayFeatures() {
+ List<ExtensionDisplayFeature> displayFeatures =
+ mExtensionWindowLayoutInfo.getDisplayFeatures();
+ return displayFeatures == null
+ ? null
+ : mExtensionWindowLayoutInfo.getDisplayFeatures()
+ .stream()
+ .map(TestExtensionDisplayFeature::create)
+ .collect(Collectors.toList());
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return mExtensionWindowLayoutInfo.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof TestExtensionWindowLayoutInfo)) {
+ return false;
+ }
+ final TestExtensionWindowLayoutInfo other = (TestExtensionWindowLayoutInfo) obj;
+ return mExtensionWindowLayoutInfo.equals(other.mExtensionWindowLayoutInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ return mExtensionWindowLayoutInfo.hashCode();
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/sidecarwrapperimpl/TestSidecarCompat.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/sidecarwrapperimpl/TestSidecarCompat.java
new file mode 100644
index 0000000..47b09e2
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/sidecarwrapperimpl/TestSidecarCompat.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.wrapper.sidecarwrapperimpl;
+
+import android.os.IBinder;
+import android.server.wm.jetpack.wrapper.TestDeviceState;
+import android.server.wm.jetpack.wrapper.TestInterfaceCompat;
+import android.server.wm.jetpack.wrapper.TestWindowLayoutInfo;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.window.sidecar.SidecarDeviceState;
+import androidx.window.sidecar.SidecarInterface;
+import androidx.window.sidecar.SidecarWindowLayoutInfo;
+
+/** Extension interface compatibility wrapper for v0.1 sidecar. */
+@SuppressWarnings("deprecation")
+public final class TestSidecarCompat implements TestInterfaceCompat {
+
+ @Nullable
+ public static TestSidecarCompat create(@Nullable SidecarInterface sidecarInterface) {
+ return sidecarInterface == null ? null : new TestSidecarCompat(sidecarInterface);
+ }
+
+ @NonNull
+ private final SidecarInterface mSidecarInterface;
+
+ private TestSidecarCompat(@NonNull SidecarInterface sidecarInterface) {
+ mSidecarInterface = sidecarInterface;
+ }
+
+ @Override
+ public void setExtensionCallback(@NonNull TestInterfaceCallback callback) {
+ mSidecarInterface.setSidecarCallback(new SidecarInterface.SidecarCallback() {
+ @Override
+ public void onDeviceStateChanged(@NonNull SidecarDeviceState newDeviceState) {
+ callback.onDeviceStateChanged(TestSidecarDeviceState.create(newDeviceState));
+ }
+
+ @Override
+ public void onWindowLayoutChanged(@NonNull IBinder windowToken,
+ @NonNull SidecarWindowLayoutInfo newLayout) {
+ callback.onWindowLayoutChanged(
+ windowToken,
+ TestSidecarWindowLayoutInfo.create(newLayout));
+ }
+ });
+ }
+
+ @Override
+ public TestWindowLayoutInfo getWindowLayoutInfo(@NonNull IBinder windowToken) {
+ return TestSidecarWindowLayoutInfo.create(
+ mSidecarInterface.getWindowLayoutInfo(windowToken));
+ }
+
+ @Override
+ public void onWindowLayoutChangeListenerAdded(@NonNull IBinder windowToken) {
+ mSidecarInterface.onWindowLayoutChangeListenerAdded(windowToken);
+ }
+
+ @Override
+ public void onWindowLayoutChangeListenerRemoved(@NonNull IBinder windowToken) {
+ mSidecarInterface.onWindowLayoutChangeListenerRemoved(windowToken);
+ }
+
+ @Override
+ public TestDeviceState getDeviceState() {
+ return TestSidecarDeviceState.create(mSidecarInterface.getDeviceState());
+ }
+
+ @Override
+ public void onDeviceStateListenersChanged(boolean isEmpty) {
+ mSidecarInterface.onDeviceStateListenersChanged(isEmpty);
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/sidecarwrapperimpl/TestSidecarDeviceState.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/sidecarwrapperimpl/TestSidecarDeviceState.java
new file mode 100644
index 0000000..63a2a44
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/sidecarwrapperimpl/TestSidecarDeviceState.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.wrapper.sidecarwrapperimpl;
+
+import android.server.wm.jetpack.wrapper.TestDeviceState;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.window.sidecar.SidecarDeviceState;
+
+/** Extension interface compatibility wrapper for v0.1 sidecar. */
+@SuppressWarnings("deprecation")
+final class TestSidecarDeviceState implements TestDeviceState {
+
+ @Nullable
+ static TestSidecarDeviceState create(@Nullable SidecarDeviceState sidecarDeviceState) {
+ return sidecarDeviceState == null
+ ? null
+ : new TestSidecarDeviceState(sidecarDeviceState);
+ }
+
+ private final SidecarDeviceState mSidecarDeviceState;
+
+ private TestSidecarDeviceState(@NonNull SidecarDeviceState sidecarDeviceState) {
+ mSidecarDeviceState = sidecarDeviceState;
+ }
+
+ @Override
+ public int getPosture() {
+ return mSidecarDeviceState.posture;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return mSidecarDeviceState.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof TestSidecarDeviceState)) {
+ return false;
+ }
+ final TestSidecarDeviceState other = (TestSidecarDeviceState) obj;
+ return mSidecarDeviceState.equals(other.mSidecarDeviceState);
+ }
+
+ @Override
+ public int hashCode() {
+ return mSidecarDeviceState.hashCode();
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/sidecarwrapperimpl/TestSidecarDisplayFeature.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/sidecarwrapperimpl/TestSidecarDisplayFeature.java
new file mode 100644
index 0000000..e94d15d
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/sidecarwrapperimpl/TestSidecarDisplayFeature.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.wrapper.sidecarwrapperimpl;
+
+import android.graphics.Rect;
+import android.server.wm.jetpack.wrapper.TestDisplayFeature;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.window.sidecar.SidecarDisplayFeature;
+
+/** Extension interface compatibility wrapper for v0.1 sidecar. */
+@SuppressWarnings("deprecation")
+final class TestSidecarDisplayFeature implements TestDisplayFeature {
+
+ @Nullable
+ static TestSidecarDisplayFeature create(@Nullable SidecarDisplayFeature sidecarDisplayFeature) {
+ return sidecarDisplayFeature == null
+ ? null
+ : new TestSidecarDisplayFeature(sidecarDisplayFeature);
+ }
+
+ private final SidecarDisplayFeature mSidecarDisplayFeature;
+
+ private TestSidecarDisplayFeature(@NonNull SidecarDisplayFeature sidecarDisplayFeature) {
+ mSidecarDisplayFeature = sidecarDisplayFeature;
+ }
+
+ @Override
+ public Rect getBounds() {
+ return mSidecarDisplayFeature.getRect();
+ }
+
+ @Override
+ public int getType() {
+ return mSidecarDisplayFeature.getType();
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return mSidecarDisplayFeature.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof TestSidecarDisplayFeature)) {
+ return false;
+ }
+ final TestSidecarDisplayFeature other = (TestSidecarDisplayFeature) obj;
+ return mSidecarDisplayFeature.equals(other.mSidecarDisplayFeature);
+ }
+
+ @Override
+ public int hashCode() {
+ return mSidecarDisplayFeature.hashCode();
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/sidecarwrapperimpl/TestSidecarWindowLayoutInfo.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/sidecarwrapperimpl/TestSidecarWindowLayoutInfo.java
new file mode 100644
index 0000000..163e0b6
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/wrapper/sidecarwrapperimpl/TestSidecarWindowLayoutInfo.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.wrapper.sidecarwrapperimpl;
+
+
+import android.server.wm.jetpack.wrapper.TestDisplayFeature;
+import android.server.wm.jetpack.wrapper.TestWindowLayoutInfo;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.window.sidecar.SidecarDisplayFeature;
+import androidx.window.sidecar.SidecarWindowLayoutInfo;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** Extension interface compatibility wrapper for v0.1 sidecar. */
+@SuppressWarnings("deprecation")
+final class TestSidecarWindowLayoutInfo implements TestWindowLayoutInfo {
+
+ @Nullable
+ static TestSidecarWindowLayoutInfo create(
+ @Nullable SidecarWindowLayoutInfo sidecarWindowLayoutInfo) {
+ return sidecarWindowLayoutInfo == null
+ ? null
+ : new TestSidecarWindowLayoutInfo(sidecarWindowLayoutInfo);
+ }
+
+ private final SidecarWindowLayoutInfo mSidecarWindowLayoutInfo;
+
+ private TestSidecarWindowLayoutInfo(SidecarWindowLayoutInfo sidecarWindowLayoutInfo) {
+ mSidecarWindowLayoutInfo = sidecarWindowLayoutInfo;
+ }
+
+ @Nullable
+ @Override
+ public List<TestDisplayFeature> getDisplayFeatures() {
+ List<SidecarDisplayFeature> displayFeatures = mSidecarWindowLayoutInfo.displayFeatures;
+ return displayFeatures == null
+ ? null
+ : displayFeatures
+ .stream()
+ .map(TestSidecarDisplayFeature::create)
+ .collect(Collectors.toList());
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return mSidecarWindowLayoutInfo.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof TestSidecarWindowLayoutInfo)) {
+ return false;
+ }
+ final TestSidecarWindowLayoutInfo other = (TestSidecarWindowLayoutInfo) obj;
+ return mSidecarWindowLayoutInfo.equals(other.mSidecarWindowLayoutInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ return mSidecarWindowLayoutInfo.hashCode();
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/window-sidecar-release.aar b/tests/framework/base/windowmanager/jetpack/window-sidecar-release.aar
new file mode 100644
index 0000000..50f101d
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/window-sidecar-release.aar
Binary files differ
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java b/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java
index f219994..8a5d21c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java
@@ -115,6 +115,7 @@
mDm = mContext.getSystemService(DisplayManager.class);
cleanupState();
+ mUseTaskOrganizer = false;
}
@After
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowContextTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowContextTests.java
index 9b113d5..05f1b09 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowContextTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowContextTests.java
@@ -27,8 +27,6 @@
import android.view.View;
import android.view.WindowManager;
-import androidx.test.filters.FlakyTest;
-
import org.junit.Test;
/**
@@ -40,7 +38,6 @@
@Presubmit
public class WindowContextTests extends WindowContextTestBase {
@Test
- @FlakyTest(bugId = 150251036)
@AppModeFull
public void testWindowContextConfigChanges() {
final WindowManagerState.DisplayContent display = createManagedVirtualDisplaySession()
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/TestTaskOrganizer.java b/tests/framework/base/windowmanager/util/src/android/server/wm/TestTaskOrganizer.java
index 5dec9e9..ca3f727 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/TestTaskOrganizer.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/TestTaskOrganizer.java
@@ -23,6 +23,7 @@
import android.app.ActivityManager;
import android.view.Display;
+import android.view.SurfaceControl;
import android.window.TaskOrganizer;
import android.window.WindowContainerTransaction;
@@ -135,7 +136,8 @@
}
@Override
- public void onTaskAppeared(@NonNull ActivityManager.RunningTaskInfo taskInfo) {
+ public void onTaskAppeared(@NonNull ActivityManager.RunningTaskInfo taskInfo,
+ SurfaceControl leash) {
addTask(taskInfo);
}
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeSettings.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeSettings.java
index c1863f9..917f7b3 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeSettings.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/ImeSettings.java
@@ -50,6 +50,8 @@
private static final String HARD_KEYBOARD_CONFIGURATION_BEHAVIOR_ALLOWED =
"HardKeyboardConfigurationBehaviorAllowed";
private static final String INLINE_SUGGESTIONS_ENABLED = "InlineSuggestionsEnabled";
+ private static final String INLINE_SUGGESTION_VIEW_CONTENT_DESC =
+ "InlineSuggestionViewContentDesc";
@NonNull
private final PersistableBundle mBundle;
@@ -120,6 +122,11 @@
return mBundle.getBoolean(INLINE_SUGGESTIONS_ENABLED);
}
+ @Nullable
+ public String getInlineSuggestionViewContentDesc(@Nullable String defaultValue) {
+ return mBundle.getString(INLINE_SUGGESTION_VIEW_CONTENT_DESC, defaultValue);
+ }
+
static Bundle serializeToBundle(@NonNull String eventCallbackActionName,
@Nullable Builder builder) {
final Bundle result = new Bundle();
@@ -261,5 +268,17 @@
mBundle.putBoolean(INLINE_SUGGESTIONS_ENABLED, enabled);
return this;
}
+
+ /**
+ * Controls whether inline suggestions are enabled for {@link MockIme}. If enabled, a
+ * suggestion strip will be rendered at the top of the keyboard.
+ *
+ * @param contentDesc content description to be set to the inline suggestion View.
+ */
+ public Builder setInlineSuggestionViewContentDesc(@NonNull String contentDesc) {
+ mBundle.putString(INLINE_SUGGESTION_VIEW_CONTENT_DESC, contentDesc);
+ return this;
+ }
+
}
}
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
index 279206e..951d1a7 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
@@ -28,7 +28,6 @@
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.inputmethodservice.InputMethodService;
-import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -74,6 +73,8 @@
import androidx.annotation.WorkerThread;
import java.util.ArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -421,6 +422,10 @@
private final View.OnLayoutChangeListener mLayoutListener;
private final LinearLayout mLayout;
+
+ @Nullable
+ private final LinearLayout mSuggestionView;
+
private boolean mDrawsBehindNavBar = false;
KeyboardLayoutView(MockIme mockIme, @NonNull ImeSettings imeSettings,
@@ -444,14 +449,19 @@
final LayoutParams scrollViewParams = new LayoutParams(MATCH_PARENT, 100);
scrollView.setLayoutParams(scrollViewParams);
- sSuggestionView = new LinearLayout(getContext());
- sSuggestionView.setBackgroundColor(0xFFEEEEEE);
- //TODO: Change magic id
- sSuggestionView.setId(0x0102000b);
- scrollView.addView(sSuggestionView,
- new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ final LinearLayout suggestionView = new LinearLayout(getContext());
+ suggestionView.setBackgroundColor(0xFFEEEEEE);
+ final String suggestionViewContentDesc =
+ mSettings.getInlineSuggestionViewContentDesc(null /* default */);
+ if (suggestionViewContentDesc != null) {
+ suggestionView.setContentDescription(suggestionViewContentDesc);
+ }
+ scrollView.addView(suggestionView, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ mSuggestionView = suggestionView;
mLayout.addView(scrollView);
+ } else {
+ mSuggestionView = null;
}
{
@@ -558,6 +568,24 @@
super.onDetachedFromWindow();
removeOnLayoutChangeListener(mLayoutListener);
}
+
+ @MainThread
+ private void updateInlineSuggestions(
+ @NonNull PendingInlineSuggestions pendingInlineSuggestions) {
+ Log.d(TAG, "updateInlineSuggestions() called: " + pendingInlineSuggestions.mTotalCount);
+ if (mSuggestionView == null || !pendingInlineSuggestions.mValid.get()) {
+ return;
+ }
+ mSuggestionView.removeAllViews();
+ for (int i = 0; i < pendingInlineSuggestions.mTotalCount; i++) {
+ View view = pendingInlineSuggestions.mViews[i];
+ Size size = pendingInlineSuggestions.mViewSizes[i];
+ if (view == null || size == null) {
+ continue;
+ }
+ mSuggestionView.addView(view, size.getWidth(), size.getHeight());
+ }
+ }
}
KeyboardLayoutView mView;
@@ -677,7 +705,6 @@
return new ImeState(hasInputBinding, hasDummyInputConnectionConnection);
}
- private static LinearLayout sSuggestionView;
private PendingInlineSuggestions mPendingInlineSuggestions;
private static final class PendingInlineSuggestions {
@@ -700,77 +727,62 @@
@MainThread
@Override
public InlineSuggestionsRequest onCreateInlineSuggestionsRequest(Bundle uiExtras) {
- Log.d(TAG, "onCreateInlineSuggestionsRequest() called");
- final ArrayList<InlinePresentationSpec> presentationSpecs = new ArrayList<>();
- presentationSpecs.add(new InlinePresentationSpec.Builder(new Size(100, 100),
- new Size(400, 100)).build());
- presentationSpecs.add(new InlinePresentationSpec.Builder(new Size(100, 100),
- new Size(400, 100)).build());
+ return getTracer().onCreateInlineSuggestionsRequest(() -> {
+ final ArrayList<InlinePresentationSpec> presentationSpecs = new ArrayList<>();
+ presentationSpecs.add(new InlinePresentationSpec.Builder(new Size(100, 100),
+ new Size(400, 100)).build());
+ presentationSpecs.add(new InlinePresentationSpec.Builder(new Size(100, 100),
+ new Size(400, 100)).build());
- return new InlineSuggestionsRequest.Builder(presentationSpecs)
- .setMaxSuggestionCount(6)
- .build();
+ return new InlineSuggestionsRequest.Builder(presentationSpecs)
+ .setMaxSuggestionCount(6)
+ .build();
+ });
}
@MainThread
@Override
- public boolean onInlineSuggestionsResponse(InlineSuggestionsResponse response) {
- Log.d(TAG,
- "onInlineSuggestionsResponse() called: " + response.getInlineSuggestions().size());
- final PendingInlineSuggestions pendingInlineSuggestions =
- new PendingInlineSuggestions(response);
- if (mPendingInlineSuggestions != null) {
- mPendingInlineSuggestions.mValid.set(false);
- }
- mPendingInlineSuggestions = pendingInlineSuggestions;
- if (pendingInlineSuggestions.mTotalCount == 0) {
- updateInlineSuggestions(pendingInlineSuggestions);
- return true;
- }
-
- for (int i = 0; i < pendingInlineSuggestions.mTotalCount; i++) {
- final int index = i;
- InlineSuggestion inlineSuggestion =
- pendingInlineSuggestions.mResponse.getInlineSuggestions().get(index);
- Size size = inlineSuggestion.getInfo().getInlinePresentationSpec().getMaxSize();
- inlineSuggestion.inflate(
- this,
- size,
- AsyncTask.THREAD_POOL_EXECUTOR,
- suggestionView -> {
- Log.d(TAG, "new inline suggestion view ready");
- if (suggestionView != null) {
- pendingInlineSuggestions.mViews[index] = suggestionView;
- pendingInlineSuggestions.mViewSizes[index] = size;
- }
- if (pendingInlineSuggestions.mInflatedViewCount.incrementAndGet()
- == pendingInlineSuggestions.mTotalCount
- && pendingInlineSuggestions.mValid.get()) {
- Log.d(TAG, "ready to display all suggestions");
- getMainExecutor().execute(
- () -> updateInlineSuggestions(pendingInlineSuggestions));
- }
- });
- }
- return true;
- }
-
- @MainThread
- private void updateInlineSuggestions(PendingInlineSuggestions pendingInlineSuggestions) {
- Log.d(TAG, "updateInlineSuggestions() called: " + pendingInlineSuggestions.mTotalCount);
- if (sSuggestionView == null || !pendingInlineSuggestions.mValid.get()) {
- return;
- }
- sSuggestionView.removeAllViews();
- for (int i = 0; i < pendingInlineSuggestions.mTotalCount; i++) {
- View view = pendingInlineSuggestions.mViews[i];
- Size size = pendingInlineSuggestions.mViewSizes[i];
- if (view == null || size == null) {
- continue;
+ public boolean onInlineSuggestionsResponse(@NonNull InlineSuggestionsResponse response) {
+ return getTracer().onInlineSuggestionsResponse(response, () -> {
+ final PendingInlineSuggestions pendingInlineSuggestions =
+ new PendingInlineSuggestions(response);
+ if (mPendingInlineSuggestions != null) {
+ mPendingInlineSuggestions.mValid.set(false);
}
- sSuggestionView.addView(view, size.getWidth(), size.getHeight());
- }
+ mPendingInlineSuggestions = pendingInlineSuggestions;
+ if (pendingInlineSuggestions.mTotalCount == 0) {
+ mView.updateInlineSuggestions(pendingInlineSuggestions);
+ return true;
+ }
+
+ final ExecutorService executorService = Executors.newCachedThreadPool();
+ for (int i = 0; i < pendingInlineSuggestions.mTotalCount; i++) {
+ final int index = i;
+ InlineSuggestion inlineSuggestion =
+ pendingInlineSuggestions.mResponse.getInlineSuggestions().get(index);
+ Size size = inlineSuggestion.getInfo().getInlinePresentationSpec().getMaxSize();
+ inlineSuggestion.inflate(
+ this,
+ size,
+ executorService,
+ suggestionView -> {
+ Log.d(TAG, "new inline suggestion view ready");
+ if (suggestionView != null) {
+ pendingInlineSuggestions.mViews[index] = suggestionView;
+ pendingInlineSuggestions.mViewSizes[index] = size;
+ }
+ if (pendingInlineSuggestions.mInflatedViewCount.incrementAndGet()
+ == pendingInlineSuggestions.mTotalCount
+ && pendingInlineSuggestions.mValid.get()) {
+ Log.d(TAG, "ready to display all suggestions");
+ mMainHandler.post(() ->
+ mView.updateInlineSuggestions(pendingInlineSuggestions));
+ }
+ });
+ }
+ return true;
+ });
}
/**
@@ -864,45 +876,44 @@
return result;
}
- public void onCreate(@NonNull Runnable runnable) {
+ void onCreate(@NonNull Runnable runnable) {
recordEventInternal("onCreate", runnable);
}
- public void onConfigureWindow(Window win, boolean isFullscreen,
- boolean isCandidatesOnly, @NonNull Runnable runnable) {
+ void onConfigureWindow(Window win, boolean isFullscreen, boolean isCandidatesOnly,
+ @NonNull Runnable runnable) {
final Bundle arguments = new Bundle();
arguments.putBoolean("isFullscreen", isFullscreen);
arguments.putBoolean("isCandidatesOnly", isCandidatesOnly);
recordEventInternal("onConfigureWindow", runnable, arguments);
}
- public boolean onEvaluateFullscreenMode(@NonNull BooleanSupplier supplier) {
+ boolean onEvaluateFullscreenMode(@NonNull BooleanSupplier supplier) {
return recordEventInternal("onEvaluateFullscreenMode", supplier::getAsBoolean);
}
- public boolean onEvaluateInputViewShown(@NonNull BooleanSupplier supplier) {
+ boolean onEvaluateInputViewShown(@NonNull BooleanSupplier supplier) {
return recordEventInternal("onEvaluateInputViewShown", supplier::getAsBoolean);
}
- public View onCreateInputView(@NonNull Supplier<View> supplier) {
+ View onCreateInputView(@NonNull Supplier<View> supplier) {
return recordEventInternal("onCreateInputView", supplier);
}
- public void onStartInput(EditorInfo editorInfo, boolean restarting,
- @NonNull Runnable runnable) {
+ void onStartInput(EditorInfo editorInfo, boolean restarting, @NonNull Runnable runnable) {
final Bundle arguments = new Bundle();
arguments.putParcelable("editorInfo", editorInfo);
arguments.putBoolean("restarting", restarting);
recordEventInternal("onStartInput", runnable, arguments);
}
- public void onWindowVisibilityChanged(@NonNull Runnable runnable, int visibility) {
+ void onWindowVisibilityChanged(@NonNull Runnable runnable, int visibility) {
final Bundle arguments = new Bundle();
arguments.putInt("visible", visibility);
recordEventInternal("onWindowVisibilityChanged", runnable, arguments);
}
- public void onStartInputView(EditorInfo editorInfo, boolean restarting,
+ void onStartInputView(EditorInfo editorInfo, boolean restarting,
@NonNull Runnable runnable) {
final Bundle arguments = new Bundle();
arguments.putParcelable("editorInfo", editorInfo);
@@ -910,31 +921,31 @@
recordEventInternal("onStartInputView", runnable, arguments);
}
- public void onFinishInputView(boolean finishingInput, @NonNull Runnable runnable) {
+ void onFinishInputView(boolean finishingInput, @NonNull Runnable runnable) {
final Bundle arguments = new Bundle();
arguments.putBoolean("finishingInput", finishingInput);
recordEventInternal("onFinishInputView", runnable, arguments);
}
- public void onFinishInput(@NonNull Runnable runnable) {
+ void onFinishInput(@NonNull Runnable runnable) {
recordEventInternal("onFinishInput", runnable);
}
- public boolean onKeyDown(int keyCode, KeyEvent event, @NonNull BooleanSupplier supplier) {
+ boolean onKeyDown(int keyCode, KeyEvent event, @NonNull BooleanSupplier supplier) {
final Bundle arguments = new Bundle();
arguments.putInt("keyCode", keyCode);
arguments.putParcelable("event", event);
return recordEventInternal("onKeyDown", supplier::getAsBoolean, arguments);
}
- public void onUpdateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo,
+ void onUpdateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo,
@NonNull Runnable runnable) {
final Bundle arguments = new Bundle();
arguments.putParcelable("cursorAnchorInfo", cursorAnchorInfo);
recordEventInternal("onUpdateCursorAnchorInfo", runnable, arguments);
}
- public boolean onShowInputRequested(int flags, boolean configChange,
+ boolean onShowInputRequested(int flags, boolean configChange,
@NonNull BooleanSupplier supplier) {
final Bundle arguments = new Bundle();
arguments.putInt("flags", flags);
@@ -942,66 +953,76 @@
return recordEventInternal("onShowInputRequested", supplier::getAsBoolean, arguments);
}
- public void onDestroy(@NonNull Runnable runnable) {
+ void onDestroy(@NonNull Runnable runnable) {
recordEventInternal("onDestroy", runnable);
}
- public void attachToken(IBinder token, @NonNull Runnable runnable) {
+ void attachToken(IBinder token, @NonNull Runnable runnable) {
final Bundle arguments = new Bundle();
arguments.putBinder("token", token);
recordEventInternal("attachToken", runnable, arguments);
}
- public void bindInput(InputBinding binding, @NonNull Runnable runnable) {
+ void bindInput(InputBinding binding, @NonNull Runnable runnable) {
final Bundle arguments = new Bundle();
arguments.putParcelable("binding", binding);
recordEventInternal("bindInput", runnable, arguments);
}
- public void unbindInput(@NonNull Runnable runnable) {
+ void unbindInput(@NonNull Runnable runnable) {
recordEventInternal("unbindInput", runnable);
}
- public void showSoftInput(int flags, ResultReceiver resultReceiver,
- @NonNull Runnable runnable) {
+ void showSoftInput(int flags, ResultReceiver resultReceiver, @NonNull Runnable runnable) {
final Bundle arguments = new Bundle();
arguments.putInt("flags", flags);
arguments.putParcelable("resultReceiver", resultReceiver);
recordEventInternal("showSoftInput", runnable, arguments);
}
- public void hideSoftInput(int flags, ResultReceiver resultReceiver,
- @NonNull Runnable runnable) {
+ void hideSoftInput(int flags, ResultReceiver resultReceiver, @NonNull Runnable runnable) {
final Bundle arguments = new Bundle();
arguments.putInt("flags", flags);
arguments.putParcelable("resultReceiver", resultReceiver);
recordEventInternal("hideSoftInput", runnable, arguments);
}
- public AbstractInputMethodImpl onCreateInputMethodInterface(
+ AbstractInputMethodImpl onCreateInputMethodInterface(
@NonNull Supplier<AbstractInputMethodImpl> supplier) {
return recordEventInternal("onCreateInputMethodInterface", supplier);
}
- public void onReceiveCommand(
- @NonNull ImeCommand command, @NonNull Runnable runnable) {
+ void onReceiveCommand(@NonNull ImeCommand command, @NonNull Runnable runnable) {
final Bundle arguments = new Bundle();
arguments.putBundle("command", command.toBundle());
recordEventInternal("onReceiveCommand", runnable, arguments);
}
- public void onHandleCommand(
+ void onHandleCommand(
@NonNull ImeCommand command, @NonNull Supplier<Object> resultSupplier) {
final Bundle arguments = new Bundle();
arguments.putBundle("command", command.toBundle());
recordEventInternal("onHandleCommand", resultSupplier, arguments);
}
- public void onInputViewLayoutChanged(@NonNull ImeLayoutInfo imeLayoutInfo,
+ void onInputViewLayoutChanged(@NonNull ImeLayoutInfo imeLayoutInfo,
@NonNull Runnable runnable) {
final Bundle arguments = new Bundle();
imeLayoutInfo.writeToBundle(arguments);
recordEventInternal("onInputViewLayoutChanged", runnable, arguments);
}
+
+ InlineSuggestionsRequest onCreateInlineSuggestionsRequest(
+ @NonNull Supplier<InlineSuggestionsRequest> supplier) {
+ return recordEventInternal("onCreateInlineSuggestionsRequest", supplier);
+ }
+
+ boolean onInlineSuggestionsResponse(@NonNull InlineSuggestionsResponse response,
+ @NonNull BooleanSupplier supplier) {
+ final Bundle arguments = new Bundle();
+ arguments.putParcelable("response", response);
+ return recordEventInternal("onInlineSuggestionsResponse", supplier::getAsBoolean,
+ arguments);
+ }
}
}
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
index e4d6319..e7abf6c 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
@@ -26,9 +26,11 @@
import static com.android.cts.mockime.ImeEventStreamTestUtils.notExpectEvent;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.os.SystemClock;
+import android.support.test.uiautomator.UiObject2;
import android.text.TextUtils;
import android.util.Pair;
import android.view.View;
@@ -37,6 +39,7 @@
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.cts.util.EndToEndImeTestBase;
import android.view.inputmethod.cts.util.TestActivity;
+import android.view.inputmethod.cts.util.TestWebView;
import android.view.inputmethod.cts.util.UnlockScreenRule;
import android.widget.EditText;
import android.widget.LinearLayout;
@@ -248,4 +251,29 @@
expectImeInvisible(TIMEOUT);
}
}
+
+ @Test
+ public void testShowHideKeyboardOnWebView() throws Exception {
+ try (MockImeSession imeSession = MockImeSession.create(
+ InstrumentationRegistry.getContext(),
+ InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+ new ImeSettings.Builder())) {
+ final ImeEventStream stream = imeSession.openEventStream();
+
+ final UiObject2 inputTextField = TestWebView.launchTestWebViewActivity(
+ TimeUnit.SECONDS.toMillis(5));
+ assertNotNull("Editor must exists on WebView", inputTextField);
+
+ expectEvent(stream, event -> "onStartInput".equals(event.getEventName()), TIMEOUT);
+ notExpectEvent(stream, event -> "onStartInputView".equals(event.getEventName()),
+ TIMEOUT);
+ expectImeInvisible(TIMEOUT);
+
+ inputTextField.click();
+ expectEvent(stream.copy(), showSoftInputMatcher(InputMethod.SHOW_EXPLICIT), TIMEOUT);
+ expectEvent(stream.copy(), event -> "onStartInputView".equals(event.getEventName()),
+ TIMEOUT);
+ expectImeVisible(TIMEOUT);
+ }
+ }
}
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/util/TestWebView.java b/tests/inputmethod/src/android/view/inputmethod/cts/util/TestWebView.java
new file mode 100644
index 0000000..5090d70
--- /dev/null
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/util/TestWebView.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod.cts.util;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.content.Context;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+
+import com.android.compatibility.common.util.Timeout;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+/**
+ * A custom {@link WebView} class which provides a simple web page for verifying IME behavior.
+ */
+public class TestWebView {
+
+ private static final class Impl extends WebView {
+ private final static String MY_HTML =
+ "<html><body>Editor: <input type='text' name='testInput'></body></html>";
+ private UiDevice mUiDevice;
+
+ public Impl(Context context, UiDevice uiDevice) {
+ super(context);
+ mUiDevice = uiDevice;
+ }
+
+ private void loadEditorPage() {
+ super.loadData(MY_HTML, "text/html", "UTF-8");
+ }
+
+ private UiObject2 getInput(Timeout timeout) {
+ final BySelector selector = By.text("Editor: ");
+ UiObject2 label = null;
+ try {
+ label = timeout.run("waitForObject(" + selector + ")",
+ () -> mUiDevice.findObject(selector));
+ } catch (Exception e) {
+ }
+ assertNotNull("Editor label must exists on WebView", label);
+
+ // Then the input is next.
+ final UiObject2 parent = label.getParent();
+ UiObject2 previous = null;
+ for (UiObject2 child : parent.getChildren()) {
+ if (label.equals(previous)) {
+ if (child.getClassName().equals(EditText.class.getName())) {
+ return child;
+ }
+ }
+ previous = child;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Not intended to be instantiated.
+ */
+ private TestWebView() {
+ }
+
+ public static UiObject2 launchTestWebViewActivity(long timeoutMs)
+ throws Exception {
+ final AtomicReference<UiObject2> inputTextFieldRef = new AtomicReference<>();
+ final AtomicReference<TestWebView.Impl> webViewRef = new AtomicReference<>();
+ final CountDownLatch latch = new CountDownLatch(1);
+ final Timeout timeoutForFindObj = new Timeout("UIOBJECT_FIND_TIMEOUT",
+ timeoutMs, 2F, timeoutMs);
+
+ TestActivity.startSync(activity -> {
+ final LinearLayout layout = new LinearLayout(activity);
+ final TestWebView.Impl webView = new Impl(activity, UiDevice.getInstance(
+ InstrumentationRegistry.getInstrumentation()));
+ webView.setWebViewClient(new WebViewClient() {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ latch.countDown();
+ }
+ });
+ webViewRef.set(webView);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ layout.addView(webView);
+ webView.loadEditorPage();
+ return layout;
+ });
+
+ latch.await(timeoutMs, TimeUnit.MILLISECONDS);
+ inputTextFieldRef.set(webViewRef.get().getInput(timeoutForFindObj));
+ return inputTextFieldRef.get();
+ }
+}
diff --git a/tests/quickaccesswallet/AndroidManifest.xml b/tests/quickaccesswallet/AndroidManifest.xml
index 4ad90ab..4b6a994 100755
--- a/tests/quickaccesswallet/AndroidManifest.xml
+++ b/tests/quickaccesswallet/AndroidManifest.xml
@@ -34,6 +34,13 @@
</intent-filter>
</activity>
+ <activity android:name="android.quickaccesswallet.QuickAccessWalletSettingsActivity">
+ <intent-filter>
+ <action android:name="android.service.quickaccesswallet.action.VIEW_WALLET_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<service
android:name="android.quickaccesswallet.TestHostApduService"
android:exported="true"
diff --git a/tests/quickaccesswallet/res/xml/quickaccesswallet_configuration.xml b/tests/quickaccesswallet/res/xml/quickaccesswallet_configuration.xml
index 1e14677..6563a11 100644
--- a/tests/quickaccesswallet/res/xml/quickaccesswallet_configuration.xml
+++ b/tests/quickaccesswallet/res/xml/quickaccesswallet_configuration.xml
@@ -16,5 +16,4 @@
<quickaccesswallet-service
xmlns:android="http://schemas.android.com/apk/res/android"
- android:settingsActivity="android.quickaccesswallet.QuickAccessWalletSettingsActivity"
android:targetActivity="android.quickaccesswallet.QuickAccessWalletActivity"/>
\ No newline at end of file
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/QuickAccessWalletClientTest.java b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/QuickAccessWalletClientTest.java
index e7bf721..c523e1f 100755
--- a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/QuickAccessWalletClientTest.java
+++ b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/QuickAccessWalletClientTest.java
@@ -112,43 +112,21 @@
@Test
public void testIsWalletFeatureAvailableWhenDeviceLocked_checksSecureSettings() {
QuickAccessWalletClient client = QuickAccessWalletClient.create(mContext);
-
-
- String showNotificationsSetting = SettingsUtils.getSecureSetting(
- Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS);
- String allowPrivateNotificationsSetting = SettingsUtils.get(
- Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);
+ String showCardsAndPasses = SettingsUtils.getSecureSetting(
+ Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT);
try {
- SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
- SETTING_ENABLED);
- SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ SettingsUtils.syncSet(mContext, Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT,
SETTING_ENABLED);
assertThat(client.isWalletFeatureAvailableWhenDeviceLocked()).isTrue();
- SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
- SETTING_ENABLED);
- SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
- SETTING_DISABLED);
- assertThat(client.isWalletFeatureAvailableWhenDeviceLocked()).isFalse();
-
- SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
- SETTING_DISABLED);
- SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
- SETTING_ENABLED);
- assertThat(client.isWalletFeatureAvailableWhenDeviceLocked()).isFalse();
-
- SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
- SETTING_DISABLED);
- SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ SettingsUtils.syncSet(mContext, Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT,
SETTING_DISABLED);
assertThat(client.isWalletFeatureAvailableWhenDeviceLocked()).isFalse();
} finally {
- // return settings to original values
- SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
- showNotificationsSetting);
- SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
- allowPrivateNotificationsSetting);
+ // return setting to original value
+ SettingsUtils.syncSet(mContext, Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT,
+ showCardsAndPasses);
}
}
@@ -438,7 +416,7 @@
}
@Test
- public void testCreateWalletSettingsIntent_parsesXmlAndUsesCorrectIntentAction() {
+ public void testCreateWalletSettingsIntent_usesSettingsActionToFindAppropriateActivity() {
Intent settingsIntent =
QuickAccessWalletClient.create(mContext).createWalletSettingsIntent();
assertThat(settingsIntent).isNotNull();
diff --git a/tests/sensor/src/android/hardware/cts/SensorTest.java b/tests/sensor/src/android/hardware/cts/SensorTest.java
index 49e3c27..bde6e0e 100644
--- a/tests/sensor/src/android/hardware/cts/SensorTest.java
+++ b/tests/sensor/src/android/hardware/cts/SensorTest.java
@@ -731,9 +731,11 @@
}
if (mFlushWhileIdle) {
SensorCtsHelper.makeMyPackageIdle();
+ sensorManager.assertFlushFail();
+ } else {
+ CountDownLatch flushLatch = sensorManager.requestFlush();
+ listener.waitForFlushComplete(flushLatch, true);
}
- CountDownLatch flushLatch = sensorManager.requestFlush();
- listener.waitForFlushComplete(flushLatch, true);
} finally {
sensorManager.unregisterListener();
if (mFlushWhileIdle) {
diff --git a/tests/sensor/src/android/hardware/cts/helpers/TestSensorManager.java b/tests/sensor/src/android/hardware/cts/helpers/TestSensorManager.java
index 7c69649..aba6d49 100644
--- a/tests/sensor/src/android/hardware/cts/helpers/TestSensorManager.java
+++ b/tests/sensor/src/android/hardware/cts/helpers/TestSensorManager.java
@@ -156,6 +156,20 @@
}
/**
+ * Call {@link SensorManager#flush(SensorEventListener)} and asserts that it fails.
+ */
+ public void assertFlushFail() {
+ if (mTestSensorEventListener == null) {
+ Log.w(LOG_TAG, "No listener registered, returning.");
+ return;
+ }
+ Assert.assertFalse(
+ SensorCtsHelper.formatAssertionMessage(
+ "Flush succeeded unexpectedly", mEnvironment),
+ mSensorManager.flush(mTestSensorEventListener));
+ }
+
+ /**
* Call {@link SensorManager#flush(SensorEventListener)}. This method will perform a no-op if
* the sensor is not registered.
*
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java
index 8616a6d..ab60c67 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java
@@ -19,30 +19,51 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.test.AndroidTestCase;
+import android.util.Log;
import java.io.IOException;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Very basic test, just of the static methods of {@link
* BluetoothAdapter}.
*/
public class BasicAdapterTest extends AndroidTestCase {
+ private static final String TAG = "BasicAdapterTest";
private static final int DISABLE_TIMEOUT = 8000; // ms timeout for BT disable
private static final int ENABLE_TIMEOUT = 10000; // ms timeout for BT enable
private static final int POLL_TIME = 400; // ms to poll BT state
private static final int CHECK_WAIT_TIME = 1000; // ms to wait before enable/disable
+ private static final int SET_NAME_TIMEOUT = 5000; // ms timeout for setting adapter name
private boolean mHasBluetooth;
+ private ReentrantLock mAdapterNameChangedlock;
+ private Condition mConditionAdapterNameChanged;
+ private boolean mIsAdapterNameChanged;
public void setUp() throws Exception {
super.setUp();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiver(mAdapterNameChangeReceiver, filter);
+
mHasBluetooth = getContext().getPackageManager().hasSystemFeature(
PackageManager.FEATURE_BLUETOOTH);
+ mAdapterNameChangedlock = new ReentrantLock();
+ mConditionAdapterNameChanged = mAdapterNameChangedlock.newCondition();
+ mIsAdapterNameChanged = false;
}
public void test_getDefaultAdapter() {
@@ -140,7 +161,7 @@
assertTrue(BluetoothAdapter.checkBluetoothAddress(adapter.getAddress()));
}
- public void test_getName() {
+ public void test_setName_getName() {
if (!mHasBluetooth) {
// Skip the test if bluetooth is not present.
return;
@@ -150,6 +171,19 @@
String name = adapter.getName();
assertNotNull(name);
+
+ // Check renaming the adapter
+ String genericName = "Generic Device 1";
+ assertTrue(adapter.setName(genericName));
+ assertTrue(waitForAdapterNameChange());
+ mIsAdapterNameChanged = false;
+ assertEquals(genericName, adapter.getName());
+
+ // Check setting adapter back to original name
+ assertTrue(adapter.setName(name));
+ assertTrue(waitForAdapterNameChange());
+ mIsAdapterNameChanged = false;
+ assertEquals(name, adapter.getName());
}
public void test_getBondedDevices() {
@@ -289,4 +323,40 @@
Thread.sleep(t);
} catch (InterruptedException e) {}
}
+
+ private boolean waitForAdapterNameChange() {
+ mAdapterNameChangedlock.lock();
+ try {
+ // Wait for the Adapter name to be changed
+ while (!mIsAdapterNameChanged) {
+ if (!mConditionAdapterNameChanged.await(
+ SET_NAME_TIMEOUT, TimeUnit.MILLISECONDS)) {
+ Log.e(TAG, "Timeout while waiting for adapter name change");
+ break;
+ }
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "waitForAdapterNameChange: interrrupted");
+ } finally {
+ mAdapterNameChangedlock.unlock();
+ }
+ return mIsAdapterNameChanged;
+ }
+
+ private final BroadcastReceiver mAdapterNameChangeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED)) {
+ mAdapterNameChangedlock.lock();
+ mIsAdapterNameChanged = true;
+ try {
+ mConditionAdapterNameChanged.signal();
+ } catch (IllegalMonitorStateException ex) {
+ } finally {
+ mAdapterNameChangedlock.unlock();
+ }
+ }
+ }
+ };
}
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index 687e316..867f8a3 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -2598,6 +2598,17 @@
}
@Test(expected = FileNotFoundException.class)
+ public void testUriWithoutScheme() throws IOException {
+ Uri uri = new Uri.Builder()
+ .authority("authority")
+ .appendPath("missing")
+ .appendPath("scheme")
+ .build();
+ ImageDecoder.Source src = ImageDecoder.createSource(getContentResolver(), uri);
+ ImageDecoder.decodeDrawable(src);
+ }
+
+ @Test(expected = FileNotFoundException.class)
public void testBadCallable() throws IOException {
ImageDecoder.Source src = ImageDecoder.createSource(() -> null);
ImageDecoder.decodeDrawable(src);
diff --git a/tests/tests/media/src/android/media/cts/AudioHelper.java b/tests/tests/media/src/android/media/cts/AudioHelper.java
index 7208e51..a0f8e47 100644
--- a/tests/tests/media/src/android/media/cts/AudioHelper.java
+++ b/tests/tests/media/src/android/media/cts/AudioHelper.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.DeviceReportLog;
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
@@ -251,6 +252,7 @@
}
}
+ @CddTest(requirement="5.10/C-1-6,C-1-7")
public static class TimestampVerifier {
// CDD 5.6 1ms timestamp accuracy
@@ -259,7 +261,7 @@
private static final double TEST_STD_JITTER_MS_WARN = 1.; // CDD requirement warning
// CDD 5.6 100ms track startup latency
- private static final double TEST_STARTUP_TIME_MS_ALLOWED = 500.; // flaky tolerance 5x
+ private final double TEST_STARTUP_TIME_MS_ALLOWED; // CDD requirement error
private static final double TEST_STARTUP_TIME_MS_WARN = 100.; // CDD requirement warning
private static final int MILLIS_PER_SECOND = 1000;
@@ -280,9 +282,12 @@
private double mMaxAbsJitterMs = 0.;
private int mWarmupCount = 0;
- public TimestampVerifier(@Nullable String tag, @IntRange(from=4000) int sampleRate) {
+ public TimestampVerifier(@Nullable String tag, @IntRange(from=4000) int sampleRate,
+ boolean isProAudioDevice) {
mTag = tag; // Log accepts null
mSampleRate = sampleRate;
+ // For pro audio, allow slightly higher than MUST value to account for variability.
+ TEST_STARTUP_TIME_MS_ALLOWED = isProAudioDevice ? 300. /* MUST is 200. */ : 500.;
}
public int getJitterCount() { return mJitterCount; }
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index 6268466..e4d4f62 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -1538,7 +1538,7 @@
mAudioManager.adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE, 66747, 0);
}
- @CddTest(requirement="5.4.4/C-4-1")
+ @CddTest(requirement="5.4.1/C-1-4")
public void testGetMicrophones() throws Exception {
if (!mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_MICROPHONE)) {
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordTest.java b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
index 5cc58ce..2b342c8 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
@@ -576,7 +576,8 @@
// For 16 bit data, use shorts
final short[] shortData = new short[BUFFER_SAMPLES];
final AudioHelper.TimestampVerifier tsVerifier =
- new AudioHelper.TimestampVerifier(TAG, RECORD_SAMPLE_RATE);
+ new AudioHelper.TimestampVerifier(TAG, RECORD_SAMPLE_RATE,
+ isProAudioDevice());
while (samplesRead < targetSamples) {
final int amount = samplesRead == 0 ? numChannels :
@@ -963,7 +964,7 @@
Log.i(TAG, "******");
}
- @CddTest(requirement="5.4.4/C-4-1")
+ @CddTest(requirement="5.4.1/C-1-4")
@Test
public void testGetActiveMicrophones() throws Exception {
if (!hasMicrophone()) {
@@ -1600,6 +1601,11 @@
PackageManager.FEATURE_AUDIO_LOW_LATENCY);
}
+ private boolean isProAudioDevice() {
+ return getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUDIO_PRO);
+ }
+
private void verifyContinuousTimestamps(
AudioTimestamp startTs, AudioTimestamp stopTs, int sampleRate)
throws Exception {
diff --git a/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java b/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java
index 600bf8c..837a4a8 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java
@@ -23,6 +23,7 @@
import android.test.AndroidTestCase;
import android.util.Log;
+import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.PollingCheck;
import java.util.ArrayList;
@@ -40,10 +41,12 @@
11025,
16000,
44100,
+ 48000,
};
private AudioRecord mAudioRecord;
+ @CddTest(requirement="5.4.1/C-1-1")
public void testGetMinBufferSize() throws Exception {
if (!hasMicrophone()) {
return;
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index d9c2f50..f5f0420 100755
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -2099,6 +2099,11 @@
.isLowRamDevice();
}
+ private boolean isProAudioDevice() {
+ return getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUDIO_PRO);
+ }
+
@Test
public void testGetTimestamp() throws Exception {
if (!hasAudioOutput()) {
@@ -2185,7 +2190,7 @@
long framesWritten = 0;
final AudioHelper.TimestampVerifier tsVerifier =
- new AudioHelper.TimestampVerifier(TAG, sampleRate);
+ new AudioHelper.TimestampVerifier(TAG, sampleRate, isProAudioDevice());
for (int i = 0; i < TEST_LOOP_CNT; ++i) {
final long trackWriteTimeNs = System.nanoTime();
diff --git a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
index b059301..44e724f 100644
--- a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
@@ -629,7 +629,7 @@
mMediaRecorder.setMaxFileSize(MAX_FILE_SIZE * 10);
}
- @CddTest(requirement="5.4.4/C-4-1")
+ @CddTest(requirement="5.4.1/C-1-4")
public void testGetActiveMicrophones() throws Exception {
if (!hasMicrophone() || !hasAac()) {
MediaUtils.skipTest("no audio codecs or microphone");
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/Android.bp b/tests/tests/notificationlegacy/notificationlegacy29/Android.bp
index 8260a66..aabff61 100644
--- a/tests/tests/notificationlegacy/notificationlegacy29/Android.bp
+++ b/tests/tests/notificationlegacy/notificationlegacy29/Android.bp
@@ -31,6 +31,7 @@
"cts",
"vts10",
"general-tests",
+ "mts"
],
sdk_version: "test_current",
target_sdk_version: "29",
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java
index a69c595..19465b8 100644
--- a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java
+++ b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java
@@ -36,6 +36,7 @@
import android.content.Intent;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
import android.provider.Telephony;
import android.service.notification.Adjustment;
import android.service.notification.NotificationAssistantService;
@@ -52,9 +53,13 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.BufferedReader;
import java.io.FileInputStream;
+import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
+import java.io.Reader;
+import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -191,7 +196,7 @@
}
@Test
- public void testAdjustNotification_rankingScoreKey() throws Exception {
+ public void testAdjustNotifications_rankingScoreKey() throws Exception {
setUpListeners();
try {
@@ -225,12 +230,11 @@
signals.putFloat(Adjustment.KEY_RANKING_SCORE, rankingScore1);
Adjustment adjustment = new Adjustment(sbn1.getPackageName(), sbn1.getKey(), signals, "",
sbn1.getUser());
- mNotificationAssistantService.adjustNotification(adjustment);
- signals = new Bundle();
- signals.putFloat(Adjustment.KEY_RANKING_SCORE, rankingScore2);
- adjustment = new Adjustment(sbn2.getPackageName(), sbn2.getKey(), signals, "",
+ Bundle signals2 = new Bundle();
+ signals2.putFloat(Adjustment.KEY_RANKING_SCORE, rankingScore2);
+ Adjustment adjustment2 = new Adjustment(sbn2.getPackageName(), sbn2.getKey(), signals2, "",
sbn2.getUser());
- mNotificationAssistantService.adjustNotification(adjustment);
+ mNotificationAssistantService.adjustNotifications(List.of(adjustment, adjustment2));
Thread.sleep(SLEEP_TIME); // wait for adjustments to be processed
mNotificationListenerService.mRankingMap.getRanking(sbn1.getKey(), out1);
@@ -454,6 +458,60 @@
}
@Test
+ public void testOnNotificationSnoozedUntilContext() throws Exception {
+ final String snoozeContext = "@SnoozeContext1@";
+
+ setUpListeners(); // also enables assistant
+
+ sendNotification(1001, ICON_ID);
+ StatusBarNotification sbn = getFirstNotificationFromPackage(TestNotificationListener.PKG);
+
+ // simulate the user snoozing the notification
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ runCommand(String.format("cmd notification snooze --condition %s %s", snoozeContext,
+ sbn.getKey()), instrumentation);
+
+ Thread.sleep(SLEEP_TIME);
+
+ assertTrue(String.format("snoozed notification <%s> was not removed", sbn.getKey()),
+ mNotificationListenerService.checkRemovedKey(sbn.getKey()));
+
+ assertEquals(String.format("snoozed notification <%s> was not observed by NAS", sbn.getKey()),
+ sbn.getKey(), mNotificationAssistantService.snoozedKey);
+ assertEquals(snoozeContext, mNotificationAssistantService.snoozedUntilContext);
+ }
+
+ @Test
+ public void testUnsnoozeFromNAS() throws Exception {
+ final String snoozeContext = "@SnoozeContext2@";
+
+ setUpListeners(); // also enables assistant
+
+ sendNotification(1002, ICON_ID);
+ StatusBarNotification sbn = getFirstNotificationFromPackage(TestNotificationListener.PKG);
+
+ // simulate the user snoozing the notification
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ runCommand(String.format("cmd notification snooze --context %s %s", snoozeContext,
+ sbn.getKey()), instrumentation);
+
+ Thread.sleep(SLEEP_TIME);
+
+ // unsnooze from listener
+ mNotificationAssistantService = TestNotificationAssistant.getInstance();
+ android.util.Log.v(TAG, "unsnoozing from listener: " + sbn.getKey());
+ mNotificationAssistantService.unsnoozeNotification(sbn.getKey());
+
+ Thread.sleep(SLEEP_TIME);
+
+ NotificationListenerService.Ranking out = new NotificationListenerService.Ranking();
+ boolean found = mNotificationListenerService.mRankingMap.getRanking(sbn.getKey(), out);
+ assertTrue("notification <" + sbn.getKey()
+ + "> was not restored when unsnoozed from listener",
+ found);
+ }
+
+ @Test
public void testOnActionInvoked_methodExists() throws Exception {
setUpListeners();
final Intent intent = new Intent(Intent.ACTION_MAIN, Telephony.Threads.CONTENT_URI);
@@ -651,12 +709,14 @@
private void runCommand(String command, Instrumentation instrumentation) throws IOException {
UiAutomation uiAutomation = instrumentation.getUiAutomation();
// Execute command
+ System.out.println("runCommand: <<<" + command + ">>>");
try (ParcelFileDescriptor fd = uiAutomation.executeShellCommand(command)) {
assertNotNull("Failed to execute shell command: " + command, fd);
// Wait for the command to finish by reading until EOF
- try (InputStream in = new FileInputStream(fd.getFileDescriptor())) {
- byte[] buffer = new byte[4096];
- while (in.read(buffer) > 0) {
+ try (BufferedReader in = new BufferedReader(new FileReader(fd.getFileDescriptor()))) {
+ String line;
+ while (null != (line = in.readLine())) {
+ android.util.Log.v(TAG, "runCommand: output: " + line);
}
} catch (IOException e) {
throw new IOException("Could not read stdout of command: " + command, e);
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/TestNotificationAssistant.java b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/TestNotificationAssistant.java
index a70f6c6..3830458 100644
--- a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/TestNotificationAssistant.java
+++ b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/TestNotificationAssistant.java
@@ -36,6 +36,8 @@
int notificationVisibleCount = 0;
int notificationSeenCount = 0;
int notificationHiddenCount = 0;
+ String snoozedKey;
+ String snoozedUntilContext;
private NotificationManager mNotificationManager;
public static String getId() {
@@ -73,6 +75,8 @@
@Override
public void onNotificationSnoozedUntilContext(StatusBarNotification statusBarNotification,
String s) {
+ snoozedKey = statusBarNotification.getKey();
+ snoozedUntilContext = s;
}
@Override
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/TestNotificationListener.java b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/TestNotificationListener.java
index aea3914..a7f068c 100644
--- a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/TestNotificationListener.java
+++ b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/TestNotificationListener.java
@@ -37,6 +37,13 @@
sNotificationListenerInstance = null;
boolean isConnected;
+ public boolean checkRemovedKey(String key) {
+ for (StatusBarNotification sbn : mRemoved) {
+ if (sbn.getKey().equals(key)) return true;
+ }
+ return false;
+ }
+
public static String getId() {
return String.format("%s/%s", TestNotificationListener.class.getPackage().getName(),
TestNotificationListener.class.getName());
@@ -76,6 +83,7 @@
@Override
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
+ android.util.Log.v(TAG, "notification posted: " + sbn);
if (!PKG.equals(sbn.getPackageName())) {
return;
}
@@ -85,9 +93,11 @@
@Override
public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
+ android.util.Log.v(TAG, "notification removed: " + sbn);
if (!mTestPackages.contains(sbn.getPackageName())) {
return;
}
+ android.util.Log.v(TAG, "adding to removed: " + sbn);
mRankingMap = rankingMap;
mRemoved.add(sbn);
}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9536/Android.bp b/tests/tests/os/AutoRevokeWhitelistedDummyApp/Android.bp
similarity index 64%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2018-9536/Android.bp
copy to tests/tests/os/AutoRevokeWhitelistedDummyApp/Android.bp
index 16f9474..d957080 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9536/Android.bp
+++ b/tests/tests/os/AutoRevokeWhitelistedDummyApp/Android.bp
@@ -1,3 +1,4 @@
+//
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,17 +12,19 @@
// WITHOUT 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-2018-9536",
- defaults: ["cts_hostsidetests_securitybulletin_defaults"],
- srcs: ["poc.cpp"],
- include_dirs: [
- "external/aac/libFDK/include",
- "external/aac/libSYS/include",
- "cts/hostsidetests/securitybulletin/securityPatch/includes",
+android_test_helper_app {
+ name: "CtsAutoRevokeWhitelistedDummyApp",
+ defaults: ["cts_defaults"],
+ sdk_version: "test_current",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "vts10",
+ "mts",
+ "general-tests",
],
- shared_libs: [
- "libbluetooth"
- ],
+ srcs: ["src/**/*.java", "src/**/*.kt"],
}
diff --git a/tests/tests/os/AutoRevokeWhitelistedDummyApp/AndroidManifest.xml b/tests/tests/os/AutoRevokeWhitelistedDummyApp/AndroidManifest.xml
new file mode 100644
index 0000000..5c253ee
--- /dev/null
+++ b/tests/tests/os/AutoRevokeWhitelistedDummyApp/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--s
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.os.cts.autorevokewhitelisteddummyapp">
+
+ <uses-permission android:name="android.permission.READ_CALENDAR" />
+
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
+
+ <application android:autoRevokePermissions="disallowed">
+ <activity android:name="android.os.cts.autorevokewhitelisteddummyapp.MainActivity"
+ android:exported="true"
+ android:visibleToInstantApps="true" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
+
diff --git a/tests/tests/os/AutoRevokeWhitelistedDummyApp/src/android/os/cts/autorevokewhitelisteddummyapp/MainActivity.kt b/tests/tests/os/AutoRevokeWhitelistedDummyApp/src/android/os/cts/autorevokewhitelisteddummyapp/MainActivity.kt
new file mode 100644
index 0000000..6e59224
--- /dev/null
+++ b/tests/tests/os/AutoRevokeWhitelistedDummyApp/src/android/os/cts/autorevokewhitelisteddummyapp/MainActivity.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.cts.autorevokewhitelisteddummyapp
+
+import android.app.Activity
+import android.os.Bundle
+import android.widget.LinearLayout
+import android.widget.LinearLayout.VERTICAL
+import android.widget.TextView
+
+class MainActivity : Activity() {
+
+ val whitelistStatus by lazy { TextView(this) }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContentView(LinearLayout(this).apply {
+ orientation = VERTICAL
+
+ addView(whitelistStatus)
+ })
+
+ requestPermissions(arrayOf("android.permission.READ_CALENDAR"), 0)
+ }
+
+ override fun onResume() {
+ super.onResume()
+
+ whitelistStatus.text = "Auto-revoke whitelisted: " + packageManager.isAutoRevokeWhitelisted
+ }
+}
diff --git a/tests/tests/os/CtsOsTestCases.xml b/tests/tests/os/CtsOsTestCases.xml
index 3718c59..d1ab773 100644
--- a/tests/tests/os/CtsOsTestCases.xml
+++ b/tests/tests/os/CtsOsTestCases.xml
@@ -36,5 +36,8 @@
<!-- Load additional APKs onto device -->
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="push" value="CtsAutoRevokeDummyApp.apk->/data/local/tmp/cts/os/CtsAutoRevokeDummyApp.apk" />
+ <option
+ name="push"
+ value="CtsAutoRevokeWhitelistedDummyApp.apk->/data/local/tmp/cts/os/CtsAutoRevokeWhitelistedDummyApp.apk" />
</target_preparer>
</configuration>
diff --git a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
index 45ea4b8..ea58070 100644
--- a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
+++ b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
@@ -26,7 +26,7 @@
import android.net.Uri
import android.platform.test.annotations.AppModeFull
import android.provider.DeviceConfig
-import android.provider.Settings.*
+import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
import android.support.test.uiautomator.By
import android.support.test.uiautomator.BySelector
import android.support.test.uiautomator.UiObject2
@@ -34,7 +34,8 @@
import android.view.accessibility.AccessibilityNodeInfo
import android.widget.Switch
import com.android.compatibility.common.util.SystemUtil
-import com.android.compatibility.common.util.SystemUtil.*
+import com.android.compatibility.common.util.SystemUtil.runShellCommand
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
import com.android.compatibility.common.util.ThrowingSupplier
import com.android.compatibility.common.util.UiAutomatorUtils
import com.android.compatibility.common.util.UiDumpUtils
@@ -46,7 +47,10 @@
import java.util.regex.Pattern
private const val APK_PATH = "/data/local/tmp/cts/os/CtsAutoRevokeDummyApp.apk"
+private const val APK_WHITELISTED_PATH =
+ "/data/local/tmp/cts/os/CtsAutoRevokeWhitelistedDummyApp.apk"
private const val APK_PACKAGE_NAME = "android.os.cts.autorevokedummyapp"
+private const val APK_WHITELISTED_PACKAGE_NAME = "android.os.cts.autorevokewhitelisteddummyapp"
/**
* Test for auto revoke
@@ -68,6 +72,7 @@
eventually {
assertPermission(PERMISSION_GRANTED)
}
+ goBack()
goHome()
Thread.sleep(5)
@@ -79,7 +84,7 @@
assertPermission(PERMISSION_DENIED)
}
runShellCommand("cmd statusbar expand-notifications")
- waitFindObject(By.text("App permissions automatically removed"))
+ waitFindObject(By.textContains("unused app"))
.click()
waitFindObject(By.text(APK_PACKAGE_NAME))
waitFindObject(By.text("Calendar permission removed"))
@@ -114,7 +119,7 @@
@AppModeFull(reason = "Uses separate apps for testing")
fun testAutoRevoke_userWhitelisting() {
wakeUpScreen()
- withUnusedThresholdMs(TimeUnit.DAYS.toMillis(30)) {
+ withUnusedThresholdMs(4L) {
withDummyApp {
// Setup
startApp()
@@ -133,12 +138,39 @@
assertFalse(getWhitelistToggle().isChecked)
}
+ // Run
+ goBack()
+ goBack()
+ goBack()
+ runAutoRevoke()
+ Thread.sleep(500L)
+
// Verify
- goBack()
- goBack()
- goBack()
startApp()
assertWhitelistState(true)
+ assertPermission(PERMISSION_GRANTED)
+ }
+ }
+ }
+
+ @AppModeFull(reason = "Uses separate apps for testing")
+ fun testAutoRevoke_manifestWhitelisting() {
+ wakeUpScreen()
+ withUnusedThresholdMs(5L) {
+ withDummyApp(APK_WHITELISTED_PATH, APK_WHITELISTED_PACKAGE_NAME) {
+ // Setup
+ startApp(APK_WHITELISTED_PACKAGE_NAME)
+ clickPermissionAllow()
+ assertWhitelistState(true)
+
+ // Run
+ goHome()
+ Thread.sleep(20L)
+ runAutoRevoke()
+ Thread.sleep(500L)
+
+ // Verify
+ assertPermission(PERMISSION_GRANTED, APK_WHITELISTED_PACKAGE_NAME)
}
}
}
@@ -201,19 +233,19 @@
private inline fun <T> withUnusedThresholdMs(threshold: Long, action: () -> T): T {
return withDeviceConfig(
- "permissions", "auto_revoke_unused_threshold_millis", threshold.toString(), action)
+ "permissions", "auto_revoke_unused_threshold_millis2", threshold.toString(), action)
}
- private fun installApp() {
- assertThat(runShellCommand("pm install -r $APK_PATH"), containsString("Success"))
+ private fun installApp(apk: String = APK_PATH) {
+ assertThat(runShellCommand("pm install -r $apk"), containsString("Success"))
}
- private fun uninstallApp() {
- assertThat(runShellCommand("pm uninstall $APK_PACKAGE_NAME"), containsString("Success"))
+ private fun uninstallApp(packageName: String = APK_PACKAGE_NAME) {
+ assertThat(runShellCommand("pm uninstall $packageName"), containsString("Success"))
}
- private fun startApp() {
- runShellCommand("am start -n $APK_PACKAGE_NAME/$APK_PACKAGE_NAME.MainActivity")
+ private fun startApp(packageName: String = APK_PACKAGE_NAME) {
+ runShellCommand("am start -n $packageName/$packageName.MainActivity")
}
private fun goHome() {
@@ -229,16 +261,20 @@
.click()
}
- private inline fun withDummyApp(action: () -> Unit) {
- installApp()
+ private inline fun withDummyApp(
+ apk: String = APK_PATH,
+ packageName: String = APK_PACKAGE_NAME,
+ action: () -> Unit
+ ) {
+ installApp(apk)
try {
action()
} finally {
- uninstallApp()
+ uninstallApp(packageName)
}
}
- private fun assertPermission(state: Int) {
+ private fun assertPermission(state: Int, packageName: String = APK_PACKAGE_NAME) {
// For some reason this incorrectly always returns PERMISSION_DENIED
// runWithShellPermissionIdentity {
// assertEquals(
@@ -248,7 +284,7 @@
try {
context.startActivity(Intent(ACTION_APPLICATION_DETAILS_SETTINGS)
- .setData(Uri.fromParts("package", APK_PACKAGE_NAME, null))
+ .setData(Uri.fromParts("package", packageName, null))
.addFlags(FLAG_ACTIVITY_NEW_TASK))
waitFindObject(byTextIgnoreCase("Permissions")).click()
diff --git a/tests/tests/os/src/android/os/cts/HidlMemoryTest.java b/tests/tests/os/src/android/os/cts/HidlMemoryTest.java
new file mode 100644
index 0000000..f83bcc3
--- /dev/null
+++ b/tests/tests/os/src/android/os/cts/HidlMemoryTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.HidlMemory;
+import android.os.NativeHandle;
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class HidlMemoryTest {
+ @Test
+ public void testAccessors() {
+ NativeHandle handle = new NativeHandle();
+ HidlMemory mem = new HidlMemory("some name", 123, handle);
+ assertEquals("some name", mem.getName());
+ assertEquals(123, mem.getSize());
+ assertTrue(handle == mem.getHandle());
+ }
+
+ @Test
+ public void testClose() throws IOException {
+ NativeHandle handle = new NativeHandle();
+ HidlMemory mem = new HidlMemory("some name", 123, handle);
+ assertFalse(isHandleClosed(handle));
+ mem.close();
+ assertTrue(isHandleClosed(handle));
+ }
+
+ @Test
+ public void testCloseNullHandle() throws IOException {
+ HidlMemory mem = new HidlMemory("some name", 123, null);
+ mem.close();
+ }
+
+ @Test
+ public void testRelease() throws IOException {
+ NativeHandle handle = new NativeHandle();
+ HidlMemory mem = new HidlMemory("some name", 123, handle);
+ assertTrue(mem.getHandle() == handle);
+ NativeHandle released = mem.releaseHandle();
+ assertTrue(mem.getHandle() == null);
+ assertTrue(released == handle);
+ assertFalse(isHandleClosed(handle));
+ handle.close();
+ }
+
+ @Test
+ public void testDup() throws IOException {
+ NativeHandle handle = new NativeHandle();
+ HidlMemory mem = new HidlMemory("some name", 123, handle);
+
+ HidlMemory dup = mem.dup();
+ assertEquals("some name", dup.getName());
+ assertEquals(123, dup.getSize());
+ assertFalse(dup.getHandle() == handle);
+
+ assertFalse(isHandleClosed(handle));
+ assertFalse(isHandleClosed(dup.getHandle()));
+
+ mem.close();
+ assertTrue(isHandleClosed(handle));
+ assertFalse(isHandleClosed(dup.getHandle()));
+ }
+
+ @Test
+ public void testDupNullHandle() throws IOException {
+ HidlMemory mem = new HidlMemory("some name", 123, null);
+
+ HidlMemory dup = mem.dup();
+ assertEquals("some name", dup.getName());
+ assertEquals(123, dup.getSize());
+ assertTrue(dup.getHandle() == null);
+ }
+
+ private static boolean isHandleClosed(NativeHandle handle) {
+ // There is no API for actually checking whether a handle is closed, and since it is a
+ // final class we can't use Mockito.spy() on it, so we rely on it throwing when trying to
+ // use it after closing.
+ try {
+ handle.getFileDescriptors();
+ return false;
+ } catch (IllegalStateException e) {
+ return true;
+ }
+ }
+}
diff --git a/tests/tests/packagewatchdog/Android.bp b/tests/tests/packagewatchdog/Android.bp
index df59195..8773e4a 100644
--- a/tests/tests/packagewatchdog/Android.bp
+++ b/tests/tests/packagewatchdog/Android.bp
@@ -23,6 +23,7 @@
"vts",
"vts10",
"general-tests",
+ "mts"
],
libs: ["android.test.base.stubs"],
static_libs: [
diff --git a/tests/tests/permission/src/android/permission/cts/PermissionControllerTest.java b/tests/tests/permission/src/android/permission/cts/PermissionControllerTest.java
index 5be2710..7c23156 100644
--- a/tests/tests/permission/src/android/permission/cts/PermissionControllerTest.java
+++ b/tests/tests/permission/src/android/permission/cts/PermissionControllerTest.java
@@ -27,6 +27,7 @@
import static android.app.AppOpsManager.MODE_FOREGROUND;
import static android.app.AppOpsManager.permissionToOp;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.permission.PermissionControllerManager.COUNT_ONLY_WHEN_GRANTED;
import static android.permission.PermissionControllerManager.REASON_INSTALLER_POLICY_VIOLATION;
import static android.permission.PermissionControllerManager.REASON_MALWARE;
import static android.permission.cts.PermissionUtils.grantPermission;
@@ -40,6 +41,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static java.util.Collections.singletonList;
+
import android.app.AppOpsManager;
import android.app.UiAutomation;
import android.content.Context;
@@ -161,7 +164,7 @@
private Map<String, List<String>> buildRevokeRequest(@NonNull String app,
@NonNull String permission) {
- return Collections.singletonMap(app, Collections.singletonList(permission));
+ return Collections.singletonMap(app, singletonList(permission));
}
private void assertRuntimePermissionLabelsAreValid(List<String> runtimePermissions,
@@ -309,7 +312,7 @@
@Test(expected = NullPointerException.class)
public void revokePermissionsWithNullPkg() throws Exception {
Map<String, List<String>> request = Collections.singletonMap(null,
- Collections.singletonList(ACCESS_FINE_LOCATION));
+ singletonList(ACCESS_FINE_LOCATION));
revokePermissions(request, true);
}
@@ -324,7 +327,7 @@
@Test(expected = NullPointerException.class)
public void revokePermissionsWithNullPermission() throws Exception {
Map<String, List<String>> request = Collections.singletonMap(APP,
- Collections.singletonList(null));
+ singletonList(null));
revokePermissions(request, true);
}
@@ -474,4 +477,37 @@
public void revokePermissionWithNullPermission() throws Exception {
sController.revokeRuntimePermission(APP2, null);
}
+
+ // TODO: Add more tests for countPermissionAppsGranted when the method can be safely called
+ // multiple times in a row
+
+ @Test
+ public void countPermissionAppsGranted() {
+ runWithShellPermissionIdentity(
+ () -> {
+ CompletableFuture<Integer> numApps = new CompletableFuture<>();
+
+ sController.countPermissionApps(singletonList(ACCESS_FINE_LOCATION),
+ COUNT_ONLY_WHEN_GRANTED, numApps::complete, null);
+
+ // TODO: Better would be to count before, grant a permission, count again and
+ // then compare before and after
+ assertThat(numApps.get()).isAtLeast(1);
+ });
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void countPermissionAppsNullPermission() {
+ sController.countPermissionApps(null, 0, (n) -> { }, null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void countPermissionAppsInvalidFlags() {
+ sController.countPermissionApps(singletonList(ACCESS_FINE_LOCATION), -1, (n) -> { }, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void countPermissionAppsNullCallback() {
+ sController.countPermissionApps(singletonList(ACCESS_FINE_LOCATION), 0, null, null);
+ }
}
diff --git a/tests/tests/permission/src/android/permission/cts/ProviderPermissionTest.java b/tests/tests/permission/src/android/permission/cts/ProviderPermissionTest.java
index 78e82ff..fd72e77 100644
--- a/tests/tests/permission/src/android/permission/cts/ProviderPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/ProviderPermissionTest.java
@@ -261,7 +261,7 @@
ui.adoptShellPermissionIdentity("android.permission.GET_RUNTIME_PERMISSIONS");
try {
flags = pm.getPermissionFlags(WRITE_EXTERNAL_STORAGE, pkg.packageName,
- UserHandle.SYSTEM);
+ android.os.Process.myUserHandle());
} finally {
ui.dropShellPermissionIdentity();
}
diff --git a/tests/tests/role/Android.bp b/tests/tests/role/Android.bp
index ac70a58..bb35032 100644
--- a/tests/tests/role/Android.bp
+++ b/tests/tests/role/Android.bp
@@ -18,6 +18,7 @@
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
],
static_libs: [
diff --git a/tests/tests/role/src/android/app/role/cts/RoleControllerManagerTest.kt b/tests/tests/role/src/android/app/role/cts/RoleControllerManagerTest.kt
new file mode 100644
index 0000000..8d7353b
--- /dev/null
+++ b/tests/tests/role/src/android/app/role/cts/RoleControllerManagerTest.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.role.cts
+
+import android.app.Instrumentation
+
+import android.app.role.RoleControllerManager
+import android.app.role.RoleManager
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Process
+import android.provider.Settings
+import androidx.test.InstrumentationRegistry
+import androidx.test.runner.AndroidJUnit4
+import com.android.compatibility.common.util.SystemUtil.runShellCommand
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.TimeUnit
+import java.util.function.Consumer
+
+/**
+ * Tests [RoleControllerManager].
+ */
+@RunWith(AndroidJUnit4::class)
+class RoleControllerManagerTest {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val context: Context = instrumentation.context
+ private val packageManager: PackageManager = context.packageManager
+ private val roleControllerManager: RoleControllerManager =
+ context.getSystemService(RoleControllerManager::class.java)!!
+
+ @Before
+ fun installApp() {
+ installPackage(APP_APK_PATH)
+ }
+
+ @After
+ fun uninstallApp() {
+ uninstallPackage(APP_PACKAGE_NAME)
+ }
+
+ @Test
+ fun appIsVisibleForRole() {
+ assertAppIsVisibleForRole(APP_PACKAGE_NAME, ROLE_NAME, true)
+ }
+
+ @Test
+ fun settingsIsNotVisibleForHomeRole() {
+ // Settings should never show as a possible home app even if qualified.
+ val settingsPackageName = packageManager.resolveActivity(
+ Intent(Settings.ACTION_SETTINGS), PackageManager.MATCH_DEFAULT_ONLY
+ or PackageManager.MATCH_DIRECT_BOOT_AWARE or PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ )!!.activityInfo.packageName
+ assertAppIsVisibleForRole(settingsPackageName, RoleManager.ROLE_HOME, false)
+ }
+
+ @Test
+ fun appIsNotVisibleForInvalidRole() {
+ assertAppIsVisibleForRole(APP_PACKAGE_NAME, "invalid", false)
+ }
+
+ @Test
+ fun invalidAppIsNotVisibleForRole() {
+ assertAppIsVisibleForRole("invalid", ROLE_NAME, false)
+ }
+
+ private fun assertAppIsVisibleForRole(
+ packageName: String,
+ roleName: String,
+ expectedIsVisible: Boolean
+ ) {
+ val future = CompletableFuture<Boolean>()
+ runWithShellPermissionIdentity {
+ roleControllerManager.isApplicationVisibleForRole(
+ roleName, packageName, context.mainExecutor, Consumer { future.complete(it) }
+ )
+ }
+ val isVisible = future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+ assertThat(isVisible).isEqualTo(expectedIsVisible)
+ }
+
+ @Test
+ fun roleIsVisible() {
+ assertRoleIsVisible(ROLE_NAME, true)
+ }
+
+ @Test
+ fun systemGalleryRoleIsNotVisible() {
+ // The system gallery role should always be hidden.
+ assertRoleIsVisible(SYSTEM_GALLERY_ROLE_NAME, false)
+ }
+
+ @Test
+ fun invalidRoleIsNotVisible() {
+ assertRoleIsVisible("invalid", false)
+ }
+
+ private fun assertRoleIsVisible(roleName: String, expectedIsVisible: Boolean) {
+ val future = CompletableFuture<Boolean>()
+ runWithShellPermissionIdentity {
+ roleControllerManager.isRoleVisible(
+ roleName, context.mainExecutor, Consumer {
+ future.complete(it)
+ }
+ )
+ }
+ val isVisible = future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+ assertThat(isVisible).isEqualTo(expectedIsVisible)
+ }
+
+ private fun installPackage(apkPath: String) {
+ assertEquals(
+ "Success",
+ runShellCommand("pm install -r --user ${Process.myUserHandle().identifier} $apkPath")
+ .trim()
+ )
+ }
+
+ private fun uninstallPackage(packageName: String) {
+ assertEquals(
+ "Success",
+ runShellCommand("pm uninstall --user ${Process.myUserHandle().identifier} $packageName")
+ .trim()
+ )
+ }
+
+ companion object {
+ private const val ROLE_NAME = RoleManager.ROLE_BROWSER
+ private const val APP_APK_PATH = "/data/local/tmp/cts/role/CtsRoleTestApp.apk"
+ private const val APP_PACKAGE_NAME = "android.app.role.cts.app"
+ private const val SYSTEM_GALLERY_ROLE_NAME = "android.app.role.SYSTEM_GALLERY"
+ private const val TIMEOUT_MILLIS = 15 * 1000L
+ }
+}
diff --git a/tests/tests/security/res/raw/bug_110435401.mid b/tests/tests/security/res/raw/bug_110435401.mid
new file mode 100644
index 0000000..184ab1f
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_110435401.mid
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_26366256.midi b/tests/tests/security/res/raw/bug_26366256.midi
deleted file mode 100644
index 5114d92..0000000
--- a/tests/tests/security/res/raw/bug_26366256.midi
+++ /dev/null
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_68664359.mid b/tests/tests/security/res/raw/bug_68664359.mid
new file mode 100644
index 0000000..f816d82
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_68664359.mid
@@ -0,0 +1 @@
+DK:@~kkkkk
\ No newline at end of file
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index e40bd6b..3720d17 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -307,12 +307,6 @@
}
@Test
- @SecurityTest(minPatchLevel = "2016-04")
- public void testStagefright_bug_26366256() throws Exception {
- doStagefrightTest(R.raw.bug_26366256);
- }
-
- @Test
@SecurityTest(minPatchLevel = "2017-02")
public void testStagefright_cve_2016_2429_b_27211885() throws Exception {
doStagefrightTest(R.raw.cve_2016_2429_b_27211885,
@@ -1122,6 +1116,18 @@
}
@Test
+ @SecurityTest(minPatchLevel = "2018-11")
+ public void testStagefright_bug_68664359() throws Exception {
+ doStagefrightTest(R.raw.bug_68664359, 60000);
+ }
+
+ @Test
+ @SecurityTest(minPatchLevel = "2018-11")
+ public void testStagefright_bug_110435401() throws Exception {
+ doStagefrightTest(R.raw.bug_110435401, 60000);
+ }
+
+ @Test
@SecurityTest(minPatchLevel = "2017-03")
public void testStagefright_cve_2017_0474() throws Exception {
doStagefrightTest(R.raw.cve_2017_0474, 120000);
diff --git a/tests/tests/telecom/src/android/telecom/cts/TelecomAvailabilityTest.java b/tests/tests/telecom/src/android/telecom/cts/TelecomAvailabilityTest.java
index 8163520..d218da9c 100644
--- a/tests/tests/telecom/src/android/telecom/cts/TelecomAvailabilityTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/TelecomAvailabilityTest.java
@@ -118,6 +118,26 @@
}
/**
+ * Tests that TelecomManager always creates resolvable/actionable emergency dialer intent.
+ */
+ public void testCreateLaunchEmergencyDialerIntent() {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+ final TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
+
+ final Intent intentWithoutNumber = telecomManager.createLaunchEmergencyDialerIntent(null);
+ assertNotNull(intentWithoutNumber);
+ assertEquals(1, mPackageManager.queryIntentActivities(intentWithoutNumber,
+ PackageManager.MATCH_DEFAULT_ONLY).size());
+
+ final Intent intentWithNumber = telecomManager.createLaunchEmergencyDialerIntent("12345");
+ assertNotNull(intentWithNumber);
+ assertEquals(1, mPackageManager.queryIntentActivities(intentWithNumber,
+ PackageManager.MATCH_DEFAULT_ONLY).size());
+ }
+
+ /**
* @return The {@link PackageInfo} of the only app named {@code PACKAGE_NAME}.
*/
private static PackageInfo findOnlyTelecomPackageInfo(PackageManager packageManager) {
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 0fbfdd1..2dfff4f 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -2506,6 +2506,28 @@
}
@Test
+ public void testIsIccLockEnabled() {
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ return;
+ }
+ // verify SecurityException
+ try {
+ mTelephonyManager.isIccLockEnabled();
+ fail("testIsIccLockEnabled: Expected SecurityException on isIccLockEnabled");
+ } catch (SecurityException se) {
+ // expected
+ }
+
+ // test with permission
+ try {
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.isIccLockEnabled());
+ } catch (SecurityException se) {
+ fail("testIsIccLockEnabled: SecurityException not expected");
+ }
+ }
+
+ @Test
public void testIsDataEnabledForApn() {
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
return;
@@ -2528,6 +2550,29 @@
}
@Test
+ public void testIsTetheringApnRequired() {
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ return;
+ }
+ // verify SecurityException
+ try {
+ mTelephonyManager.isTetheringApnRequired();
+ fail("testIsTetheringApnRequired: Expected SecurityException on "
+ + "isTetheringApnRequired");
+ } catch (SecurityException se) {
+ // expected
+ }
+
+ // test with permission
+ try {
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.isTetheringApnRequired());
+ } catch (SecurityException se) {
+ fail("testIsIccLockEnabled: SecurityException not expected");
+ }
+ }
+
+ @Test
public void testGetCarrierInfoForImsiEncryption() {
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
return;
diff --git a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerFilterTest.java b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerFilterTest.java
new file mode 100644
index 0000000..4e019b1
--- /dev/null
+++ b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerFilterTest.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.media.tv.tuner.Tuner;
+import android.media.tv.tuner.filter.AlpFilterConfiguration;
+import android.media.tv.tuner.filter.AvSettings;
+import android.media.tv.tuner.filter.DownloadSettings;
+import android.media.tv.tuner.filter.Filter;
+import android.media.tv.tuner.filter.IpFilterConfiguration;
+import android.media.tv.tuner.filter.MmtpFilterConfiguration;
+import android.media.tv.tuner.filter.PesSettings;
+import android.media.tv.tuner.filter.RecordSettings;
+import android.media.tv.tuner.filter.SectionSettingsWithSectionBits;
+import android.media.tv.tuner.filter.SectionSettingsWithTableInfo;
+import android.media.tv.tuner.filter.TlvFilterConfiguration;
+import android.media.tv.tuner.filter.TsFilterConfiguration;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TunerFilterTest {
+ private static final String TAG = "MediaTunerFilterTest";
+
+ private Context mContext;
+ private Tuner mTuner;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+ InstrumentationRegistry
+ .getInstrumentation().getUiAutomation().adoptShellPermissionIdentity();
+ if (!hasTuner()) return;
+ mTuner = new Tuner(mContext, null, 100);
+ }
+
+ @After
+ public void tearDown() {
+ if (mTuner != null) {
+ mTuner.close();
+ mTuner = null;
+ }
+ }
+
+ @Test
+ public void testAvSettings() throws Exception {
+ if (!hasTuner()) return;
+ AvSettings settings =
+ AvSettings
+ .builder(Filter.TYPE_TS, true)
+ .setPassthrough(false)
+ .build();
+
+ assertFalse(settings.isPassthrough());
+ }
+
+ @Test
+ public void testDownloadSettings() throws Exception {
+ if (!hasTuner()) return;
+ DownloadSettings settings =
+ DownloadSettings
+ .builder(Filter.TYPE_MMTP)
+ .setDownloadId(2)
+ .build();
+
+ assertEquals(2, settings.getDownloadId());
+ }
+
+ @Test
+ public void testPesSettings() throws Exception {
+ if (!hasTuner()) return;
+ PesSettings settings =
+ PesSettings
+ .builder(Filter.TYPE_TS)
+ .setStreamId(2)
+ .setRaw(true)
+ .build();
+
+ assertEquals(2, settings.getStreamId());
+ assertTrue(settings.isRaw());
+ }
+
+ @Test
+ public void testRecordSettings() throws Exception {
+ if (!hasTuner()) return;
+ RecordSettings settings =
+ RecordSettings
+ .builder(Filter.TYPE_TS)
+ .setTsIndexMask(
+ RecordSettings.TS_INDEX_FIRST_PACKET
+ | RecordSettings.TS_INDEX_PRIVATE_DATA)
+ .setScIndexType(RecordSettings.INDEX_TYPE_SC)
+ .setScIndexMask(RecordSettings.SC_INDEX_I_FRAME)
+ .build();
+
+ assertEquals(
+ RecordSettings.TS_INDEX_FIRST_PACKET | RecordSettings.TS_INDEX_PRIVATE_DATA,
+ settings.getTsIndexMask());
+ assertEquals(RecordSettings.INDEX_TYPE_SC, settings.getScIndexType());
+ assertEquals(RecordSettings.SC_INDEX_I_FRAME, settings.getScIndexMask());
+ }
+
+ @Test
+ public void testSectionSettingsWithSectionBits() throws Exception {
+ if (!hasTuner()) return;
+ SectionSettingsWithSectionBits settings =
+ SectionSettingsWithSectionBits
+ .builder(Filter.TYPE_TS)
+ .setCrcEnabled(true)
+ .setRepeat(false)
+ .setRaw(false)
+ .setFilter(new byte[] {2, 3, 4})
+ .setMask(new byte[] {7, 6, 5, 4})
+ .setMode(new byte[] {22, 55, 33})
+ .build();
+
+ assertTrue(settings.isCrcEnabled());
+ assertFalse(settings.isRepeat());
+ assertFalse(settings.isRaw());
+ Assert.assertArrayEquals(new byte[] {2, 3, 4}, settings.getFilterBytes());
+ Assert.assertArrayEquals(new byte[] {7, 6, 5, 4}, settings.getMask());
+ Assert.assertArrayEquals(new byte[] {22, 55, 33}, settings.getMode());
+ }
+
+ @Test
+ public void testSectionSettingsWithTableInfo() throws Exception {
+ if (!hasTuner()) return;
+ SectionSettingsWithTableInfo settings =
+ SectionSettingsWithTableInfo
+ .builder(Filter.TYPE_TS)
+ .setTableId(11)
+ .setVersion(2)
+ .setCrcEnabled(false)
+ .setRepeat(true)
+ .setRaw(true)
+ .build();
+
+ assertEquals(11, settings.getTableId());
+ assertEquals(2, settings.getVersion());
+ assertFalse(settings.isCrcEnabled());
+ assertTrue(settings.isRepeat());
+ assertTrue(settings.isRaw());
+ }
+
+ @Test
+ public void testAlpFilterConfiguration() throws Exception {
+ if (!hasTuner()) return;
+ AlpFilterConfiguration config =
+ AlpFilterConfiguration
+ .builder()
+ .setPacketType(AlpFilterConfiguration.PACKET_TYPE_COMPRESSED)
+ .setLengthType(AlpFilterConfiguration.LENGTH_TYPE_WITH_ADDITIONAL_HEADER)
+ .build();
+
+ assertEquals(Filter.TYPE_ALP, config.getType());
+ assertEquals(AlpFilterConfiguration.PACKET_TYPE_COMPRESSED, config.getPacketType());
+ assertEquals(
+ AlpFilterConfiguration.LENGTH_TYPE_WITH_ADDITIONAL_HEADER, config.getLengthType());
+ }
+
+ @Test
+ public void testIpFilterConfiguration() throws Exception {
+ if (!hasTuner()) return;
+ IpFilterConfiguration config =
+ IpFilterConfiguration
+ .builder()
+ .setSrcIpAddress(new byte[] {(byte) 0xC0, (byte) 0xA8, 0, 1})
+ .setDstIpAddress(new byte[] {(byte) 0xC0, (byte) 0xA8, 3, 4})
+ .setSrcPort(33)
+ .setDstPort(23)
+ .setPassthrough(false)
+ .build();
+
+ assertEquals(Filter.TYPE_IP, config.getType());
+ Assert.assertArrayEquals(new byte[] {(byte) 0xC0, (byte) 0xA8, 0, 1}, config.getSrcIpAddress());
+ Assert.assertArrayEquals(new byte[] {(byte) 0xC0, (byte) 0xA8, 3, 4}, config.getDstIpAddress());
+ assertEquals(33, config.getSrcPort());
+ assertEquals(23, config.getDstPort());
+ assertFalse(config.isPassthrough());
+ }
+
+ @Test
+ public void testMmtpFilterConfiguration() throws Exception {
+ if (!hasTuner()) return;
+ MmtpFilterConfiguration config =
+ MmtpFilterConfiguration
+ .builder()
+ .setMmtpPacketId(3)
+ .build();
+
+ assertEquals(Filter.TYPE_MMTP, config.getType());
+ assertEquals(3, config.getMmtpPacketId());
+ }
+
+ @Test
+ public void testTlvFilterConfiguration() throws Exception {
+ if (!hasTuner()) return;
+ TlvFilterConfiguration config =
+ TlvFilterConfiguration
+ .builder()
+ .setPacketType(TlvFilterConfiguration.PACKET_TYPE_IPV4)
+ .setCompressedIpPacket(true)
+ .setPassthrough(false)
+ .build();
+
+ assertEquals(Filter.TYPE_TLV, config.getType());
+ assertEquals(TlvFilterConfiguration.PACKET_TYPE_IPV4, config.getPacketType());
+ assertTrue(config.isCompressedIpPacket());
+ assertFalse(config.isPassthrough());
+ }
+
+ @Test
+ public void testTsFilterConfiguration() throws Exception {
+ if (!hasTuner()) return;
+
+ PesSettings settings =
+ PesSettings
+ .builder(Filter.TYPE_TS)
+ .setStreamId(3)
+ .setRaw(false)
+ .build();
+
+ TsFilterConfiguration config =
+ TsFilterConfiguration
+ .builder()
+ .setTpid(521)
+ .setSettings(settings)
+ .build();
+
+ assertEquals(Filter.TYPE_TS, config.getType());
+ assertEquals(521, config.getTpid());
+
+ assertTrue(config.getSettings() instanceof PesSettings);
+ PesSettings pes = (PesSettings) config.getSettings();
+ assertEquals(3, pes.getStreamId());
+ assertFalse(pes.isRaw());
+ }
+
+
+ private boolean hasTuner() {
+ return mContext.getPackageManager().hasSystemFeature("android.hardware.tv.tuner");
+ }
+}