Merge "API Review] Removed unnecessary SystemApi annotations" into tm-dev
diff --git a/apps/CameraITS/tests/scene1_2/test_yuv_plus_jpeg.py b/apps/CameraITS/tests/scene1_2/test_yuv_plus_jpeg.py
index 7caebd2..be22003 100644
--- a/apps/CameraITS/tests/scene1_2/test_yuv_plus_jpeg.py
+++ b/apps/CameraITS/tests/scene1_2/test_yuv_plus_jpeg.py
@@ -84,6 +84,8 @@
else:
w, h = capture_request_utils.get_available_output_sizes(
'yuv', props, max_size=MAX_IMG_SIZE)[0]
+ logging.debug('YUV size: (%d, %d)', w, h)
+ logging.debug('JPEG size: %s', max_jpeg_size)
fmt_yuv = {'format': 'yuv', 'width': w, 'height': h}
fmt_jpg = {'format': 'jpeg'}
diff --git a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
index df1813c..ccacfee 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
@@ -91,7 +91,6 @@
_GYRO_POST_WAIT_TIME = 0.2 # Seconds to wait to capture some extra gyro data.
_IMG_SIZE_MAX = 640 * 480 # Maximum image size.
_NUM_FRAMES_MAX = 300 # fps*test_length should be < this for smooth captures.
-_NUM_GYRO_PTS_TO_AVG = 20 # Number of gyroscope events to average.
def _collect_data(cam, fps, w, h, test_length, rot_rig, chart_dist, log_path):
@@ -194,51 +193,6 @@
return events, frames
-def _plot_gyro_events(gyro_events, log_path):
- """Plot x, y, and z on the gyro events.
-
- Samples are grouped into NUM_GYRO_PTS_TO_AVG groups and averaged to minimize
- random spikes in data.
-
- Args:
- gyro_events: List of gyroscope events.
- log_path: Text to location to save data.
- """
-
- nevents = (len(gyro_events) // _NUM_GYRO_PTS_TO_AVG) * _NUM_GYRO_PTS_TO_AVG
- gyro_events = gyro_events[:nevents]
- times = np.array([(e['time'] - gyro_events[0]['time']) * _NSEC_TO_SEC
- for e in gyro_events])
- x = np.array([e['x'] for e in gyro_events])
- y = np.array([e['y'] for e in gyro_events])
- z = np.array([e['z'] for e in gyro_events])
-
- # Group samples into size-N groups & average each together to minimize random
- # spikes in data.
- times = times[_NUM_GYRO_PTS_TO_AVG//2::_NUM_GYRO_PTS_TO_AVG]
- x = x.reshape(nevents//_NUM_GYRO_PTS_TO_AVG, _NUM_GYRO_PTS_TO_AVG).mean(1)
- y = y.reshape(nevents//_NUM_GYRO_PTS_TO_AVG, _NUM_GYRO_PTS_TO_AVG).mean(1)
- z = z.reshape(nevents//_NUM_GYRO_PTS_TO_AVG, _NUM_GYRO_PTS_TO_AVG).mean(1)
-
- pylab.figure(_NAME)
- # x & y on same axes
- pylab.subplot(2, 1, 1)
- pylab.title(_NAME + ' (mean of %d pts)' % _NUM_GYRO_PTS_TO_AVG)
- pylab.plot(times, x, 'r', label='x')
- pylab.plot(times, y, 'g', label='y')
- pylab.ylabel('gyro x & y movement (rads/s)')
- pylab.legend()
-
- # z on separate axes
- pylab.subplot(2, 1, 2)
- pylab.plot(times, z, 'b', label='z')
- pylab.xlabel('time (seconds)')
- pylab.ylabel('gyro z movement (rads/s)')
- pylab.legend()
- matplotlib.pyplot.savefig(
- '%s_gyro_events.png' % (os.path.join(log_path, _NAME)))
-
-
def _get_cam_times(cam_events, fps):
"""Get the camera frame times.
@@ -543,7 +497,7 @@
rot_rig, chart_distance, log_path)
logging.debug('Start frame: %d', _START_FRAME)
- _plot_gyro_events(events['gyro'], log_path)
+ sensor_fusion_utils.plot_gyro_events(events['gyro'], _NAME, log_path)
# Validity check on gyro/camera timestamps
cam_times = _get_cam_times(
diff --git a/apps/CameraITS/utils/sensor_fusion_utils.py b/apps/CameraITS/utils/sensor_fusion_utils.py
index e7893fe..e1b3a07 100644
--- a/apps/CameraITS/utils/sensor_fusion_utils.py
+++ b/apps/CameraITS/utils/sensor_fusion_utils.py
@@ -17,10 +17,13 @@
import bisect
import codecs
import logging
+import os
import struct
import time
import unittest
+from matplotlib import pylab
+import matplotlib.pyplot
import numpy as np
import scipy.spatial
import serial
@@ -63,6 +66,8 @@
_NSEC_TO_SEC = 1E-9
_SEC_TO_NSEC = int(1/_NSEC_TO_SEC)
+_NUM_GYRO_PTS_TO_AVG = 20
+
def serial_port_def(name):
"""Determine the serial port and open.
@@ -405,6 +410,52 @@
return exact_best_shift, fit_coeffs, shift_candidates, spatial_distances
+def plot_gyro_events(gyro_events, plot_name, log_path):
+ """Plot x, y, and z on the gyro events.
+
+ Samples are grouped into NUM_GYRO_PTS_TO_AVG groups and averaged to minimize
+ random spikes in data.
+
+ Args:
+ gyro_events: List of gyroscope events.
+ plot_name: name of plot(s).
+ log_path: location to save data.
+ """
+
+ nevents = (len(gyro_events) // _NUM_GYRO_PTS_TO_AVG) * _NUM_GYRO_PTS_TO_AVG
+ gyro_events = gyro_events[:nevents]
+ times = np.array([(e['time'] - gyro_events[0]['time']) * _NSEC_TO_SEC
+ for e in gyro_events])
+ x = np.array([e['x'] for e in gyro_events])
+ y = np.array([e['y'] for e in gyro_events])
+ z = np.array([e['z'] for e in gyro_events])
+
+ # Group samples into size-N groups & average each together to minimize random
+ # spikes in data.
+ times = times[_NUM_GYRO_PTS_TO_AVG//2::_NUM_GYRO_PTS_TO_AVG]
+ x = x.reshape(nevents//_NUM_GYRO_PTS_TO_AVG, _NUM_GYRO_PTS_TO_AVG).mean(1)
+ y = y.reshape(nevents//_NUM_GYRO_PTS_TO_AVG, _NUM_GYRO_PTS_TO_AVG).mean(1)
+ z = z.reshape(nevents//_NUM_GYRO_PTS_TO_AVG, _NUM_GYRO_PTS_TO_AVG).mean(1)
+
+ pylab.figure(plot_name)
+ # x & y on same axes
+ pylab.subplot(2, 1, 1)
+ pylab.title(f'{plot_name}(mean of {_NUM_GYRO_PTS_TO_AVG} pts)')
+ pylab.plot(times, x, 'r', label='x')
+ pylab.plot(times, y, 'g', label='y')
+ pylab.ylabel('gyro x & y movement (rads/s)')
+ pylab.legend()
+
+ # z on separate axes
+ pylab.subplot(2, 1, 2)
+ pylab.plot(times, z, 'b', label='z')
+ pylab.xlabel('time (seconds)')
+ pylab.ylabel('gyro z movement (rads/s)')
+ pylab.legend()
+ file_name = os.path.join(log_path, plot_name)
+ matplotlib.pyplot.savefig(f'{file_name}_gyro_events.png')
+
+
class SensorFusionUtilsTests(unittest.TestCase):
"""Run a suite of unit tests on this module."""
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java
index 336a923..3f27a2d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java
@@ -592,7 +592,11 @@
shutdownCamera();
mCurrentCameraIndex = index;
- mCameraId = mCameraIdList[index];
+
+ Set<String> cameraIdSet = mTestCases.keySet();
+ List<String> stringsList = new ArrayList<>(cameraIdSet);
+
+ mCameraId = stringsList.get(index);
try {
mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
mCameraDevice = mBlockingCameraManager.openCamera(mCameraId,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index 61f0ea8..588f061 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -177,7 +177,7 @@
private CameraCaptureSession mSession = null;
private ImageReader[] mOutputImageReaders = null;
private SparseArray<String> mPhysicalStreamMap = new SparseArray<String>();
- private SparseArray<Integer> mStreamUseCaseMap = new SparseArray<Integer>();
+ private SparseArray<Long> mStreamUseCaseMap = new SparseArray<Long>();
private ImageReader mInputImageReader = null;
private CameraCharacteristics mCameraCharacteristics = null;
private HashMap<String, CameraCharacteristics> mPhysicalCameraChars =
@@ -1604,7 +1604,7 @@
outputSizes[i] = new Size(width, height);
if (!surfaceObj.isNull("useCase")) {
- mStreamUseCaseMap.put(i, surfaceObj.optInt("useCase"));
+ mStreamUseCaseMap.put(i, surfaceObj.optLong("useCase"));
}
}
} catch (org.json.JSONException e) {
diff --git a/apps/VpnApp/latest/AndroidManifest.xml b/apps/VpnApp/latest/AndroidManifest.xml
index 76c5e35..959ceda7 100644
--- a/apps/VpnApp/latest/AndroidManifest.xml
+++ b/apps/VpnApp/latest/AndroidManifest.xml
@@ -26,6 +26,7 @@
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<action android:name="com.android.cts.vpnfirewall.action.CONNECT_AND_FINISH"/>
+ <action android:name="com.android.cts.vpnfirewall.action.DISCONNECT_AND_FINISH"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
diff --git a/common/device-side/bedstead/deviceadminapp/src/main/AndroidManifest.xml b/common/device-side/bedstead/deviceadminapp/src/main/AndroidManifest.xml
index 7733f55..c880395 100644
--- a/common/device-side/bedstead/deviceadminapp/src/main/AndroidManifest.xml
+++ b/common/device-side/bedstead/deviceadminapp/src/main/AndroidManifest.xml
@@ -29,5 +29,27 @@
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
</intent-filter>
</receiver>
+
+ <receiver android:name="com.android.eventlib.premade.EventLibDelegatedAdminReceiver"
+ android:permission="android.permission.BIND_DEVICE_ADMIN"
+ android:exported="true">
+
+ <intent-filter>
+ <action android:name="android.app.action.CHOOSE_PRIVATE_KEY_ALIAS"/>
+ <action android:name="android.app.action.NETWORK_LOGS_AVAILABLE"/>
+ <action android:name="android.app.action.SECURITY_LOGS_AVAILABLE"/>
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.eventlib.premade.EventLibDelegatedAdminReceiver"
+ android:permission="android.permission.BIND_DEVICE_ADMIN"
+ android:exported="true">
+
+ <intent-filter>
+ <action android:name="android.app.action.CHOOSE_PRIVATE_KEY_ALIAS"/>
+ <action android:name="android.app.action.NETWORK_LOGS_AVAILABLE"/>
+ <action android:name="android.app.action.SECURITY_LOGS_AVAILABLE"/>
+ </intent-filter>
+ </receiver>
</application>
</manifest>
diff --git a/common/device-side/bedstead/deviceadminapp/src/main/java/com/android/bedstead/deviceadminapp/DeviceAdminApp.java b/common/device-side/bedstead/deviceadminapp/src/main/java/com/android/bedstead/deviceadminapp/DeviceAdminApp.java
index 4312217..acfe7f9 100644
--- a/common/device-side/bedstead/deviceadminapp/src/main/java/com/android/bedstead/deviceadminapp/DeviceAdminApp.java
+++ b/common/device-side/bedstead/deviceadminapp/src/main/java/com/android/bedstead/deviceadminapp/DeviceAdminApp.java
@@ -16,10 +16,12 @@
package com.android.bedstead.deviceadminapp;
+import android.app.admin.DelegatedAdminReceiver;
import android.app.admin.DeviceAdminReceiver;
import android.content.ComponentName;
import android.content.Context;
+import com.android.eventlib.premade.EventLibDelegatedAdminReceiver;
import com.android.eventlib.premade.EventLibDeviceAdminReceiver;
/**
@@ -32,4 +34,10 @@
return new ComponentName(
context.getPackageName(), EventLibDeviceAdminReceiver.class.getName());
}
+
+ /** Get the {@link ComponentName} for the {@link DelegatedAdminReceiver} subclass. */
+ public static ComponentName delegatedAdminComponentName(Context context) {
+ return new ComponentName(
+ context.getPackageName(), EventLibDelegatedAdminReceiver.class.getName());
+ }
}
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Events.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Events.java
index e2a4c84..cbc83a4 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Events.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Events.java
@@ -38,7 +38,7 @@
import java.util.concurrent.atomic.AtomicBoolean;
/** Event store for the current package. */
-class Events {
+final class Events {
private static final String TAG = "EventLibEvents";
private static final String EVENT_LOG_FILE_NAME = "Events";
@@ -87,28 +87,30 @@
}
private void loadEventsFromFile() {
- mEventList.clear();
- Instant now = Instant.now();
- Deque<Event> eventQueue = new ArrayDeque<>();
- try (FileInputStream fileInputStream = mContext.openFileInput(EVENT_LOG_FILE_NAME)) {
- Event event = readEvent(fileInputStream);
+ synchronized (mEventList) {
+ mEventList.clear();
+ Instant now = Instant.now();
+ Deque<Event> eventQueue = new ArrayDeque<>();
+ try (FileInputStream fileInputStream = mContext.openFileInput(EVENT_LOG_FILE_NAME)) {
+ Event event = readEvent(fileInputStream);
- while (event != null) {
- // I'm not sure if we need this
- if (event.mTimestamp.plus(MAX_LOG_AGE).isAfter(now)) {
- eventQueue.addFirst(event);
+ while (event != null) {
+ // I'm not sure if we need this
+ if (event.mTimestamp.plus(MAX_LOG_AGE).isAfter(now)) {
+ eventQueue.addFirst(event);
+ }
+ event = readEvent(fileInputStream);
}
- event = readEvent(fileInputStream);
- }
- for (Event e : eventQueue) {
- mEventList.addFirst(e);
+ for (Event e : eventQueue) {
+ mEventList.addFirst(e);
+ }
+ } catch (FileNotFoundException e) {
+ // Ignore this exception as if there's no file there's nothing to load
+ Log.i(TAG, "No existing event file");
+ } catch (IOException e) {
+ Log.e(TAG, "Error when loading events from file", e);
}
- } catch (FileNotFoundException e) {
- // Ignore this exception as if there's no file there's nothing to load
- Log.i(TAG, "No existing event file");
- } catch (IOException e) {
- Log.e(TAG, "Error when loading events from file", e);
}
}
@@ -163,13 +165,17 @@
/** Get all logged events. */
public Queue<Event> getEvents() {
- return mEventList;
+ return mEventList;
}
/** Register an {@link EventListener} to be called when a new {@link Event} is logged. */
- public void registerEventListener(EventListener listener) {
- synchronized (mEventListeners) {
- mEventListeners.add(listener);
+ public Queue<Event> registerEventListener(EventListener listener) {
+ synchronized (mEventList) {
+ synchronized (mEventListeners) {
+ mEventListeners.add(listener);
+
+ return getEvents();
+ }
}
}
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/LocalEventQuerier.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/LocalEventQuerier.java
index 1b51899..c1be192 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/LocalEventQuerier.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/LocalEventQuerier.java
@@ -36,8 +36,7 @@
LocalEventQuerier(Context context, EventLogsQuery<E, F> eventLogsQuery) {
mEventLogsQuery = eventLogsQuery;
mEvents = Events.getInstance(context, /* needsHistory= */ true);
- mFetchedEvents = new LinkedBlockingDeque<>(mEvents.getEvents());
- mEvents.registerEventListener(this);
+ mFetchedEvents = new LinkedBlockingDeque<>(mEvents.registerEventListener(this));
}
@Override
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminChoosePrivateKeyAliasEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminChoosePrivateKeyAliasEvent.java
new file mode 100644
index 0000000..31d4fcd
--- /dev/null
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminChoosePrivateKeyAliasEvent.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.eventlib.events.delegatedadminreceivers;
+
+import android.app.admin.DelegatedAdminReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import androidx.annotation.CheckResult;
+
+import com.android.eventlib.Event;
+import com.android.eventlib.EventLogger;
+import com.android.eventlib.EventLogsQuery;
+import com.android.queryable.info.DelegatedAdminReceiverInfo;
+import com.android.queryable.queries.DelegatedAdminReceiverQuery;
+import com.android.queryable.queries.DelegatedAdminReceiverQueryHelper;
+import com.android.queryable.queries.IntegerQuery;
+import com.android.queryable.queries.IntegerQueryHelper;
+import com.android.queryable.queries.IntentQueryHelper;
+import com.android.queryable.queries.StringQuery;
+import com.android.queryable.queries.StringQueryHelper;
+import com.android.queryable.queries.UriQuery;
+import com.android.queryable.queries.UriQueryHelper;
+import com.android.queryable.util.SerializableParcelWrapper;
+
+/**
+ * Event logged when
+ * {@link DelegatedAdminReceiver#onChoosePrivateKeyAlias(Context, Intent, int, Uri, String)} is
+ * called.
+ */
+public final class DelegatedAdminChoosePrivateKeyAliasEvent extends Event {
+
+ private static final long serialVersionUID = 1;
+
+ /** Begins a query for {@link DelegatedAdminChoosePrivateKeyAliasEvent} events. */
+ public static DelegatedAdminChoosePrivateKeyAliasEventQuery queryPackage(String packageName) {
+ return new DelegatedAdminChoosePrivateKeyAliasEventQuery(packageName);
+ }
+
+ /** {@link EventLogsQuery} for {@link DelegatedAdminChoosePrivateKeyAliasEvent}. */
+ public static final class DelegatedAdminChoosePrivateKeyAliasEventQuery
+ extends EventLogsQuery<DelegatedAdminChoosePrivateKeyAliasEvent,
+ DelegatedAdminChoosePrivateKeyAliasEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
+ DelegatedAdminReceiverQueryHelper<DelegatedAdminChoosePrivateKeyAliasEventQuery> mDelegatedAdminReceiver =
+ new DelegatedAdminReceiverQueryHelper<>(this);
+ IntentQueryHelper<DelegatedAdminChoosePrivateKeyAliasEventQuery> mIntent =
+ new IntentQueryHelper<>(this);
+ IntegerQueryHelper<DelegatedAdminChoosePrivateKeyAliasEventQuery> mUid =
+ new IntegerQueryHelper<>(this);
+ UriQueryHelper<DelegatedAdminChoosePrivateKeyAliasEventQuery> mUri =
+ new UriQueryHelper<>(this);
+ StringQueryHelper<DelegatedAdminChoosePrivateKeyAliasEventQuery> mAlias =
+ new StringQueryHelper<>(this);
+
+ private DelegatedAdminChoosePrivateKeyAliasEventQuery(String packageName) {
+ super(DelegatedAdminChoosePrivateKeyAliasEvent.class, packageName);
+ }
+
+ /**
+ * Queries {@link Intent} passed into
+ * {@link DelegatedAdminReceiver#onChoosePrivateKeyAlias(Context, Intent, int, Uri, String).
+ */
+ @CheckResult
+ public IntentQueryHelper<DelegatedAdminChoosePrivateKeyAliasEventQuery> whereIntent() {
+ return mIntent;
+ }
+
+ /** Queries {@link DelegatedAdminReceiver}. */
+ @CheckResult
+ public DelegatedAdminReceiverQuery<DelegatedAdminChoosePrivateKeyAliasEventQuery> whereDelegatedAdminReceiver() {
+ return mDelegatedAdminReceiver;
+ }
+
+ /** Query {@code uid}. */
+ @CheckResult
+ public IntegerQuery<DelegatedAdminChoosePrivateKeyAliasEventQuery> whereUid() {
+ return mUid;
+ }
+
+ /** Queries {@link Uri}. */
+ @CheckResult
+ public UriQuery<DelegatedAdminChoosePrivateKeyAliasEventQuery> whereUri() {
+ return mUri;
+ }
+
+ /** Query {@code alias}. */
+ @CheckResult
+ public StringQuery<DelegatedAdminChoosePrivateKeyAliasEventQuery> whereAlias() {
+ return mAlias;
+ }
+
+ @Override
+ protected boolean filter(DelegatedAdminChoosePrivateKeyAliasEvent event) {
+ if (!mIntent.matches(event.mIntent)) {
+ return false;
+ }
+ if (!mDelegatedAdminReceiver.matches(event.mDelegatedAdminReceiver)) {
+ return false;
+ }
+ if (!mUid.matches(event.mUid)) {
+ return false;
+ }
+ if (!mUri.matches(event.mUri)) {
+ return false;
+ }
+ if (!mAlias.matches(event.mAlias)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String describeQuery(String fieldName) {
+ return toStringBuilder(DelegatedAdminChoosePrivateKeyAliasEvent.class, this)
+ .field("intent", mIntent)
+ .field("delegatedAdminReceiver", mDelegatedAdminReceiver)
+ .field("uid", mUid)
+ .field("uri", mUri)
+ .field("alias", mAlias)
+ .toString();
+ }
+ }
+
+ /** Begins logging a {@link DelegatedAdminChoosePrivateKeyAliasEvent}. */
+ public static DelegatedAdminChoosePrivateKeyAliasEventLogger logger(
+ DelegatedAdminReceiver delegatedAdminReceiver, Context context,
+ Intent intent, int uid, Uri uri, String alias) {
+ return new DelegatedAdminChoosePrivateKeyAliasEventLogger(
+ delegatedAdminReceiver, context, intent, uid, uri, alias);
+ }
+
+ /** {@link EventLogger} for {@link DelegatedAdminChoosePrivateKeyAliasEvent}. */
+ public static final class DelegatedAdminChoosePrivateKeyAliasEventLogger
+ extends EventLogger<DelegatedAdminChoosePrivateKeyAliasEvent> {
+ private DelegatedAdminChoosePrivateKeyAliasEventLogger(
+ DelegatedAdminReceiver delegatedAdminReceiver, Context context, Intent intent,
+ int uid, Uri uri, String alias) {
+ super(context, new DelegatedAdminChoosePrivateKeyAliasEvent());
+ mEvent.mIntent = new SerializableParcelWrapper<>(intent);
+ mEvent.mUid = uid;
+ mEvent.mUri = new SerializableParcelWrapper<>(uri);
+ mEvent.mAlias = alias;
+ setDelegatedAdminReceiver(delegatedAdminReceiver);
+ }
+
+ /** Sets the {@link DelegatedAdminReceiver} which received this event. */
+ public DelegatedAdminChoosePrivateKeyAliasEventLogger setDelegatedAdminReceiver(
+ DelegatedAdminReceiver delegatedAdminReceiver) {
+ mEvent.mDelegatedAdminReceiver = new DelegatedAdminReceiverInfo(delegatedAdminReceiver);
+ return this;
+ }
+
+ /** Sets the {@link DelegatedAdminReceiver} which received this event. */
+ public DelegatedAdminChoosePrivateKeyAliasEventLogger setDelegatedAdminReceiver(
+ Class<? extends DelegatedAdminReceiver> delegatedAdminReceiverClass) {
+ mEvent.mDelegatedAdminReceiver = new DelegatedAdminReceiverInfo(delegatedAdminReceiverClass);
+ return this;
+ }
+
+ /** Sets the {@link DelegatedAdminReceiver} which received this event. */
+ public DelegatedAdminChoosePrivateKeyAliasEventLogger setDelegatedAdminReceiver(
+ String delegatedAdminReceiverClassName) {
+ mEvent.mDelegatedAdminReceiver = new DelegatedAdminReceiverInfo(delegatedAdminReceiverClassName);
+ return this;
+ }
+
+ /** Sets the {@link Intent} which was received. */
+ public DelegatedAdminChoosePrivateKeyAliasEventLogger setIntent(Intent intent) {
+ mEvent.mIntent = new SerializableParcelWrapper<>(intent);
+ return this;
+ }
+
+ /** Sets the {@code uid} which was received. */
+ public DelegatedAdminChoosePrivateKeyAliasEventLogger setUid(int uid) {
+ mEvent.mUid = uid;
+ return this;
+ }
+
+ /** Sets the {@link Uri} which was received. */
+ public DelegatedAdminChoosePrivateKeyAliasEventLogger setUri(Uri uri) {
+ mEvent.mUri = new SerializableParcelWrapper<>(uri);
+ return this;
+ }
+
+ /** Sets the {@code alias} which was received. */
+ public DelegatedAdminChoosePrivateKeyAliasEventLogger setAlias(String alias) {
+ mEvent.mAlias = alias;
+ return this;
+ }
+ }
+
+ protected SerializableParcelWrapper<Intent> mIntent;
+ protected DelegatedAdminReceiverInfo mDelegatedAdminReceiver;
+ protected int mUid;
+ protected SerializableParcelWrapper<Uri> mUri;
+ protected String mAlias;
+
+ /**
+ * The {@link Intent} passed into
+ * {@link DelegatedAdminReceiver#onChoosePrivateKeyAlias(Context, Intent, int, Uri, String)
+ */
+ public Intent intent() {
+ if (mIntent == null) {
+ return null;
+ }
+ return mIntent.get();
+ }
+
+ /** Information about the {@link DelegatedAdminReceiver} which received the intent. */
+ public DelegatedAdminReceiverInfo delegatedAdminReceiver() {
+ return mDelegatedAdminReceiver;
+ }
+
+ /**
+ * The {@code uid} passed into
+ * {@link DelegatedAdminReceiver#onChoosePrivateKeyAlias(Context, Intent, int, Uri, String)
+ */
+ public int uid() {
+ return mUid;
+ }
+
+ /**
+ * The {@link Uri} passed into
+ * {@link DelegatedAdminReceiver#onChoosePrivateKeyAlias(Context, Intent, int, Uri, String)
+ */
+ public Uri uri() {
+ if (mUri == null) {
+ return null;
+ }
+ return mUri.get();
+ }
+
+ /**
+ * The {@code alias} passed into
+ * {@link DelegatedAdminReceiver#onChoosePrivateKeyAlias(Context, Intent, int, Uri, String)
+ */
+ public String alias() {
+ return mAlias;
+ }
+
+ @Override
+ public String toString() {
+ return "DelegatedAdminChoosePrivateKeyAliasEvent{"
+ + " intent=" + intent()
+ + ", uid=" + mUid
+ + ", uri=" + uri()
+ + ", alias=" + mAlias
+ + ", delegatedAdminReceiver=" + mDelegatedAdminReceiver
+ + ", packageName='" + mPackageName + "'"
+ + ", timestamp=" + mTimestamp
+ + "}";
+ }
+}
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminNetworkLogsAvailableEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminNetworkLogsAvailableEvent.java
new file mode 100644
index 0000000..39b61d3
--- /dev/null
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminNetworkLogsAvailableEvent.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.eventlib.events.deviceadminreceivers;
+
+import android.app.admin.DelegatedAdminReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.annotation.CheckResult;
+
+import com.android.eventlib.Event;
+import com.android.eventlib.EventLogger;
+import com.android.eventlib.EventLogsQuery;
+import com.android.queryable.info.DelegatedAdminReceiverInfo;
+import com.android.queryable.queries.DelegatedAdminReceiverQuery;
+import com.android.queryable.queries.DelegatedAdminReceiverQueryHelper;
+import com.android.queryable.queries.IntegerQueryHelper;
+import com.android.queryable.queries.IntentQueryHelper;
+import com.android.queryable.queries.LongQueryHelper;
+import com.android.queryable.util.SerializableParcelWrapper;
+
+/**
+ * Event logged when {@link DelegatedAdminReceiver#onNetworkLogsAvailable(Context, Intent, long,
+ * int)}
+ * is called.
+ */
+public final class DelegatedAdminNetworkLogsAvailableEvent extends Event {
+
+ private static final long serialVersionUID = 1;
+ protected SerializableParcelWrapper<Intent> mIntent;
+ protected DelegatedAdminReceiverInfo mDelegatedAdminReceiver;
+ protected long mBatchToken;
+ protected int mNetworkLogsCount;
+
+ /** Begins a query for {@link DelegatedAdminNetworkLogsAvailableEvent} events. */
+ public static DelegatedAdminNetworkLogsAvailableEventQuery queryPackage(String packageName) {
+ return new DelegatedAdminNetworkLogsAvailableEventQuery(packageName);
+ }
+
+ /** Begins logging a {@link DelegatedAdminNetworkLogsAvailableEvent}. */
+ public static DelegatedAdminNetworkLogsAvailableEventLogger logger(
+ DelegatedAdminReceiver delegatedAdminReceiver, Context context, Intent intent,
+ long batchToken, int networkLogsCount) {
+ return new DelegatedAdminNetworkLogsAvailableEventLogger(
+ delegatedAdminReceiver, context, intent, batchToken, networkLogsCount);
+ }
+
+ /**
+ * The {@link Intent} passed into
+ * {@link DelegatedAdminReceiver#onNetworkLogsAvailable(Context, Intent, long, int)}.
+ */
+ public Intent intent() {
+ if (mIntent == null) {
+ return null;
+ }
+ return mIntent.get();
+ }
+
+ /** Information about the {@link DelegatedAdminReceiver} which received the intent. */
+ public DelegatedAdminReceiverInfo delegatedAdminReceiver() {
+ return mDelegatedAdminReceiver;
+ }
+
+ /**
+ * The {@code batchToken} passed into
+ * {@link DelegatedAdminReceiver#onNetworkLogsAvailable(Context, Intent, long, int)}.
+ */
+ public long batchToken() {
+ return mBatchToken;
+ }
+
+ /**
+ * The {@code networkLogsCount} passed into
+ * {@link DelegatedAdminReceiver#onNetworkLogsAvailable(Context, Intent, long, int)}.
+ */
+ public int networkLogsCount() {
+ return mNetworkLogsCount;
+ }
+
+ @Override
+ public String toString() {
+ return "DelegatedAdminNetworkLogsAvailableEvent{"
+ + " intent=" + intent()
+ + ", batchToken=" + mBatchToken
+ + ", networkLogsCount=" + mNetworkLogsCount
+ + ", delegatedAdminReceiver=" + mDelegatedAdminReceiver
+ + ", packageName='" + mPackageName + "'"
+ + ", timestamp=" + mTimestamp
+ + "}";
+ }
+
+ /** {@link EventLogsQuery} for {@link DelegatedAdminNetworkLogsAvailableEvent}. */
+ public static final class DelegatedAdminNetworkLogsAvailableEventQuery
+ extends EventLogsQuery<DelegatedAdminNetworkLogsAvailableEvent,
+ DelegatedAdminNetworkLogsAvailableEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
+ DelegatedAdminReceiverQueryHelper<DelegatedAdminNetworkLogsAvailableEventQuery>
+ mDelegatedAdminReceiver =
+ new DelegatedAdminReceiverQueryHelper<>(this);
+ IntentQueryHelper<DelegatedAdminNetworkLogsAvailableEventQuery> mIntent =
+ new IntentQueryHelper<>(this);
+ LongQueryHelper<DelegatedAdminNetworkLogsAvailableEventQuery> mBatchToken =
+ new LongQueryHelper<>(this);
+ IntegerQueryHelper<DelegatedAdminNetworkLogsAvailableEventQuery> mNetworkLogsCount =
+ new IntegerQueryHelper<>(this);
+
+ private DelegatedAdminNetworkLogsAvailableEventQuery(String packageName) {
+ super(DelegatedAdminNetworkLogsAvailableEvent.class, packageName);
+ }
+
+ /**
+ * Queries {@link Intent} passed into
+ * {@link DelegatedAdminReceiver#onNetworkLogsAvailable(Context, Intent, long, int)}.
+ */
+ @CheckResult
+ public IntentQueryHelper<DelegatedAdminNetworkLogsAvailableEventQuery> whereIntent() {
+ return mIntent;
+ }
+
+ /** Queries {@link DelegatedAdminReceiver}. */
+ @CheckResult
+ public DelegatedAdminReceiverQuery<DelegatedAdminNetworkLogsAvailableEventQuery> whereDelegatedAdminReceiver() {
+ return mDelegatedAdminReceiver;
+ }
+
+ /**
+ * Query {@code batchToken} passed into
+ * {@link DelegatedAdminReceiver#onNetworkLogsAvailable(Context, Intent, long, int)}.
+ */
+ @CheckResult
+ public LongQueryHelper<DelegatedAdminNetworkLogsAvailableEventQuery> whereBatchToken() {
+ return mBatchToken;
+ }
+
+ /**
+ * Query {@code networkLogsCount} passed into
+ * {@link DelegatedAdminReceiver#onNetworkLogsAvailable(Context, Intent, long, int)}.
+ */
+ @CheckResult
+ public IntegerQueryHelper<DelegatedAdminNetworkLogsAvailableEventQuery> whereNetworkLogsCount() {
+ return mNetworkLogsCount;
+ }
+
+ @Override
+ protected boolean filter(DelegatedAdminNetworkLogsAvailableEvent event) {
+ if (!mIntent.matches(event.mIntent)) {
+ return false;
+ }
+ if (!mDelegatedAdminReceiver.matches(event.mDelegatedAdminReceiver)) {
+ return false;
+ }
+ if (!mBatchToken.matches(event.mBatchToken)) {
+ return false;
+ }
+ return mNetworkLogsCount.matches(event.mNetworkLogsCount);
+ }
+
+ @Override
+ public String describeQuery(String fieldName) {
+ return toStringBuilder(DelegatedAdminNetworkLogsAvailableEvent.class, this)
+ .field("intent", mIntent)
+ .field("delegatedAdminReceiver", mDelegatedAdminReceiver)
+ .field("batchToken", mBatchToken)
+ .field("networkLogsCount", mNetworkLogsCount)
+ .toString();
+ }
+ }
+
+ /** {@link EventLogger} for {@link DelegatedAdminNetworkLogsAvailableEvent}. */
+ public static final class DelegatedAdminNetworkLogsAvailableEventLogger
+ extends EventLogger<DelegatedAdminNetworkLogsAvailableEvent> {
+ private DelegatedAdminNetworkLogsAvailableEventLogger(
+ DelegatedAdminReceiver delegatedAdminReceiver, Context context, Intent intent,
+ long batchToken, int networkLogsCount) {
+ super(context, new DelegatedAdminNetworkLogsAvailableEvent());
+ mEvent.mIntent = new SerializableParcelWrapper<>(intent);
+ mEvent.mBatchToken = batchToken;
+ mEvent.mNetworkLogsCount = networkLogsCount;
+ setDelegatedAdminReceiver(delegatedAdminReceiver);
+ }
+
+ /** Sets the {@link DelegatedAdminReceiver} which received this event. */
+ public DelegatedAdminNetworkLogsAvailableEventLogger setDelegatedAdminReceiver(
+ DelegatedAdminReceiver delegatedAdminReceiver) {
+ mEvent.mDelegatedAdminReceiver = new DelegatedAdminReceiverInfo(delegatedAdminReceiver);
+ return this;
+ }
+
+ /** Sets the {@link DelegatedAdminReceiver} which received this event. */
+ public DelegatedAdminNetworkLogsAvailableEventLogger setDelegatedAdminReceiver(
+ Class<? extends DelegatedAdminReceiver> delegatedAdminReceiverClass) {
+ mEvent.mDelegatedAdminReceiver = new DelegatedAdminReceiverInfo(
+ delegatedAdminReceiverClass);
+ return this;
+ }
+
+ /** Sets the {@link DelegatedAdminReceiver} which received this event. */
+ public DelegatedAdminNetworkLogsAvailableEventLogger setDelegatedAdminReceiver(
+ String delegatedAdminReceiverClassName) {
+ mEvent.mDelegatedAdminReceiver = new DelegatedAdminReceiverInfo(
+ delegatedAdminReceiverClassName);
+ return this;
+ }
+
+ /** Sets the {@link Intent} which was received. */
+ public DelegatedAdminNetworkLogsAvailableEventLogger setIntent(Intent intent) {
+ mEvent.mIntent = new SerializableParcelWrapper<>(intent);
+ return this;
+ }
+
+ /** Sets the {@code batchToken} which was received. */
+ public DelegatedAdminNetworkLogsAvailableEventLogger setBatchToken(long batchToken) {
+ mEvent.mBatchToken = batchToken;
+ return this;
+ }
+
+ /** Sets the {@code networkLogsCount} which was received. */
+ public DelegatedAdminNetworkLogsAvailableEventLogger setNetworkLogsCount(
+ int networkLogsCount) {
+ mEvent.mNetworkLogsCount = networkLogsCount;
+ return this;
+ }
+ }
+}
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminReceiverEvents.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminReceiverEvents.java
new file mode 100644
index 0000000..9bb0552
--- /dev/null
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminReceiverEvents.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.eventlib.events.delegatedadminreceivers;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import com.android.eventlib.events.delegatedadminreceivers.DelegatedAdminChoosePrivateKeyAliasEvent.DelegatedAdminChoosePrivateKeyAliasEventQuery;
+import com.android.eventlib.events.delegatedadminreceivers.DelegatedAdminSecurityLogsAvailableEvent.DelegatedAdminSecurityLogsAvailableEventQuery;
+import com.android.eventlib.events.deviceadminreceivers.DelegatedAdminNetworkLogsAvailableEvent.DelegatedAdminNetworkLogsAvailableEventQuery;
+
+/**
+ * Quick access to event queries about device admin receivers.
+ */
+public interface DelegatedAdminReceiverEvents {
+
+ /**
+ * Query for when {@link DeviceAdminReceiver#onChoosePrivateKeyAlias(Context, Intent, int, Uri, String)}
+ * is called on a device admin receiver.
+ *
+ * <p>Additional filters can be added to the returned object.
+ *
+ * <p>{@code #poll} can be used to fetch results, and the result can be asserted on.
+ */
+ DelegatedAdminChoosePrivateKeyAliasEventQuery delegateChoosePrivateKeyAlias();
+
+ /**
+ * Query for when {@link DeviceAdminReceiver#onNetworkLogsAvailable(Context, Intent, long, int)}
+ * is called on a device admin receiver.
+ *
+ * <p>Additional filters can be added to the returned object.
+ *
+ * <p>{@code #poll} can be used to fetch results, and the result can be asserted on.
+ */
+ DelegatedAdminNetworkLogsAvailableEventQuery delegateNetworkLogsAvailable();
+
+ /**
+ * Query for when {@link DeviceAdminReceiver#onSecurityLogsAvailable(Context, Intent)} is called
+ * on a device admin receiver.
+ *
+ * <p>Additional filters can be added to the returned object.
+ *
+ * <p>{@code #poll} can be used to fetch results, and the result can be asserted on.
+ */
+ DelegatedAdminSecurityLogsAvailableEventQuery delegateSecurityLogsAvailable();
+}
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminSecurityLogsAvailableEvent.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminSecurityLogsAvailableEvent.java
new file mode 100644
index 0000000..fa6689d
--- /dev/null
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminSecurityLogsAvailableEvent.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.eventlib.events.delegatedadminreceivers;
+
+import android.app.admin.DelegatedAdminReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.annotation.CheckResult;
+
+import com.android.eventlib.Event;
+import com.android.eventlib.EventLogger;
+import com.android.eventlib.EventLogsQuery;
+import com.android.queryable.info.DelegatedAdminReceiverInfo;
+import com.android.queryable.queries.DelegatedAdminReceiverQuery;
+import com.android.queryable.queries.DelegatedAdminReceiverQueryHelper;
+import com.android.queryable.queries.IntentQueryHelper;
+import com.android.queryable.util.SerializableParcelWrapper;
+
+/**
+ * Event logged when {@link DelegatedAdminReceiver#onSecurityLogsAvailable(Context, Intent)}
+ * is called.
+ */
+public final class DelegatedAdminSecurityLogsAvailableEvent extends Event {
+
+ private static final long serialVersionUID = 1;
+ protected SerializableParcelWrapper<Intent> mIntent;
+ protected DelegatedAdminReceiverInfo mDelegatedAdminReceiver;
+
+ /** Begins a query for {@link DelegatedAdminSecurityLogsAvailableEvent} events. */
+ public static DelegatedAdminSecurityLogsAvailableEventQuery queryPackage(String packageName) {
+ return new DelegatedAdminSecurityLogsAvailableEventQuery(packageName);
+ }
+
+ /** Begins logging a {@link DelegatedAdminSecurityLogsAvailableEvent}. */
+ public static DelegatedAdminSecurityLogsAvailableEventLogger logger(
+ DelegatedAdminReceiver delegatedAdminReceiver, Context context, Intent intent) {
+ return new DelegatedAdminSecurityLogsAvailableEventLogger(delegatedAdminReceiver, context,
+ intent);
+ }
+
+ /**
+ * The {@link Intent} passed into
+ * {@link DelegatedAdminReceiver#onSecurityLogsAvailable(Context, Intent)}.
+ */
+ public Intent intent() {
+ if (mIntent == null) {
+ return null;
+ }
+ return mIntent.get();
+ }
+
+ /** Information about the {@link DelegatedAdminReceiver} which received the intent. */
+ public DelegatedAdminReceiverInfo delegatedAdminReceiver() {
+ return mDelegatedAdminReceiver;
+ }
+
+ @Override
+ public String toString() {
+ return "DelegatedAdminSecurityLogsAvailableEvent{"
+ + " intent=" + intent()
+ + ", delegatedAdminReceiver=" + mDelegatedAdminReceiver
+ + ", packageName='" + mPackageName + "'"
+ + ", timestamp=" + mTimestamp
+ + "}";
+ }
+
+ /** {@link EventLogsQuery} for {@link DelegatedAdminSecurityLogsAvailableEvent}. */
+ public static final class DelegatedAdminSecurityLogsAvailableEventQuery
+ extends EventLogsQuery<DelegatedAdminSecurityLogsAvailableEvent,
+ DelegatedAdminSecurityLogsAvailableEventQuery> {
+
+ private static final long serialVersionUID = 1;
+
+ DelegatedAdminReceiverQueryHelper<DelegatedAdminSecurityLogsAvailableEventQuery>
+ mDelegatedAdminReceiver =
+ new DelegatedAdminReceiverQueryHelper<>(this);
+ IntentQueryHelper<DelegatedAdminSecurityLogsAvailableEventQuery> mIntent =
+ new IntentQueryHelper<>(this);
+
+ private DelegatedAdminSecurityLogsAvailableEventQuery(String packageName) {
+ super(DelegatedAdminSecurityLogsAvailableEvent.class, packageName);
+ }
+
+ /**
+ * Queries {@link Intent} passed into
+ * {@link DelegatedAdminReceiver#onSecurityLogsAvailable(Context, Intent)}.
+ */
+ @CheckResult
+ public IntentQueryHelper<DelegatedAdminSecurityLogsAvailableEventQuery> whereIntent() {
+ return mIntent;
+ }
+
+ /** Queries {@link DelegatedAdminReceiver}. */
+ @CheckResult
+ public DelegatedAdminReceiverQuery<DelegatedAdminSecurityLogsAvailableEventQuery> whereDelegatedAdminReceiver() {
+ return mDelegatedAdminReceiver;
+ }
+
+ @Override
+ protected boolean filter(DelegatedAdminSecurityLogsAvailableEvent event) {
+ if (!mIntent.matches(event.mIntent)) {
+ return false;
+ }
+ return mDelegatedAdminReceiver.matches(event.mDelegatedAdminReceiver);
+ }
+
+ @Override
+ public String describeQuery(String fieldName) {
+ return toStringBuilder(DelegatedAdminSecurityLogsAvailableEvent.class, this)
+ .field("intent", mIntent)
+ .field("delegatedAdminReceiver", mDelegatedAdminReceiver)
+ .toString();
+ }
+ }
+
+ /** {@link EventLogger} for {@link DelegatedAdminSecurityLogsAvailableEvent}. */
+ public static final class DelegatedAdminSecurityLogsAvailableEventLogger
+ extends EventLogger<DelegatedAdminSecurityLogsAvailableEvent> {
+ private DelegatedAdminSecurityLogsAvailableEventLogger(
+ DelegatedAdminReceiver delegatedAdminReceiver, Context context, Intent intent) {
+ super(context, new DelegatedAdminSecurityLogsAvailableEvent());
+ mEvent.mIntent = new SerializableParcelWrapper<>(intent);
+ setDelegatedAdminReceiver(delegatedAdminReceiver);
+ }
+
+ /** Sets the {@link DelegatedAdminReceiver} which received this event. */
+ public DelegatedAdminSecurityLogsAvailableEventLogger setDelegatedAdminReceiver(
+ DelegatedAdminReceiver delegatedAdminReceiver) {
+ mEvent.mDelegatedAdminReceiver = new DelegatedAdminReceiverInfo(delegatedAdminReceiver);
+ return this;
+ }
+
+ /** Sets the {@link DelegatedAdminReceiver} which received this event. */
+ public DelegatedAdminSecurityLogsAvailableEventLogger setDelegatedAdminReceiver(
+ Class<? extends DelegatedAdminReceiver> delegatedAdminReceiverClass) {
+ mEvent.mDelegatedAdminReceiver = new DelegatedAdminReceiverInfo(
+ delegatedAdminReceiverClass);
+ return this;
+ }
+
+ /** Sets the {@link DelegatedAdminReceiver} which received this event. */
+ public DelegatedAdminSecurityLogsAvailableEventLogger setDelegatedAdminReceiver(
+ String delegatedAdminReceiverClassName) {
+ mEvent.mDelegatedAdminReceiver = new DelegatedAdminReceiverInfo(
+ delegatedAdminReceiverClassName);
+ return this;
+ }
+
+ /** Sets the {@link Intent} which was received. */
+ public DelegatedAdminSecurityLogsAvailableEventLogger setIntent(Intent intent) {
+ mEvent.mIntent = new SerializableParcelWrapper<>(intent);
+ return this;
+ }
+ }
+}
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/premade/EventLibAppComponentFactory.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/premade/EventLibAppComponentFactory.java
index 9d304b9..7cdfabc 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/premade/EventLibAppComponentFactory.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/premade/EventLibAppComponentFactory.java
@@ -54,6 +54,26 @@
try {
return super.instantiateReceiver(classLoader, className, intent);
} catch (ClassNotFoundException e) {
+ if (className.endsWith("DeviceAdminReceiver")) {
+ Log.d(LOG_TAG, "Broadcast Receiver class (" + className
+ + ") not found, routing to TestAppDeviceAdminReceiver");
+ EventLibDeviceAdminReceiver receiver = (EventLibDeviceAdminReceiver)
+ super.instantiateReceiver(
+ classLoader, EventLibDeviceAdminReceiver.class.getName(),
+ intent);
+ receiver.setOverrideDeviceAdminReceiverClassName(className);
+ return receiver;
+ } else if (className.endsWith("DelegatedAdminReceiver")) {
+ Log.d(LOG_TAG, "Broadcast Receiver class (" + className
+ + ") not found, routing to EventLibDelegatedAdminReceiver");
+ EventLibDelegatedAdminReceiver receiver = (EventLibDelegatedAdminReceiver)
+ super.instantiateReceiver(
+ classLoader, EventLibDelegatedAdminReceiver.class.getName(),
+ intent);
+ receiver.setOverrideDelegatedAdminReceiverClassName(className);
+ return receiver;
+ }
+
Log.d(LOG_TAG, "Broadcast Receiver class (" + className
+ ") not found, routing to EventLibBroadcastReceiver");
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/premade/EventLibDelegatedAdminReceiver.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/premade/EventLibDelegatedAdminReceiver.java
new file mode 100644
index 0000000..891819d
--- /dev/null
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/premade/EventLibDelegatedAdminReceiver.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.eventlib.premade;
+
+import android.app.admin.DelegatedAdminReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import com.android.eventlib.events.delegatedadminreceivers.DelegatedAdminChoosePrivateKeyAliasEvent;
+import com.android.eventlib.events.delegatedadminreceivers.DelegatedAdminChoosePrivateKeyAliasEvent.DelegatedAdminChoosePrivateKeyAliasEventLogger;
+import com.android.eventlib.events.delegatedadminreceivers.DelegatedAdminSecurityLogsAvailableEvent;
+import com.android.eventlib.events.delegatedadminreceivers.DelegatedAdminSecurityLogsAvailableEvent.DelegatedAdminSecurityLogsAvailableEventLogger;
+import com.android.eventlib.events.deviceadminreceivers.DelegatedAdminNetworkLogsAvailableEvent;
+import com.android.eventlib.events.deviceadminreceivers.DelegatedAdminNetworkLogsAvailableEvent.DelegatedAdminNetworkLogsAvailableEventLogger;
+
+/**
+ * {@link DelegatedAdminReceiver} which logs all callbacks using EventLib.
+ */
+@SuppressWarnings("NewApi")
+public class EventLibDelegatedAdminReceiver extends DelegatedAdminReceiver {
+
+ private String mOverrideDelegatedAdminReceiverClassName;
+
+ public void setOverrideDelegatedAdminReceiverClassName(
+ String overrideDelegatedAdminReceiverClassName) {
+ mOverrideDelegatedAdminReceiverClassName = overrideDelegatedAdminReceiverClassName;
+ }
+
+ /**
+ * Get the class name for this {@link DelegatedAdminReceiver}.
+ *
+ * <p>This will account for the name being overridden.
+ */
+ public String className() {
+ if (mOverrideDelegatedAdminReceiverClassName != null) {
+ return mOverrideDelegatedAdminReceiverClassName;
+ } else {
+ return EventLibDelegatedAdminReceiver.class.getName();
+ }
+ }
+
+ @Override
+ public String onChoosePrivateKeyAlias(Context context, Intent intent, int uid, Uri uri,
+ String alias) {
+ DelegatedAdminChoosePrivateKeyAliasEventLogger logger =
+ DelegatedAdminChoosePrivateKeyAliasEvent
+ .logger(this, context, intent, uid, uri, alias);
+
+ if (mOverrideDelegatedAdminReceiverClassName != null) {
+ logger.setDelegatedAdminReceiver(mOverrideDelegatedAdminReceiverClassName);
+ }
+
+ logger.log();
+
+ // TODO(b/198280332) Allow TestApp to return values for methods.
+ if (uri == null) {
+ return null;
+ }
+ return uri.getQueryParameter("alias");
+ }
+
+ @Override
+ public void onNetworkLogsAvailable(Context context, Intent intent, long batchToken,
+ int networkLogsCount) {
+ DelegatedAdminNetworkLogsAvailableEventLogger logger =
+ DelegatedAdminNetworkLogsAvailableEvent
+ .logger(this, context, intent, batchToken, networkLogsCount);
+
+ if (mOverrideDelegatedAdminReceiverClassName != null) {
+ logger.setDelegatedAdminReceiver(mOverrideDelegatedAdminReceiverClassName);
+ }
+
+ logger.log();
+ }
+
+ @Override
+ public void onSecurityLogsAvailable(Context context, Intent intent) {
+ DelegatedAdminSecurityLogsAvailableEventLogger logger =
+ DelegatedAdminSecurityLogsAvailableEvent.logger(this, context, intent);
+
+ if (mOverrideDelegatedAdminReceiverClassName != null) {
+ logger.setDelegatedAdminReceiver(mOverrideDelegatedAdminReceiverClassName);
+ }
+
+ logger.log();
+ }
+}
diff --git a/common/device-side/bedstead/eventlib/src/test/AndroidManifest.xml b/common/device-side/bedstead/eventlib/src/test/AndroidManifest.xml
index bca5f18..a626be8 100644
--- a/common/device-side/bedstead/eventlib/src/test/AndroidManifest.xml
+++ b/common/device-side/bedstead/eventlib/src/test/AndroidManifest.xml
@@ -52,6 +52,17 @@
</intent-filter>
</receiver>
+ <receiver android:name="com.android.eventlib.premade.EventLibDelegatedAdminReceiver"
+ android:permission="android.permission.BIND_DEVICE_ADMIN"
+ android:exported="true">
+
+ <intent-filter>
+ <action android:name="android.app.action.CHOOSE_PRIVATE_KEY_ALIAS"/>
+ <action android:name="android.app.action.NETWORK_LOGS_AVAILABLE"/>
+ <action android:name="android.app.action.SECURITY_LOGS_AVAILABLE"/>
+ </intent-filter>
+ </receiver>
+
<service android:name="com.android.eventlib.premade.EventLibService"
android:exported="true" />
<service android:name="com.android.generatedEventLibService" />
diff --git a/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminNetworkLogsAvailableEventTest.java b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminNetworkLogsAvailableEventTest.java
new file mode 100644
index 0000000..dc6c057
--- /dev/null
+++ b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminNetworkLogsAvailableEventTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.eventlib.events.delegatedadminreceivers;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.admin.DelegatedAdminReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import com.android.bedstead.nene.TestApis;
+import com.android.eventlib.EventLogs;
+import com.android.eventlib.events.deviceadminreceivers.DelegatedAdminNetworkLogsAvailableEvent;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class DelegatedAdminNetworkLogsAvailableEventTest {
+
+ private static final Context sContext = TestApis.context().instrumentedContext();
+ private static final String STRING_VALUE = "Value";
+ private static final String DIFFERENT_STRING_VALUE = "Value2";
+ private static final Intent INTENT = new Intent();
+
+ private static final String DEFAULT_DEVICE_ADMIN_RECEIVER_CLASS_NAME =
+ TestDelegatedAdminReceiver.class.getName();
+ private static final String CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME =
+ "customDelegatedAdminReceiver";
+ private static final String DIFFERENT_CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME =
+ "customDelegatedAdminReceiver2";
+ private static final DelegatedAdminReceiver DEVICE_ADMIN_RECEIVER = new TestDelegatedAdminReceiver();
+ private static final long BATCH_TOKEN = 1;
+ private static final long DIFFERENT_BATCH_TOKEN = 2;
+ private static final int NETWORK_LOGS_COUNT = 1;
+ private static final int DIFFERENT_NETWORK_LOGS_COUNT = 2;
+
+ private static class TestDelegatedAdminReceiver extends DelegatedAdminReceiver {
+ }
+
+ @Before
+ public void setUp() {
+ EventLogs.resetLogs();
+ }
+
+ @Test
+ public void whereIntent_works() {
+ Intent intent = new Intent(STRING_VALUE);
+ DelegatedAdminNetworkLogsAvailableEvent.logger(
+ DEVICE_ADMIN_RECEIVER, sContext, intent, BATCH_TOKEN, NETWORK_LOGS_COUNT).log();
+
+ EventLogs<DelegatedAdminNetworkLogsAvailableEvent> eventLogs =
+ DelegatedAdminNetworkLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereIntent().action().isEqualTo(STRING_VALUE);
+
+ assertThat(eventLogs.poll().intent()).isEqualTo(intent);
+ }
+
+ @Test
+ public void whereIntent_skipsNonMatching() {
+ Intent intent = new Intent(STRING_VALUE);
+ Intent differentIntent = new Intent();
+ differentIntent.setAction(DIFFERENT_STRING_VALUE);
+ DelegatedAdminNetworkLogsAvailableEvent.logger(
+ DEVICE_ADMIN_RECEIVER, sContext, differentIntent, BATCH_TOKEN, NETWORK_LOGS_COUNT).log();
+ DelegatedAdminNetworkLogsAvailableEvent.logger(
+ DEVICE_ADMIN_RECEIVER, sContext, intent, BATCH_TOKEN, NETWORK_LOGS_COUNT).log();
+
+ EventLogs<DelegatedAdminNetworkLogsAvailableEvent> eventLogs =
+ DelegatedAdminNetworkLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereIntent().action().isEqualTo(STRING_VALUE);
+
+ assertThat(eventLogs.poll().intent()).isEqualTo(intent);
+ }
+
+ @Test
+ public void whereDelegatedAdminReceiver_customValueOnLogger_works() {
+ DelegatedAdminNetworkLogsAvailableEvent.logger(DEVICE_ADMIN_RECEIVER, sContext, INTENT, BATCH_TOKEN, NETWORK_LOGS_COUNT)
+ .setDelegatedAdminReceiver(CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME)
+ .log();
+
+ EventLogs<DelegatedAdminNetworkLogsAvailableEvent> eventLogs =
+ DelegatedAdminNetworkLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereDelegatedAdminReceiver().broadcastReceiver().receiverClass().className().isEqualTo(
+ CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+
+ assertThat(eventLogs.poll().delegatedAdminReceiver().className()).isEqualTo(
+ CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+ }
+
+ @Test
+ public void whereDelegatedAdminReceiver_customValueOnLogger_skipsNonMatching() {
+ DelegatedAdminNetworkLogsAvailableEvent.logger(
+ DEVICE_ADMIN_RECEIVER, sContext, INTENT, BATCH_TOKEN, NETWORK_LOGS_COUNT)
+ .setDelegatedAdminReceiver(DIFFERENT_CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME)
+ .log();
+ DelegatedAdminNetworkLogsAvailableEvent.logger(
+ DEVICE_ADMIN_RECEIVER, sContext, INTENT, BATCH_TOKEN, NETWORK_LOGS_COUNT)
+ .setDelegatedAdminReceiver(CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME)
+ .log();
+
+ EventLogs<DelegatedAdminNetworkLogsAvailableEvent> eventLogs =
+ DelegatedAdminNetworkLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereDelegatedAdminReceiver().broadcastReceiver().receiverClass().className().isEqualTo(
+ CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+
+ assertThat(eventLogs.poll().delegatedAdminReceiver().className()).isEqualTo(
+ CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+ }
+
+ @Test
+ public void whereDelegatedAdminReceiver_defaultValue_works() {
+ DelegatedAdminNetworkLogsAvailableEvent.logger(
+ DEVICE_ADMIN_RECEIVER, sContext, INTENT, BATCH_TOKEN, NETWORK_LOGS_COUNT).log();
+
+ EventLogs<DelegatedAdminNetworkLogsAvailableEvent> eventLogs =
+ DelegatedAdminNetworkLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereDelegatedAdminReceiver().broadcastReceiver().receiverClass().className()
+ .isEqualTo(DEFAULT_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+
+ assertThat(eventLogs.poll().delegatedAdminReceiver().className())
+ .isEqualTo(DEFAULT_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+ }
+
+ @Test
+ public void whereDelegatedAdminReceiver_defaultValue_skipsNonMatching() {
+ DelegatedAdminNetworkLogsAvailableEvent.logger(
+ DEVICE_ADMIN_RECEIVER, sContext, INTENT, BATCH_TOKEN, NETWORK_LOGS_COUNT)
+ .setDelegatedAdminReceiver(CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME)
+ .log();
+ DelegatedAdminNetworkLogsAvailableEvent.logger(
+ DEVICE_ADMIN_RECEIVER, sContext, INTENT, BATCH_TOKEN, NETWORK_LOGS_COUNT)
+ .log();
+
+ EventLogs<DelegatedAdminNetworkLogsAvailableEvent> eventLogs =
+ DelegatedAdminNetworkLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereDelegatedAdminReceiver().broadcastReceiver().receiverClass().className()
+ .isEqualTo(DEFAULT_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+
+ assertThat(eventLogs.poll().delegatedAdminReceiver().className())
+ .isEqualTo(DEFAULT_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+ }
+
+ @Test
+ public void whereBatchToken_works() {
+ DelegatedAdminNetworkLogsAvailableEvent.logger(
+ DEVICE_ADMIN_RECEIVER, sContext, INTENT, BATCH_TOKEN, NETWORK_LOGS_COUNT).log();
+
+ EventLogs<DelegatedAdminNetworkLogsAvailableEvent> eventLogs =
+ DelegatedAdminNetworkLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereBatchToken().isEqualTo(BATCH_TOKEN);
+
+ assertThat(eventLogs.poll().batchToken()).isEqualTo(BATCH_TOKEN);
+ }
+
+ @Test
+ public void whereBatchToken_skipsNonMatching() {
+ DelegatedAdminNetworkLogsAvailableEvent.logger(
+ DEVICE_ADMIN_RECEIVER, sContext, INTENT, DIFFERENT_BATCH_TOKEN, NETWORK_LOGS_COUNT).log();
+ DelegatedAdminNetworkLogsAvailableEvent.logger(
+ DEVICE_ADMIN_RECEIVER, sContext, INTENT, BATCH_TOKEN, NETWORK_LOGS_COUNT).log();
+
+ EventLogs<DelegatedAdminNetworkLogsAvailableEvent> eventLogs =
+ DelegatedAdminNetworkLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereBatchToken().isEqualTo(BATCH_TOKEN);
+
+ assertThat(eventLogs.poll().batchToken()).isEqualTo(BATCH_TOKEN);
+ }
+
+ @Test
+ public void whereNetworkLogsCount_works() {
+ DelegatedAdminNetworkLogsAvailableEvent.logger(
+ DEVICE_ADMIN_RECEIVER, sContext, INTENT, BATCH_TOKEN, NETWORK_LOGS_COUNT).log();
+
+ EventLogs<DelegatedAdminNetworkLogsAvailableEvent> eventLogs =
+ DelegatedAdminNetworkLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereNetworkLogsCount().isEqualTo(NETWORK_LOGS_COUNT);
+
+ assertThat(eventLogs.poll().networkLogsCount()).isEqualTo(NETWORK_LOGS_COUNT);
+ }
+
+ @Test
+ public void whereNetworkLogsCount_skipsNonMatching() {
+ DelegatedAdminNetworkLogsAvailableEvent.logger(
+ DEVICE_ADMIN_RECEIVER, sContext, INTENT, BATCH_TOKEN, DIFFERENT_NETWORK_LOGS_COUNT).log();
+ DelegatedAdminNetworkLogsAvailableEvent.logger(
+ DEVICE_ADMIN_RECEIVER, sContext, INTENT, BATCH_TOKEN, NETWORK_LOGS_COUNT).log();
+
+ EventLogs<DelegatedAdminNetworkLogsAvailableEvent> eventLogs =
+ DelegatedAdminNetworkLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereNetworkLogsCount().isEqualTo(NETWORK_LOGS_COUNT);
+
+ assertThat(eventLogs.poll().networkLogsCount()).isEqualTo(NETWORK_LOGS_COUNT);
+ }
+}
diff --git a/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminSecurityLogsAvailableEventTest.java b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminSecurityLogsAvailableEventTest.java
new file mode 100644
index 0000000..42a5565
--- /dev/null
+++ b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/delegatedadminreceivers/DelegatedAdminSecurityLogsAvailableEventTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.eventlib.events.delegatedadminreceivers;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.admin.DelegatedAdminReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import com.android.bedstead.nene.TestApis;
+import com.android.eventlib.EventLogs;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class DelegatedAdminSecurityLogsAvailableEventTest {
+
+ private static final Context sContext = TestApis.context().instrumentedContext();
+ private static final String STRING_VALUE = "Value";
+ private static final String DIFFERENT_STRING_VALUE = "Value2";
+ private static final Intent INTENT = new Intent();
+
+ private static final String DEFAULT_DEVICE_ADMIN_RECEIVER_CLASS_NAME =
+ TestDelegatedAdminReceiver.class.getName();
+ private static final String CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME =
+ "customDelegatedAdminReceiver";
+ private static final String DIFFERENT_CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME =
+ "customDelegatedAdminReceiver2";
+ private static final DelegatedAdminReceiver DEVICE_ADMIN_RECEIVER = new TestDelegatedAdminReceiver();
+
+ private static class TestDelegatedAdminReceiver extends DelegatedAdminReceiver {
+ }
+
+ @Before
+ public void setUp() {
+ EventLogs.resetLogs();
+ }
+
+ @Test
+ public void whereIntent_works() {
+ Intent intent = new Intent(STRING_VALUE);
+ DelegatedAdminSecurityLogsAvailableEvent.logger(DEVICE_ADMIN_RECEIVER, sContext, intent).log();
+
+ EventLogs<DelegatedAdminSecurityLogsAvailableEvent> eventLogs =
+ DelegatedAdminSecurityLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereIntent().action().isEqualTo(STRING_VALUE);
+
+ assertThat(eventLogs.poll().intent()).isEqualTo(intent);
+ }
+
+ @Test
+ public void whereIntent_skipsNonMatching() {
+ Intent intent = new Intent(STRING_VALUE);
+ Intent differentIntent = new Intent();
+ differentIntent.setAction(DIFFERENT_STRING_VALUE);
+ DelegatedAdminSecurityLogsAvailableEvent.logger(
+ DEVICE_ADMIN_RECEIVER, sContext, differentIntent).log();
+ DelegatedAdminSecurityLogsAvailableEvent.logger(DEVICE_ADMIN_RECEIVER, sContext, intent).log();
+
+ EventLogs<DelegatedAdminSecurityLogsAvailableEvent> eventLogs =
+ DelegatedAdminSecurityLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereIntent().action().isEqualTo(STRING_VALUE);
+
+ assertThat(eventLogs.poll().intent()).isEqualTo(intent);
+ }
+
+ @Test
+ public void whereDelegatedAdminReceiver_customValueOnLogger_works() {
+ DelegatedAdminSecurityLogsAvailableEvent.logger(DEVICE_ADMIN_RECEIVER, sContext, INTENT)
+ .setDelegatedAdminReceiver(CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME)
+ .log();
+
+ EventLogs<DelegatedAdminSecurityLogsAvailableEvent> eventLogs =
+ DelegatedAdminSecurityLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereDelegatedAdminReceiver().broadcastReceiver().receiverClass().className()
+ .isEqualTo(CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+
+ assertThat(eventLogs.poll().delegatedAdminReceiver().className()).isEqualTo(
+ CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+ }
+
+ @Test
+ public void whereDelegatedAdminReceiver_customValueOnLogger_skipsNonMatching() {
+ DelegatedAdminSecurityLogsAvailableEvent.logger(DEVICE_ADMIN_RECEIVER, sContext, INTENT)
+ .setDelegatedAdminReceiver(DIFFERENT_CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME)
+ .log();
+ DelegatedAdminSecurityLogsAvailableEvent.logger(DEVICE_ADMIN_RECEIVER, sContext, INTENT)
+ .setDelegatedAdminReceiver(CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME)
+ .log();
+
+ EventLogs<DelegatedAdminSecurityLogsAvailableEvent> eventLogs =
+ DelegatedAdminSecurityLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereDelegatedAdminReceiver().broadcastReceiver().receiverClass().className()
+ .isEqualTo(CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+
+ assertThat(eventLogs.poll().delegatedAdminReceiver().className()).isEqualTo(
+ CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+ }
+
+ @Test
+ public void whereDelegatedAdminReceiver_defaultValue_works() {
+ DelegatedAdminSecurityLogsAvailableEvent.logger(DEVICE_ADMIN_RECEIVER, sContext, INTENT).log();
+
+ EventLogs<DelegatedAdminSecurityLogsAvailableEvent> eventLogs =
+ DelegatedAdminSecurityLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereDelegatedAdminReceiver().broadcastReceiver().receiverClass().className()
+ .isEqualTo(DEFAULT_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+
+ assertThat(eventLogs.poll().delegatedAdminReceiver().className())
+ .isEqualTo(DEFAULT_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+ }
+
+ @Test
+ public void whereDelegatedAdminReceiver_defaultValue_skipsNonMatching() {
+ DelegatedAdminSecurityLogsAvailableEvent.logger(DEVICE_ADMIN_RECEIVER, sContext, INTENT)
+ .setDelegatedAdminReceiver(CUSTOM_DEVICE_ADMIN_RECEIVER_CLASS_NAME)
+ .log();
+ DelegatedAdminSecurityLogsAvailableEvent.logger(DEVICE_ADMIN_RECEIVER, sContext, INTENT)
+ .log();
+
+ EventLogs<DelegatedAdminSecurityLogsAvailableEvent> eventLogs =
+ DelegatedAdminSecurityLogsAvailableEvent.queryPackage(sContext.getPackageName())
+ .whereDelegatedAdminReceiver().broadcastReceiver().receiverClass().className()
+ .isEqualTo(DEFAULT_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+
+ assertThat(eventLogs.poll().delegatedAdminReceiver().className())
+ .isEqualTo(DEFAULT_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+ }
+}
diff --git a/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceConfigurationChangedEventTest.java b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceConfigurationChangedEventTest.java
index a4f0493..a51c57b 100644
--- a/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceConfigurationChangedEventTest.java
+++ b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceConfigurationChangedEventTest.java
@@ -16,10 +16,6 @@
package com.android.eventlib.events.services;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-
//TODO(b/204770471) Currently unable to create these tests without an instrumented service.
-@RunWith(JUnit4.class)
+//@RunWith(JUnit4.class)
public class ServiceConfigurationChangedEventTest {}
diff --git a/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceLowMemoryEventTest.java b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceLowMemoryEventTest.java
index 4808a5b..edd15e8 100644
--- a/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceLowMemoryEventTest.java
+++ b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceLowMemoryEventTest.java
@@ -16,10 +16,6 @@
package com.android.eventlib.events.services;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-
//TODO(b/204770471) Currently unable to create these tests without an instrumented service.
-@RunWith(JUnit4.class)
+//@RunWith(JUnit4.class)
public class ServiceLowMemoryEventTest {}
diff --git a/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceMemoryTrimmedEventTest.java b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceMemoryTrimmedEventTest.java
index 53a69cf..c633e3e 100644
--- a/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceMemoryTrimmedEventTest.java
+++ b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceMemoryTrimmedEventTest.java
@@ -16,10 +16,6 @@
package com.android.eventlib.events.services;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-
//TODO(b/204770471) Currently unable to create these tests without an instrumented service.
-@RunWith(JUnit4.class)
+//@RunWith(JUnit4.class)
public class ServiceMemoryTrimmedEventTest {}
diff --git a/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceReboundEventTest.java b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceReboundEventTest.java
index 9776bfa..0c09f39 100644
--- a/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceReboundEventTest.java
+++ b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceReboundEventTest.java
@@ -16,10 +16,6 @@
package com.android.eventlib.events.services;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-
//TODO(b/204770471) Currently unable to create these tests without an instrumented service.
-@RunWith(JUnit4.class)
+//@RunWith(JUnit4.class)
public class ServiceReboundEventTest {}
diff --git a/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceTaskRemovedEventTest.java b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceTaskRemovedEventTest.java
index 40f1807..878a41a 100644
--- a/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceTaskRemovedEventTest.java
+++ b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/events/services/ServiceTaskRemovedEventTest.java
@@ -16,10 +16,6 @@
package com.android.eventlib.events.services;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-
//TODO(b/204770471) Currently unable to create these tests without an instrumented service.
-@RunWith(JUnit4.class)
+//@RunWith(JUnit4.class)
public class ServiceTaskRemovedEventTest {}
diff --git a/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/premade/EventLibDelegatedAdminReceiverTest.java b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/premade/EventLibDelegatedAdminReceiverTest.java
new file mode 100644
index 0000000..5959f15
--- /dev/null
+++ b/common/device-side/bedstead/eventlib/src/test/java/com/android/eventlib/premade/EventLibDelegatedAdminReceiverTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.eventlib.premade;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import com.android.bedstead.harrier.BedsteadJUnit4;
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.nene.TestApis;
+import com.android.eventlib.EventLogs;
+import com.android.eventlib.events.delegatedadminreceivers.DelegatedAdminChoosePrivateKeyAliasEvent;
+import com.android.eventlib.events.delegatedadminreceivers.DelegatedAdminSecurityLogsAvailableEvent;
+import com.android.eventlib.events.deviceadminreceivers.DelegatedAdminNetworkLogsAvailableEvent;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(BedsteadJUnit4.class)
+public class EventLibDelegatedAdminReceiverTest {
+
+ @ClassRule @Rule
+ public static final DeviceState sDeviceState = new DeviceState();
+
+ private static final Context sContext = TestApis.context().instrumentedContext();
+ private static final Intent sIntent = new Intent();
+ private static final int UID = 1;
+ private static final Uri URI = Uri.parse("http://uri");
+ private static final String ALIAS = "alias";
+ private static final long BATCH_TOKEN = 1;
+ private static final int NETWORK_LOGS_COUNT = 1;
+
+ @Before
+ public void setUp() {
+ EventLogs.resetLogs();
+ }
+
+ @Test
+ public void choosePrivateKeyAlias_logsChoosePrivateKeyAliasEvent() {
+ EventLibDelegatedAdminReceiver receiver = new EventLibDelegatedAdminReceiver();
+
+ receiver.onChoosePrivateKeyAlias(sContext, sIntent, UID, URI, ALIAS);
+
+ EventLogs<DelegatedAdminChoosePrivateKeyAliasEvent> eventLogs =
+ DelegatedAdminChoosePrivateKeyAliasEvent.queryPackage(sContext.getPackageName());
+ assertThat(eventLogs.poll().intent()).isEqualTo(sIntent);
+ }
+
+ @Test
+ public void securityLogsAvailable_logsSecurityLogsAvailableEvent() {
+ EventLibDelegatedAdminReceiver receiver = new EventLibDelegatedAdminReceiver();
+
+ receiver.onSecurityLogsAvailable(sContext, sIntent);
+
+ EventLogs<DelegatedAdminSecurityLogsAvailableEvent> eventLogs =
+ DelegatedAdminSecurityLogsAvailableEvent.queryPackage(sContext.getPackageName());
+ assertThat(eventLogs.poll().intent()).isEqualTo(sIntent);
+ }
+
+ @Test
+ public void networkLogsAvailable_logsNetworksLogsAvailableEvent() {
+ EventLibDelegatedAdminReceiver receiver = new EventLibDelegatedAdminReceiver();
+
+ receiver.onNetworkLogsAvailable(sContext, sIntent, BATCH_TOKEN, NETWORK_LOGS_COUNT);
+
+ EventLogs<DelegatedAdminNetworkLogsAvailableEvent> eventLogs =
+ DelegatedAdminNetworkLogsAvailableEvent.queryPackage(sContext.getPackageName());
+ assertThat(eventLogs.poll().intent()).isEqualTo(sIntent);
+ }
+
+}
diff --git a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/BlockUninstall.java b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/BlockUninstall.java
new file mode 100644
index 0000000..a74583e
--- /dev/null
+++ b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/BlockUninstall.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.harrier.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
+import static com.android.bedstead.nene.devicepolicy.CommonDevicePolicy.DELEGATION_BLOCK_UNINSTALL;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+/**
+ * Policy for setting uninstall blocked.
+ *
+ * <p>This is used by methods such as
+ * {@code DevicePolicyManager#setUninstallBlocked(ComponentName, String, boolean)} and
+ * {@code DevicePolicyManager#isUninstallBlocked(ComponentName)}.
+ */
+@EnterprisePolicy(
+ dpc = APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER
+ | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED,
+ delegatedScopes = DELEGATION_BLOCK_UNINSTALL
+)
+public final class BlockUninstall {
+}
diff --git a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/EnableSystemApp.java b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/EnableSystemApp.java
new file mode 100644
index 0000000..3d0943c
--- /dev/null
+++ b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/EnableSystemApp.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.harrier.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
+import static com.android.bedstead.nene.devicepolicy.CommonDevicePolicy.DELEGATION_ENABLE_SYSTEM_APP;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+/**
+ * Policy for enabling system apps.
+ *
+ * <p>See {@code DevicePolicyManager#enableSystemApp(ComponentName, String)} for more
+ * detail.
+ */
+@EnterprisePolicy(dpc = {
+ APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER
+ | APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED},
+ delegatedScopes = DELEGATION_ENABLE_SYSTEM_APP)
+public final class EnableSystemApp {
+}
diff --git a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/HideApplication.java b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/HideApplication.java
new file mode 100644
index 0000000..5abed15
--- /dev/null
+++ b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/HideApplication.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.harrier.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
+import static com.android.bedstead.nene.devicepolicy.CommonDevicePolicy.DELEGATION_PACKAGE_ACCESS;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+/**
+ * Policy for hiding applications.
+ * See {@code DevicePolicyManager#setApplicationHidden(ComponentName, String, boolean)} for more
+ * detail.
+ */
+@EnterprisePolicy(dpc = {
+ APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER
+ | APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED},
+ delegatedScopes = DELEGATION_PACKAGE_ACCESS)
+public final class HideApplication {
+}
diff --git a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/NetworkLogging.java b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/NetworkLogging.java
new file mode 100644
index 0000000..986c4dd
--- /dev/null
+++ b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/NetworkLogging.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.harrier.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER_PROFILE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
+import static com.android.bedstead.nene.devicepolicy.CommonDevicePolicy.DELEGATION_NETWORK_LOGGING;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+/**
+ * Policy for retrieving network logs.
+ */
+@EnterprisePolicy(dpc = {APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER_PROFILE
+ | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED},
+ delegatedScopes = DELEGATION_NETWORK_LOGGING)
+public final class NetworkLogging {
+ // There's a special case where for DO if there is an unaffiliated
+ // user on the device a SecurityException will be thrown. For now we deal with this by
+ // not having any PolicyDoesNotApplyTest
+}
diff --git a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/SuspendPackage.java b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/SuspendPackage.java
new file mode 100644
index 0000000..324848f
--- /dev/null
+++ b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/SuspendPackage.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.harrier.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
+import static com.android.bedstead.nene.devicepolicy.CommonDevicePolicy.DELEGATION_PACKAGE_ACCESS;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+/**
+ * Policy for hiding applications.
+ * See {@code DevicePolicyManager#setPackagesSuspended(ComponentName, String[], boolean)} for more
+ * detail.
+ */
+@EnterprisePolicy(dpc = {
+ APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER
+ | APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED},
+ delegatedScopes = DELEGATION_PACKAGE_ACCESS)
+public final class SuspendPackage {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
index 73fc2ac..f45db02 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
@@ -38,12 +38,10 @@
import android.content.Context;
import android.content.Intent;
import android.os.Build;
-import android.os.Bundle;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider;
-import androidx.test.platform.app.InstrumentationRegistry;
import com.android.bedstead.harrier.annotations.AfterClass;
import com.android.bedstead.harrier.annotations.BeforeClass;
@@ -95,6 +93,7 @@
import com.android.bedstead.nene.devicepolicy.ProfileOwner;
import com.android.bedstead.nene.exceptions.AdbException;
import com.android.bedstead.nene.exceptions.NeneException;
+import com.android.bedstead.nene.logging.Logger;
import com.android.bedstead.nene.packages.Package;
import com.android.bedstead.nene.permissions.PermissionContext;
import com.android.bedstead.nene.permissions.PermissionContextImpl;
@@ -139,6 +138,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@@ -185,7 +185,7 @@
private String mSkipTestsReason;
private String mFailTestsReason;
// The minimum version supported by tests, defaults to current version
- private final int mMinSdkVersion;
+ private int mMinSdkVersion;
private int mMinSdkVersionCurrentTest;
private @Nullable String mPermissionsInstrumentationPackage;
private final Set<String> mPermissionsInstrumentationPackagePermissions = new HashSet<>();
@@ -200,711 +200,753 @@
// We are allowed 11 minutes before the entire test run fails
private static final Duration MAX_TEST_DURATION = Duration.ofMinutes(10);
private final ExecutorService mTestExecutor = Executors.newSingleThreadExecutor();
+ private Thread mTestThread;
+
+ private final Logger mLogger = Logger.forInstance(this);
public DeviceState() {
- Bundle arguments = InstrumentationRegistry.getArguments();
- mSkipTestTeardown = Boolean.parseBoolean(
- arguments.getString(SKIP_TEST_TEARDOWN_KEY, "false"));
- mSkipClassTeardown = Boolean.parseBoolean(
- arguments.getString(SKIP_CLASS_TEARDOWN_KEY, "false"));
- mSkipTestsReason = arguments.getString(SKIP_TESTS_REASON_KEY, "");
- mSkipTests = !mSkipTestsReason.isEmpty();
- mMinSdkVersion = arguments.getInt(MIN_SDK_VERSION_KEY, SDK_INT);
- mPermissionsInstrumentationPackage =
- arguments.getString(PERMISSIONS_INSTRUMENTATION_PACKAGE_KEY);
- if (mPermissionsInstrumentationPackage != null) {
- mPermissionsInstrumentationPackagePermissions.addAll(
- TestApis.packages().find(mPermissionsInstrumentationPackage)
- .requestedPermissions());
- }
+ mLogger.constructor(() -> {
+ Future<Thread> testThreadFuture = mTestExecutor.submit(Thread::currentThread);
+
+ mSkipTestTeardown = TestApis.instrumentation().arguments().getBoolean(SKIP_TEST_TEARDOWN_KEY, false);
+ mSkipClassTeardown = TestApis.instrumentation().arguments().getBoolean(SKIP_CLASS_TEARDOWN_KEY, false);
+
+ mSkipTestsReason = TestApis.instrumentation().arguments().getString(SKIP_TESTS_REASON_KEY, "");
+ mSkipTests = !mSkipTestsReason.isEmpty();
+ mMinSdkVersion = TestApis.instrumentation().arguments().getInt(MIN_SDK_VERSION_KEY, SDK_INT);
+ mPermissionsInstrumentationPackage = TestApis.instrumentation().arguments().getString(PERMISSIONS_INSTRUMENTATION_PACKAGE_KEY);
+ if (mPermissionsInstrumentationPackage != null) {
+ mPermissionsInstrumentationPackagePermissions.addAll(
+ TestApis.packages().find(mPermissionsInstrumentationPackage)
+ .requestedPermissions());
+ }
+
+ try {
+ mTestThread = testThreadFuture.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new AssertionError(
+ "Error setting up DeviceState. Interrupted getting test thread", e);
+ }
+ });
}
@Override
void setSkipTestTeardown(boolean skipTestTeardown) {
- mSkipTestTeardown = skipTestTeardown;
+ mLogger.method("setSkipTestTeardown", skipTestTeardown, () -> {
+ mSkipTestTeardown = skipTestTeardown;
+ });
}
@Override
void setUsingBedsteadJUnit4(boolean usingBedsteadJUnit4) {
- mUsingBedsteadJUnit4 = usingBedsteadJUnit4;
+ mLogger.method("setUsingBedsteadJUnit4", usingBedsteadJUnit4, () -> {
+ mUsingBedsteadJUnit4 = usingBedsteadJUnit4;
+ });
}
- @Override public Statement apply(final Statement base,
- final Description description) {
-
- if (description.isTest()) {
- return applyTest(base, description);
- } else if (description.isSuite()) {
- return applySuite(base, description);
- }
- throw new IllegalStateException("Unknown description type: " + description);
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return mLogger.method("apply", base, description, () -> {
+ if (description.isTest()) {
+ return applyTest(base, description);
+ } else if (description.isSuite()) {
+ return applySuite(base, description);
+ }
+ throw new IllegalStateException("Unknown description type: " + description);
+ });
}
private Statement applyTest(Statement base, Description description) {
- return new Statement() {
- @Override public void evaluate() throws Throwable {
+ return mLogger.method("applyTest", base, description, () -> {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ Future<Throwable> future = mTestExecutor.submit(() -> {
+ try {
+ executeTest(base, description);
+ return null;
+ } catch (Throwable e) {
+ return e;
+ }
+ });
- Future<Throwable> future = mTestExecutor.submit(() -> {
try {
- executeTest(base, description);
- return null;
- } catch (Throwable e) {
- return e;
- }
- });
+ Throwable t = future.get(MAX_TEST_DURATION.getSeconds(), TimeUnit.SECONDS);
+ if (t != null) {
+ if (t instanceof AssertionError
+ || t instanceof AssumptionViolatedException) {
+ throw t;
+ } else {
+ // We wrap the failure in an AssertionError so it doesn't crash
+ throw new AssertionError("Exception while executing test", t);
+ }
+ }
+ } catch (TimeoutException e) {
+ StackTraceElement[] stack = mTestThread.getStackTrace();
+ future.cancel(true);
- try {
- Throwable t = future.get(MAX_TEST_DURATION.getSeconds(), TimeUnit.SECONDS);
- if (t != null) {
- throw t;
+ AssertionError assertionError = new AssertionError(
+ "Timed out executing test " + description.getDisplayName());
+ assertionError.setStackTrace(stack);
+ throw assertionError;
}
- } catch (TimeoutException e) {
- future.cancel(true);
-
- throw new AssertionError(
- "Timed out executing test " + description.getDisplayName());
}
- }};
+ };
+ });
}
private void executeTest(Statement base, Description description) throws Throwable {
- PermissionContextImpl permissionContext = null;
+ mLogger.method(Throwable.class, "executeTest", base, description, () -> {
+ PermissionContextImpl permissionContext = null;
- try {
- Log.d(LOG_TAG, "Preparing state for test " + description.getMethodName());
+ String testName = description.getMethodName();
- testApps().snapshot();
- Tags.clearTags();
- Tags.addTag(Tags.USES_DEVICESTATE);
- assumeFalse(mSkipTestsReason, mSkipTests);
- assertFalse(mFailTestsReason, mFailTests);
+ try {
+ Log.d(LOG_TAG, "Preparing state for test " + testName);
- // Ensure that tests only see events from the current test
- EventLogs.resetLogs();
+ testApps().snapshot();
+ Tags.clearTags();
+ Tags.addTag(Tags.USES_DEVICESTATE);
+ assumeFalse(mSkipTestsReason, mSkipTests);
+ assertFalse(mFailTestsReason, mFailTests);
- mMinSdkVersionCurrentTest = mMinSdkVersion;
- List<Annotation> annotations = getAnnotations(description);
- permissionContext = applyAnnotations(annotations, /* isTest= */ true);
+ // Ensure that tests only see events from the current test
+ EventLogs.resetLogs();
- Log.d(LOG_TAG,
- "Finished preparing state for test " + description.getMethodName());
+ mMinSdkVersionCurrentTest = mMinSdkVersion;
+ List<Annotation> annotations = getAnnotations(description);
+ permissionContext = applyAnnotations(annotations, /* isTest= */ true);
- base.evaluate();
- } finally {
- Log.d(LOG_TAG,
- "Tearing down state for test " + description.getMethodName());
+ Log.d(LOG_TAG, "Finished preparing state for test " + testName);
- if (permissionContext != null) {
- permissionContext.close();
+ base.evaluate();
+ } finally {
+ Log.d(LOG_TAG, "Tearing down state for test " + testName);
+
+ if (permissionContext != null) {
+ permissionContext.close();
+ }
+
+ teardownNonShareableState();
+ if (!mSkipTestTeardown) {
+ teardownShareableState();
+ }
+ Log.d(LOG_TAG, "Finished tearing down state for test " + testName);
}
-
- teardownNonShareableState();
- if (!mSkipTestTeardown) {
- teardownShareableState();
- }
- Log.d(LOG_TAG,
- "Finished tearing down state for test "
- + description.getMethodName());
- }
+ });
}
private PermissionContextImpl applyAnnotations(List<Annotation> annotations, boolean isTest)
throws Throwable {
- PermissionContextImpl permissionContext = null;
- Log.i(LOG_TAG, "Applying annotations: " + annotations);
- for (Annotation annotation : annotations) {
- Log.i(LOG_TAG, "Applying annotation " + annotation);
+ return mLogger.method(Throwable.class, "applyAnnotations", annotations, isTest, () -> {
+ PermissionContextImpl permissionContext = null;
+ Log.i(LOG_TAG, "Applying annotations: " + annotations);
+ for (Annotation annotation : annotations) {
+ Log.i(LOG_TAG, "Applying annotation " + annotation);
- Class<? extends Annotation> annotationType = annotation.annotationType();
+ Class<? extends Annotation> annotationType = annotation.annotationType();
- EnsureHasNoProfileAnnotation ensureHasNoProfileAnnotation =
- annotationType.getAnnotation(EnsureHasNoProfileAnnotation.class);
- if (ensureHasNoProfileAnnotation != null) {
- UserType userType = (UserType) annotation.annotationType()
- .getMethod(FOR_USER).invoke(annotation);
- ensureHasNoProfile(ensureHasNoProfileAnnotation.value(), userType);
- continue;
- }
+ EnsureHasNoProfileAnnotation ensureHasNoProfileAnnotation =
+ annotationType.getAnnotation(EnsureHasNoProfileAnnotation.class);
+ if (ensureHasNoProfileAnnotation != null) {
+ UserType userType = (UserType) annotation.annotationType()
+ .getMethod(FOR_USER).invoke(annotation);
+ ensureHasNoProfile(ensureHasNoProfileAnnotation.value(), userType);
+ continue;
+ }
- EnsureHasProfileAnnotation ensureHasProfileAnnotation =
- annotationType.getAnnotation(EnsureHasProfileAnnotation.class);
- if (ensureHasProfileAnnotation != null) {
- UserType forUser = (UserType) annotation.annotationType()
- .getMethod(FOR_USER).invoke(annotation);
- OptionalBoolean installInstrumentedApp = (OptionalBoolean)
- annotation.annotationType()
- .getMethod(INSTALL_INSTRUMENTED_APP).invoke(annotation);
-
- boolean dpcIsPrimary = false;
- boolean useParentInstance = false;
- if (ensureHasProfileAnnotation.hasProfileOwner()) {
- dpcIsPrimary = (boolean)
+ EnsureHasProfileAnnotation ensureHasProfileAnnotation =
+ annotationType.getAnnotation(EnsureHasProfileAnnotation.class);
+ if (ensureHasProfileAnnotation != null) {
+ UserType forUser = (UserType) annotation.annotationType()
+ .getMethod(FOR_USER).invoke(annotation);
+ OptionalBoolean installInstrumentedApp = (OptionalBoolean)
annotation.annotationType()
- .getMethod(DPC_IS_PRIMARY).invoke(annotation);
+ .getMethod(INSTALL_INSTRUMENTED_APP).invoke(annotation);
- if (dpcIsPrimary) {
- useParentInstance = (boolean)
+ boolean dpcIsPrimary = false;
+ boolean useParentInstance = false;
+ if (ensureHasProfileAnnotation.hasProfileOwner()) {
+ dpcIsPrimary = (boolean)
annotation.annotationType()
- .getMethod(USE_PARENT_INSTANCE_OF_DPC).invoke(annotation);
+ .getMethod(DPC_IS_PRIMARY).invoke(annotation);
+ if (dpcIsPrimary) {
+ useParentInstance = (boolean)
+ annotation.annotationType()
+ .getMethod(USE_PARENT_INSTANCE_OF_DPC).invoke(
+ annotation);
+
+ }
}
- }
- OptionalBoolean switchedToParentUser = (OptionalBoolean)
- annotation.annotationType()
- .getMethod(SWITCHED_TO_PARENT_USER).invoke(annotation);
-
- ensureHasProfile(
- ensureHasProfileAnnotation.value(), installInstrumentedApp,
- forUser, ensureHasProfileAnnotation.hasProfileOwner(),
- dpcIsPrimary, useParentInstance, switchedToParentUser);
- continue;
- }
-
- EnsureHasNoUserAnnotation ensureHasNoUserAnnotation =
- annotationType.getAnnotation(EnsureHasNoUserAnnotation.class);
- if (ensureHasNoUserAnnotation != null) {
- ensureHasNoUser(ensureHasNoUserAnnotation.value());
- continue;
- }
-
- EnsureHasUserAnnotation ensureHasUserAnnotation =
- annotationType.getAnnotation(EnsureHasUserAnnotation.class);
- if (ensureHasUserAnnotation != null) {
- OptionalBoolean installInstrumentedApp = (OptionalBoolean)
- annotation.annotationType()
- .getMethod(INSTALL_INSTRUMENTED_APP).invoke(annotation);
- OptionalBoolean switchedToUser = (OptionalBoolean)
- annotation.annotationType()
- .getMethod(SWITCHED_TO_USER).invoke(annotation);
- ensureHasUser(
- ensureHasUserAnnotation.value(), installInstrumentedApp, switchedToUser);
- continue;
- }
-
- RequireRunOnUserAnnotation requireRunOnUserAnnotation =
- annotationType.getAnnotation(RequireRunOnUserAnnotation.class);
- if (requireRunOnUserAnnotation != null) {
- OptionalBoolean switchedToUser = (OptionalBoolean)
- annotation.annotationType()
- .getMethod(SWITCHED_TO_USER).invoke(annotation);
- requireRunOnUser(requireRunOnUserAnnotation.value(), switchedToUser);
- continue;
- }
-
- if (annotation instanceof TestTag) {
- TestTag testTagAnnotation = (TestTag) annotation;
- Tags.addTag(testTagAnnotation.value());
- }
-
- RequireRunOnProfileAnnotation requireRunOnProfileAnnotation =
- annotationType.getAnnotation(RequireRunOnProfileAnnotation.class);
- if (requireRunOnProfileAnnotation != null) {
- OptionalBoolean installInstrumentedAppInParent = (OptionalBoolean)
- annotation.annotationType()
- .getMethod("installInstrumentedAppInParent")
- .invoke(annotation);
-
- OptionalBoolean switchedToParentUser = (OptionalBoolean)
- annotation.annotationType()
- .getMethod(SWITCHED_TO_PARENT_USER).invoke(annotation);
-
-
- boolean dpcIsPrimary = false;
- Set<String> affiliationIds = null;
- if (requireRunOnProfileAnnotation.hasProfileOwner()) {
- dpcIsPrimary = (boolean)
+ OptionalBoolean switchedToParentUser = (OptionalBoolean)
annotation.annotationType()
- .getMethod(DPC_IS_PRIMARY).invoke(annotation);
- affiliationIds = new HashSet<>(Arrays.asList((String[])
+ .getMethod(SWITCHED_TO_PARENT_USER).invoke(annotation);
+
+ ensureHasProfile(
+ ensureHasProfileAnnotation.value(), installInstrumentedApp,
+ forUser, ensureHasProfileAnnotation.hasProfileOwner(),
+ dpcIsPrimary, useParentInstance, switchedToParentUser);
+ continue;
+ }
+
+ EnsureHasNoUserAnnotation ensureHasNoUserAnnotation =
+ annotationType.getAnnotation(EnsureHasNoUserAnnotation.class);
+ if (ensureHasNoUserAnnotation != null) {
+ ensureHasNoUser(ensureHasNoUserAnnotation.value());
+ continue;
+ }
+
+ EnsureHasUserAnnotation ensureHasUserAnnotation =
+ annotationType.getAnnotation(EnsureHasUserAnnotation.class);
+ if (ensureHasUserAnnotation != null) {
+ OptionalBoolean installInstrumentedApp = (OptionalBoolean)
annotation.annotationType()
- .getMethod(AFFILIATION_IDS).invoke(annotation)));
- }
-
- requireRunOnProfile(requireRunOnProfileAnnotation.value(),
- installInstrumentedAppInParent,
- requireRunOnProfileAnnotation.hasProfileOwner(),
- /* useParentInstance= */ false,
- dpcIsPrimary, switchedToParentUser, affiliationIds);
- continue;
- }
-
- if (annotation instanceof EnsureTestAppInstalled) {
- EnsureTestAppInstalled ensureTestAppInstalledAnnotation =
- (EnsureTestAppInstalled) annotation;
- ensureTestAppInstalled(
- ensureTestAppInstalledAnnotation.key(),
- ensureTestAppInstalledAnnotation.packageName(),
- ensureTestAppInstalledAnnotation.onUser(),
- ensureTestAppInstalledAnnotation.isPrimary()
- );
- continue;
- }
-
- if (annotation instanceof EnsureTestAppHasPermission) {
- EnsureTestAppHasPermission ensureTestAppHasPermissionAnnotation =
- (EnsureTestAppHasPermission) annotation;
- ensureTestAppHasPermission(
- ensureTestAppHasPermissionAnnotation.testAppKey(),
- ensureTestAppHasPermissionAnnotation.value(),
- ensureTestAppHasPermissionAnnotation.minVersion(),
- ensureTestAppHasPermissionAnnotation.maxVersion()
- );
- continue;
- }
-
- if (annotation instanceof EnsureTestAppHasAppOp) {
- EnsureTestAppHasAppOp ensureTestAppHasAppOpAnnotation =
- (EnsureTestAppHasAppOp) annotation;
- ensureTestAppHasAppOp(
- ensureTestAppHasAppOpAnnotation.testAppKey(),
- ensureTestAppHasAppOpAnnotation.value(),
- ensureTestAppHasAppOpAnnotation.minVersion(),
- ensureTestAppHasAppOpAnnotation.maxVersion()
- );
- continue;
- }
-
- if (annotation instanceof EnsureHasDelegate) {
- EnsureHasDelegate ensureHasDelegateAnnotation =
- (EnsureHasDelegate) annotation;
- ensureHasDelegate(
- ensureHasDelegateAnnotation.admin(),
- Arrays.asList(ensureHasDelegateAnnotation.scopes()),
- ensureHasDelegateAnnotation.isPrimary());
- continue;
- }
-
-
- if (annotation instanceof EnsureHasDeviceOwner) {
- EnsureHasDeviceOwner ensureHasDeviceOwnerAnnotation =
- (EnsureHasDeviceOwner) annotation;
- ensureHasDeviceOwner(ensureHasDeviceOwnerAnnotation.failureMode(),
- ensureHasDeviceOwnerAnnotation.isPrimary(),
- new HashSet<>(
- Arrays.asList(ensureHasDeviceOwnerAnnotation.affiliationIds())));
- continue;
- }
-
- if (annotation instanceof EnsureHasNoDelegate) {
- EnsureHasNoDelegate ensureHasNoDelegateAnnotation =
- (EnsureHasNoDelegate) annotation;
- ensureHasNoDelegate(ensureHasNoDelegateAnnotation.admin());
- continue;
- }
-
- if (annotation instanceof EnsureHasNoDeviceOwner) {
- ensureHasNoDeviceOwner();
- continue;
- }
-
- if (annotation instanceof RequireFeature) {
- RequireFeature requireFeatureAnnotation = (RequireFeature) annotation;
- requireFeature(
- requireFeatureAnnotation.value(),
- requireFeatureAnnotation.failureMode());
- continue;
- }
-
- if (annotation instanceof RequireDoesNotHaveFeature) {
- RequireDoesNotHaveFeature requireDoesNotHaveFeatureAnnotation =
- (RequireDoesNotHaveFeature) annotation;
- requireDoesNotHaveFeature(
- requireDoesNotHaveFeatureAnnotation.value(),
- requireDoesNotHaveFeatureAnnotation.failureMode());
- continue;
- }
-
- if (annotation instanceof EnsureHasProfileOwner) {
- EnsureHasProfileOwner ensureHasProfileOwnerAnnotation =
- (EnsureHasProfileOwner) annotation;
- ensureHasProfileOwner(ensureHasProfileOwnerAnnotation.onUser(),
- ensureHasProfileOwnerAnnotation.isPrimary(),
- ensureHasProfileOwnerAnnotation.useParentInstance(),
- new HashSet<>(Arrays.asList(ensureHasProfileOwnerAnnotation.affiliationIds())));
- continue;
- }
-
- if (annotationType.equals(EnsureHasNoProfileOwner.class)) {
- EnsureHasNoProfileOwner ensureHasNoProfileOwnerAnnotation =
- (EnsureHasNoProfileOwner) annotation;
- ensureHasNoProfileOwner(ensureHasNoProfileOwnerAnnotation.onUser());
- continue;
- }
-
- if (annotation instanceof RequireUserSupported) {
- RequireUserSupported requireUserSupportedAnnotation =
- (RequireUserSupported) annotation;
- requireUserSupported(
- requireUserSupportedAnnotation.value(),
- requireUserSupportedAnnotation.failureMode());
- continue;
- }
-
- if (annotation instanceof RequireLowRamDevice) {
- RequireLowRamDevice requireLowRamDeviceAnnotation =
- (RequireLowRamDevice) annotation;
- requireLowRamDevice(requireLowRamDeviceAnnotation.reason(),
- requireLowRamDeviceAnnotation.failureMode());
- continue;
- }
-
- if (annotation instanceof RequireNotLowRamDevice) {
- RequireNotLowRamDevice requireNotLowRamDeviceAnnotation =
- (RequireNotLowRamDevice) annotation;
- requireNotLowRamDevice(requireNotLowRamDeviceAnnotation.reason(),
- requireNotLowRamDeviceAnnotation.failureMode());
- continue;
- }
-
- if (annotation instanceof RequireTargetSdkVersion) {
- RequireTargetSdkVersion requireTargetSdkVersionAnnotation =
- (RequireTargetSdkVersion) annotation;
-
- requireTargetSdkVersion(
- requireTargetSdkVersionAnnotation.min(),
- requireTargetSdkVersionAnnotation.max(),
- requireTargetSdkVersionAnnotation.failureMode());
-
- continue;
- }
-
- if (annotation instanceof RequireSdkVersion) {
- RequireSdkVersion requireSdkVersionAnnotation =
- (RequireSdkVersion) annotation;
-
- if (requireSdkVersionAnnotation.reason().isEmpty()) {
- requireSdkVersion(
- requireSdkVersionAnnotation.min(),
- requireSdkVersionAnnotation.max(),
- requireSdkVersionAnnotation.failureMode());
- } else {
- requireSdkVersion(
- requireSdkVersionAnnotation.min(),
- requireSdkVersionAnnotation.max(),
- requireSdkVersionAnnotation.failureMode(),
- requireSdkVersionAnnotation.reason());
- }
-
- continue;
- }
-
- if (annotation instanceof RequirePackageInstalled) {
- RequirePackageInstalled requirePackageInstalledAnnotation =
- (RequirePackageInstalled) annotation;
- requirePackageInstalled(
- requirePackageInstalledAnnotation.value(),
- requirePackageInstalledAnnotation.onUser(),
- requirePackageInstalledAnnotation.failureMode());
- continue;
- }
-
- if (annotation instanceof RequirePackageNotInstalled) {
- RequirePackageNotInstalled requirePackageNotInstalledAnnotation =
- (RequirePackageNotInstalled) annotation;
- requirePackageNotInstalled(
- requirePackageNotInstalledAnnotation.value(),
- requirePackageNotInstalledAnnotation.onUser(),
- requirePackageNotInstalledAnnotation.failureMode()
- );
- continue;
- }
-
- if (annotation instanceof EnsurePackageNotInstalled) {
- EnsurePackageNotInstalled ensurePackageNotInstalledAnnotation =
- (EnsurePackageNotInstalled) annotation;
- ensurePackageNotInstalled(
- ensurePackageNotInstalledAnnotation.value(),
- ensurePackageNotInstalledAnnotation.onUser()
- );
- continue;
- }
-
- if (annotation instanceof RequireNotHeadlessSystemUserMode) {
- requireNotHeadlessSystemUserMode();
- continue;
- }
-
- if (annotation instanceof RequireHeadlessSystemUserMode) {
- requireHeadlessSystemUserMode();
- continue;
- }
-
- if (annotation instanceof EnsureCanGetPermission) {
- EnsureCanGetPermission ensureCanGetPermissionAnnotation =
- (EnsureCanGetPermission) annotation;
-
- if (!meetsSdkVersionRequirements(
- ensureCanGetPermissionAnnotation.minVersion(),
- ensureCanGetPermissionAnnotation.maxVersion())) {
- Log.d(LOG_TAG,
- "Version " + SDK_INT + " does not need to get permissions "
- + Arrays.toString(ensureCanGetPermissionAnnotation.value()));
+ .getMethod(INSTALL_INSTRUMENTED_APP).invoke(annotation);
+ OptionalBoolean switchedToUser = (OptionalBoolean)
+ annotation.annotationType()
+ .getMethod(SWITCHED_TO_USER).invoke(annotation);
+ ensureHasUser(
+ ensureHasUserAnnotation.value(), installInstrumentedApp,
+ switchedToUser);
continue;
}
- for (String permission : ensureCanGetPermissionAnnotation.value()) {
- ensureCanGetPermission(permission);
- }
- continue;
- }
-
- if (annotation instanceof EnsureHasAppOp) {
- EnsureHasAppOp ensureHasAppOpAnnotation = (EnsureHasAppOp) annotation;
-
- if (!meetsSdkVersionRequirements(
- ensureHasAppOpAnnotation.minVersion(),
- ensureHasAppOpAnnotation.maxVersion())) {
- Log.d(LOG_TAG,
- "Version " + SDK_INT + " does not need to get appOp "
- + ensureHasAppOpAnnotation.value());
+ RequireRunOnUserAnnotation requireRunOnUserAnnotation =
+ annotationType.getAnnotation(RequireRunOnUserAnnotation.class);
+ if (requireRunOnUserAnnotation != null) {
+ OptionalBoolean switchedToUser = (OptionalBoolean)
+ annotation.annotationType()
+ .getMethod(SWITCHED_TO_USER).invoke(annotation);
+ requireRunOnUser(requireRunOnUserAnnotation.value(), switchedToUser);
continue;
}
- try {
- if (permissionContext == null) {
- permissionContext = TestApis.permissions().withAppOp(
- ensureHasAppOpAnnotation.value());
- } else {
- permissionContext = permissionContext.withAppOp(
- ensureHasAppOpAnnotation.value());
- }
- } catch (NeneException e) {
- failOrSkip("Error getting appOp: " + e,
- ensureHasAppOpAnnotation.failureMode());
+ if (annotation instanceof TestTag) {
+ TestTag testTagAnnotation = (TestTag) annotation;
+ Tags.addTag(testTagAnnotation.value());
}
- continue;
- }
- if (annotation instanceof EnsureDoesNotHaveAppOp) {
- EnsureDoesNotHaveAppOp ensureDoesNotHaveAppOpAnnotation =
- (EnsureDoesNotHaveAppOp) annotation;
+ RequireRunOnProfileAnnotation requireRunOnProfileAnnotation =
+ annotationType.getAnnotation(RequireRunOnProfileAnnotation.class);
+ if (requireRunOnProfileAnnotation != null) {
+ OptionalBoolean installInstrumentedAppInParent = (OptionalBoolean)
+ annotation.annotationType()
+ .getMethod("installInstrumentedAppInParent")
+ .invoke(annotation);
- try {
- if (permissionContext == null) {
- permissionContext = TestApis.permissions().withoutAppOp(
- ensureDoesNotHaveAppOpAnnotation.value());
- } else {
- permissionContext = permissionContext.withoutAppOp(
- ensureDoesNotHaveAppOpAnnotation.value());
+ OptionalBoolean switchedToParentUser = (OptionalBoolean)
+ annotation.annotationType()
+ .getMethod(SWITCHED_TO_PARENT_USER).invoke(annotation);
+
+
+ boolean dpcIsPrimary = false;
+ Set<String> affiliationIds = null;
+ if (requireRunOnProfileAnnotation.hasProfileOwner()) {
+ dpcIsPrimary = (boolean)
+ annotation.annotationType()
+ .getMethod(DPC_IS_PRIMARY).invoke(annotation);
+ affiliationIds = new HashSet<>(Arrays.asList((String[])
+ annotation.annotationType()
+ .getMethod(AFFILIATION_IDS).invoke(annotation)));
}
- } catch (NeneException e) {
- failOrSkip("Error denying appOp: " + e,
- ensureDoesNotHaveAppOpAnnotation.failureMode());
- }
- continue;
- }
- if (annotation instanceof EnsureHasPermission) {
- EnsureHasPermission ensureHasPermissionAnnotation =
- (EnsureHasPermission) annotation;
-
- if (!meetsSdkVersionRequirements(
- ensureHasPermissionAnnotation.minVersion(),
- ensureHasPermissionAnnotation.maxVersion())) {
- Log.d(LOG_TAG,
- "Version " + SDK_INT + " does not need to get permission "
- + Arrays.toString(ensureHasPermissionAnnotation.value()));
+ requireRunOnProfile(requireRunOnProfileAnnotation.value(),
+ installInstrumentedAppInParent,
+ requireRunOnProfileAnnotation.hasProfileOwner(),
+ dpcIsPrimary, /* useParentInstance= */ false,
+ switchedToParentUser, affiliationIds);
continue;
}
- for (String permission : ensureHasPermissionAnnotation.value()) {
- ensureCanGetPermission(permission);
+ if (annotation instanceof EnsureTestAppInstalled) {
+ EnsureTestAppInstalled ensureTestAppInstalledAnnotation =
+ (EnsureTestAppInstalled) annotation;
+ ensureTestAppInstalled(
+ ensureTestAppInstalledAnnotation.key(),
+ ensureTestAppInstalledAnnotation.packageName(),
+ ensureTestAppInstalledAnnotation.onUser(),
+ ensureTestAppInstalledAnnotation.isPrimary()
+ );
+ continue;
}
- try {
- if (permissionContext == null) {
- permissionContext = TestApis.permissions().withPermission(
- ensureHasPermissionAnnotation.value());
+ if (annotation instanceof EnsureTestAppHasPermission) {
+ EnsureTestAppHasPermission ensureTestAppHasPermissionAnnotation =
+ (EnsureTestAppHasPermission) annotation;
+ ensureTestAppHasPermission(
+ ensureTestAppHasPermissionAnnotation.testAppKey(),
+ ensureTestAppHasPermissionAnnotation.value(),
+ ensureTestAppHasPermissionAnnotation.minVersion(),
+ ensureTestAppHasPermissionAnnotation.maxVersion()
+ );
+ continue;
+ }
+
+ if (annotation instanceof EnsureTestAppHasAppOp) {
+ EnsureTestAppHasAppOp ensureTestAppHasAppOpAnnotation =
+ (EnsureTestAppHasAppOp) annotation;
+ ensureTestAppHasAppOp(
+ ensureTestAppHasAppOpAnnotation.testAppKey(),
+ ensureTestAppHasAppOpAnnotation.value(),
+ ensureTestAppHasAppOpAnnotation.minVersion(),
+ ensureTestAppHasAppOpAnnotation.maxVersion()
+ );
+ continue;
+ }
+
+ if (annotation instanceof EnsureHasDelegate) {
+ EnsureHasDelegate ensureHasDelegateAnnotation =
+ (EnsureHasDelegate) annotation;
+ ensureHasDelegate(
+ ensureHasDelegateAnnotation.admin(),
+ Arrays.asList(ensureHasDelegateAnnotation.scopes()),
+ ensureHasDelegateAnnotation.isPrimary());
+ continue;
+ }
+
+
+ if (annotation instanceof EnsureHasDeviceOwner) {
+ EnsureHasDeviceOwner ensureHasDeviceOwnerAnnotation =
+ (EnsureHasDeviceOwner) annotation;
+ ensureHasDeviceOwner(ensureHasDeviceOwnerAnnotation.failureMode(),
+ ensureHasDeviceOwnerAnnotation.isPrimary(),
+ new HashSet<>(
+ Arrays.asList(
+ ensureHasDeviceOwnerAnnotation.affiliationIds())));
+ continue;
+ }
+
+ if (annotation instanceof EnsureHasNoDelegate) {
+ EnsureHasNoDelegate ensureHasNoDelegateAnnotation =
+ (EnsureHasNoDelegate) annotation;
+ ensureHasNoDelegate(ensureHasNoDelegateAnnotation.admin());
+ continue;
+ }
+
+ if (annotation instanceof EnsureHasNoDeviceOwner) {
+ ensureHasNoDeviceOwner();
+ continue;
+ }
+
+ if (annotation instanceof RequireFeature) {
+ RequireFeature requireFeatureAnnotation = (RequireFeature) annotation;
+ requireFeature(
+ requireFeatureAnnotation.value(),
+ requireFeatureAnnotation.failureMode());
+ continue;
+ }
+
+ if (annotation instanceof RequireDoesNotHaveFeature) {
+ RequireDoesNotHaveFeature requireDoesNotHaveFeatureAnnotation =
+ (RequireDoesNotHaveFeature) annotation;
+ requireDoesNotHaveFeature(
+ requireDoesNotHaveFeatureAnnotation.value(),
+ requireDoesNotHaveFeatureAnnotation.failureMode());
+ continue;
+ }
+
+ if (annotation instanceof EnsureHasProfileOwner) {
+ EnsureHasProfileOwner ensureHasProfileOwnerAnnotation =
+ (EnsureHasProfileOwner) annotation;
+ ensureHasProfileOwner(ensureHasProfileOwnerAnnotation.onUser(),
+ ensureHasProfileOwnerAnnotation.isPrimary(),
+ ensureHasProfileOwnerAnnotation.useParentInstance(),
+ new HashSet<>(Arrays.asList(
+ ensureHasProfileOwnerAnnotation.affiliationIds())));
+ continue;
+ }
+
+ if (annotationType.equals(EnsureHasNoProfileOwner.class)) {
+ EnsureHasNoProfileOwner ensureHasNoProfileOwnerAnnotation =
+ (EnsureHasNoProfileOwner) annotation;
+ ensureHasNoProfileOwner(ensureHasNoProfileOwnerAnnotation.onUser());
+ continue;
+ }
+
+ if (annotation instanceof RequireUserSupported) {
+ RequireUserSupported requireUserSupportedAnnotation =
+ (RequireUserSupported) annotation;
+ requireUserSupported(
+ requireUserSupportedAnnotation.value(),
+ requireUserSupportedAnnotation.failureMode());
+ continue;
+ }
+
+ if (annotation instanceof RequireLowRamDevice) {
+ RequireLowRamDevice requireLowRamDeviceAnnotation =
+ (RequireLowRamDevice) annotation;
+ requireLowRamDevice(requireLowRamDeviceAnnotation.reason(),
+ requireLowRamDeviceAnnotation.failureMode());
+ continue;
+ }
+
+ if (annotation instanceof RequireNotLowRamDevice) {
+ RequireNotLowRamDevice requireNotLowRamDeviceAnnotation =
+ (RequireNotLowRamDevice) annotation;
+ requireNotLowRamDevice(requireNotLowRamDeviceAnnotation.reason(),
+ requireNotLowRamDeviceAnnotation.failureMode());
+ continue;
+ }
+
+ if (annotation instanceof RequireTargetSdkVersion) {
+ RequireTargetSdkVersion requireTargetSdkVersionAnnotation =
+ (RequireTargetSdkVersion) annotation;
+
+ requireTargetSdkVersion(
+ requireTargetSdkVersionAnnotation.min(),
+ requireTargetSdkVersionAnnotation.max(),
+ requireTargetSdkVersionAnnotation.failureMode());
+
+ continue;
+ }
+
+ if (annotation instanceof RequireSdkVersion) {
+ RequireSdkVersion requireSdkVersionAnnotation =
+ (RequireSdkVersion) annotation;
+
+ if (requireSdkVersionAnnotation.reason().isEmpty()) {
+ requireSdkVersion(
+ requireSdkVersionAnnotation.min(),
+ requireSdkVersionAnnotation.max(),
+ requireSdkVersionAnnotation.failureMode());
} else {
- permissionContext = permissionContext.withPermission(
- ensureHasPermissionAnnotation.value());
+ requireSdkVersion(
+ requireSdkVersionAnnotation.min(),
+ requireSdkVersionAnnotation.max(),
+ requireSdkVersionAnnotation.failureMode(),
+ requireSdkVersionAnnotation.reason());
}
- } catch (NeneException e) {
- failOrSkip("Error getting permission: " + e,
- ensureHasPermissionAnnotation.failureMode());
+
+ continue;
}
- continue;
- }
- if (annotation instanceof EnsureDoesNotHavePermission) {
- EnsureDoesNotHavePermission ensureDoesNotHavePermission =
- (EnsureDoesNotHavePermission) annotation;
+ if (annotation instanceof RequirePackageInstalled) {
+ RequirePackageInstalled requirePackageInstalledAnnotation =
+ (RequirePackageInstalled) annotation;
+ requirePackageInstalled(
+ requirePackageInstalledAnnotation.value(),
+ requirePackageInstalledAnnotation.onUser(),
+ requirePackageInstalledAnnotation.failureMode());
+ continue;
+ }
- try {
- if (permissionContext == null) {
- permissionContext = TestApis.permissions().withoutPermission(
- ensureDoesNotHavePermission.value());
- } else {
- permissionContext = permissionContext.withoutPermission(
- ensureDoesNotHavePermission.value());
+ if (annotation instanceof RequirePackageNotInstalled) {
+ RequirePackageNotInstalled requirePackageNotInstalledAnnotation =
+ (RequirePackageNotInstalled) annotation;
+ requirePackageNotInstalled(
+ requirePackageNotInstalledAnnotation.value(),
+ requirePackageNotInstalledAnnotation.onUser(),
+ requirePackageNotInstalledAnnotation.failureMode()
+ );
+ continue;
+ }
+
+ if (annotation instanceof EnsurePackageNotInstalled) {
+ EnsurePackageNotInstalled ensurePackageNotInstalledAnnotation =
+ (EnsurePackageNotInstalled) annotation;
+ ensurePackageNotInstalled(
+ ensurePackageNotInstalledAnnotation.value(),
+ ensurePackageNotInstalledAnnotation.onUser()
+ );
+ continue;
+ }
+
+ if (annotation instanceof RequireNotHeadlessSystemUserMode) {
+ requireNotHeadlessSystemUserMode();
+ continue;
+ }
+
+ if (annotation instanceof RequireHeadlessSystemUserMode) {
+ requireHeadlessSystemUserMode();
+ continue;
+ }
+
+ if (annotation instanceof EnsureCanGetPermission) {
+ EnsureCanGetPermission ensureCanGetPermissionAnnotation =
+ (EnsureCanGetPermission) annotation;
+
+ if (!meetsSdkVersionRequirements(
+ ensureCanGetPermissionAnnotation.minVersion(),
+ ensureCanGetPermissionAnnotation.maxVersion())) {
+ Log.d(LOG_TAG,
+ "Version " + SDK_INT + " does not need to get permissions "
+ + Arrays.toString(
+ ensureCanGetPermissionAnnotation.value()));
+ continue;
}
- } catch (NeneException e) {
- failOrSkip("Error denying permission: " + e,
- ensureDoesNotHavePermission.failureMode());
+
+ for (String permission : ensureCanGetPermissionAnnotation.value()) {
+ ensureCanGetPermission(permission);
+ }
+ continue;
}
- continue;
+
+ if (annotation instanceof EnsureHasAppOp) {
+ EnsureHasAppOp ensureHasAppOpAnnotation = (EnsureHasAppOp) annotation;
+
+ if (!meetsSdkVersionRequirements(
+ ensureHasAppOpAnnotation.minVersion(),
+ ensureHasAppOpAnnotation.maxVersion())) {
+ Log.d(LOG_TAG,
+ "Version " + SDK_INT + " does not need to get appOp "
+ + ensureHasAppOpAnnotation.value());
+ continue;
+ }
+
+ try {
+ if (permissionContext == null) {
+ permissionContext = TestApis.permissions().withAppOp(
+ ensureHasAppOpAnnotation.value());
+ } else {
+ permissionContext = permissionContext.withAppOp(
+ ensureHasAppOpAnnotation.value());
+ }
+ } catch (NeneException e) {
+ failOrSkip("Error getting appOp: " + e,
+ ensureHasAppOpAnnotation.failureMode());
+ }
+ continue;
+ }
+
+ if (annotation instanceof EnsureDoesNotHaveAppOp) {
+ EnsureDoesNotHaveAppOp ensureDoesNotHaveAppOpAnnotation =
+ (EnsureDoesNotHaveAppOp) annotation;
+
+ try {
+ if (permissionContext == null) {
+ permissionContext = TestApis.permissions().withoutAppOp(
+ ensureDoesNotHaveAppOpAnnotation.value());
+ } else {
+ permissionContext = permissionContext.withoutAppOp(
+ ensureDoesNotHaveAppOpAnnotation.value());
+ }
+ } catch (NeneException e) {
+ failOrSkip("Error denying appOp: " + e,
+ ensureDoesNotHaveAppOpAnnotation.failureMode());
+ }
+ continue;
+ }
+
+ if (annotation instanceof EnsureHasPermission) {
+ EnsureHasPermission ensureHasPermissionAnnotation =
+ (EnsureHasPermission) annotation;
+
+ if (!meetsSdkVersionRequirements(
+ ensureHasPermissionAnnotation.minVersion(),
+ ensureHasPermissionAnnotation.maxVersion())) {
+ Log.d(LOG_TAG,
+ "Version " + SDK_INT + " does not need to get permission "
+ + Arrays.toString(ensureHasPermissionAnnotation.value()));
+ continue;
+ }
+
+ for (String permission : ensureHasPermissionAnnotation.value()) {
+ ensureCanGetPermission(permission);
+ }
+
+ try {
+ if (permissionContext == null) {
+ permissionContext = TestApis.permissions().withPermission(
+ ensureHasPermissionAnnotation.value());
+ } else {
+ permissionContext = permissionContext.withPermission(
+ ensureHasPermissionAnnotation.value());
+ }
+ } catch (NeneException e) {
+ failOrSkip("Error getting permission: " + e,
+ ensureHasPermissionAnnotation.failureMode());
+ }
+ continue;
+ }
+
+ if (annotation instanceof EnsureDoesNotHavePermission) {
+ EnsureDoesNotHavePermission ensureDoesNotHavePermission =
+ (EnsureDoesNotHavePermission) annotation;
+
+ try {
+ if (permissionContext == null) {
+ permissionContext = TestApis.permissions().withoutPermission(
+ ensureDoesNotHavePermission.value());
+ } else {
+ permissionContext = permissionContext.withoutPermission(
+ ensureDoesNotHavePermission.value());
+ }
+ } catch (NeneException e) {
+ failOrSkip("Error denying permission: " + e,
+ ensureDoesNotHavePermission.failureMode());
+ }
+ continue;
+ }
+
+ if (annotation instanceof EnsureScreenIsOn) {
+ ensureScreenIsOn();
+ continue;
+ }
+
+ if (annotation instanceof EnsurePasswordSet) {
+ EnsurePasswordSet ensurePasswordSetAnnotation =
+ (EnsurePasswordSet) annotation;
+ ensurePasswordSet(
+ ensurePasswordSetAnnotation.forUser(),
+ ensurePasswordSetAnnotation.password());
+ continue;
+ }
+
+ if (annotation instanceof EnsurePasswordNotSet) {
+ EnsurePasswordNotSet ensurePasswordNotSetAnnotation =
+ (EnsurePasswordNotSet) annotation;
+ ensurePasswordNotSet(ensurePasswordNotSetAnnotation.forUser());
+ continue;
+ }
+
+ if (annotation instanceof OtherUser) {
+ OtherUser otherUserAnnotation = (OtherUser) annotation;
+ mOtherUserType = otherUserAnnotation.value();
+ continue;
+ }
+
+ if (annotation instanceof EnsureBluetoothEnabled) {
+ ensureBluetoothEnabled();
+ continue;
+ }
+
+ if (annotation instanceof EnsureBluetoothDisabled) {
+ ensureBluetoothDisabled();
+ continue;
+ }
}
- if (annotation instanceof EnsureScreenIsOn) {
- ensureScreenIsOn();
- continue;
+ requireSdkVersion(/* min= */ mMinSdkVersionCurrentTest,
+ /* max= */ Integer.MAX_VALUE, FailureMode.SKIP);
+
+ if (isTest && mPermissionsInstrumentationPackage != null
+ && !mHasRequirePermissionInstrumentation) {
+ requireNoPermissionsInstrumentation("No reason to use instrumentation");
}
- if (annotation instanceof EnsurePasswordSet) {
- EnsurePasswordSet ensurePasswordSetAnnotation =
- (EnsurePasswordSet) annotation;
- ensurePasswordSet(
- ensurePasswordSetAnnotation.forUser(),
- ensurePasswordSetAnnotation.password());
- continue;
- }
-
- if (annotation instanceof EnsurePasswordNotSet) {
- EnsurePasswordNotSet ensurePasswordNotSetAnnotation =
- (EnsurePasswordNotSet) annotation;
- ensurePasswordNotSet(ensurePasswordNotSetAnnotation.forUser());
- continue;
- }
-
- if (annotation instanceof OtherUser) {
- OtherUser otherUserAnnotation = (OtherUser) annotation;
- mOtherUserType = otherUserAnnotation.value();
- continue;
- }
-
- if (annotation instanceof EnsureBluetoothEnabled) {
- ensureBluetoothEnabled();
- continue;
- }
-
- if (annotation instanceof EnsureBluetoothDisabled) {
- ensureBluetoothDisabled();
- continue;
- }
- }
-
- requireSdkVersion(/* min= */ mMinSdkVersionCurrentTest,
- /* max= */ Integer.MAX_VALUE, FailureMode.SKIP);
-
- if (isTest && mPermissionsInstrumentationPackage != null
- && !mHasRequirePermissionInstrumentation) {
- requireNoPermissionsInstrumentation("No reason to use instrumentation");
- }
-
- return permissionContext;
+ return permissionContext;
+ });
}
private List<Annotation> getAnnotations(Description description) {
- if (mUsingBedsteadJUnit4 && description.isTest()) {
- // The annotations are already exploded for tests
- return new ArrayList<>(description.getAnnotations());
- }
+ return mLogger.method("getAnnotations", description, () -> {
+ if (mUsingBedsteadJUnit4 && description.isTest()) {
+ // The annotations are already exploded for tests
+ return new ArrayList<>(description.getAnnotations());
+ }
- // Otherwise we should build a new collection by recursively gathering annotations
- // if we find any which don't work without the runner we should error and fail the test
- List<Annotation> annotations = new ArrayList<>();
+ // Otherwise we should build a new collection by recursively gathering annotations
+ // if we find any which don't work without the runner we should error and fail the test
+ List<Annotation> annotations = new ArrayList<>();
- if (description.isTest()) {
- annotations =
- new ArrayList<>(Arrays.asList(description.getTestClass().getAnnotations()));
- }
+ if (description.isTest()) {
+ annotations =
+ new ArrayList<>(Arrays.asList(description.getTestClass().getAnnotations()));
+ }
- annotations.addAll(description.getAnnotations());
+ annotations.addAll(description.getAnnotations());
- checkAnnotations(annotations);
+ checkAnnotations(annotations);
- BedsteadJUnit4.resolveRecursiveAnnotations(annotations,
- /* parameterizedAnnotation= */ null);
+ BedsteadJUnit4.resolveRecursiveAnnotations(annotations,
+ /* parameterizedAnnotation= */ null);
- checkAnnotations(annotations);
+ checkAnnotations(annotations);
- return annotations;
+ return annotations;
+ });
}
private void checkAnnotations(Collection<Annotation> annotations) {
- for (Annotation annotation : annotations) {
- if (annotation.annotationType().getAnnotation(RequiresBedsteadJUnit4.class) != null
- || annotation.annotationType().getAnnotation(
- ParameterizedAnnotation.class) != null) {
- throw new AssertionFailedError("Test is annotated "
- + annotation.annotationType().getSimpleName()
- + " which requires using the BedsteadJUnit4 test runner");
+ mLogger.method("checkAnnotations", annotations, () -> {
+ for (Annotation annotation : annotations) {
+ if (annotation.annotationType().getAnnotation(RequiresBedsteadJUnit4.class) != null
+ || annotation.annotationType().getAnnotation(
+ ParameterizedAnnotation.class) != null) {
+ throw new AssertionFailedError("Test is annotated "
+ + annotation.annotationType().getSimpleName()
+ + " which requires using the BedsteadJUnit4 test runner");
+ }
}
- }
+ });
}
private Statement applySuite(Statement base, Description description) {
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- checkValidAnnotations(description);
+ return mLogger.method("applySuite", base, description, () -> {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ checkValidAnnotations(description);
- TestClass testClass = new TestClass(description.getTestClass());
+ TestClass testClass = new TestClass(description.getTestClass());
- PermissionContextImpl permissionContext = null;
+ PermissionContextImpl permissionContext = null;
- if (mSkipTests || mFailTests) {
- Log.d(LOG_TAG, "Skipping suite setup and teardown due to skipTests: "
- + mSkipTests + ", failTests: " + mFailTests);
- base.evaluate();
- return;
- }
+ if (mSkipTests || mFailTests) {
+ Log.d(LOG_TAG, "Skipping suite setup and teardown due to skipTests: "
+ + mSkipTests + ", failTests: " + mFailTests);
+ base.evaluate();
+ return;
+ }
- Log.d(LOG_TAG, "Preparing state for suite " + description.getClassName());
+ Log.d(LOG_TAG, "Preparing state for suite " + description.getClassName());
- Tags.clearTags();
- Tags.addTag(Tags.USES_DEVICESTATE);
- if (TestApis.packages().instrumented().isInstantApp()) {
- Tags.addTag(Tags.INSTANT_APP);
- }
-
- try {
- TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_FALSE);
+ Tags.clearTags();
+ Tags.addTag(Tags.USES_DEVICESTATE);
+ if (TestApis.packages().instrumented().isInstantApp()) {
+ Tags.addTag(Tags.INSTANT_APP);
+ }
try {
- List<Annotation> annotations =
- new ArrayList<>(getAnnotations(description));
- permissionContext = applyAnnotations(annotations, /* isTest= */ false);
- } catch (AssumptionViolatedException e) {
- Log.i(LOG_TAG, "Assumption failed during class setup", e);
- mSkipTests = true;
- mSkipTestsReason = e.getMessage();
- } catch (AssertionError e) {
- Log.i(LOG_TAG, "Assertion failed during class setup", e);
- mFailTests = true;
- mFailTestsReason = e.getMessage();
+ TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_FALSE);
+
+ try {
+ List<Annotation> annotations =
+ new ArrayList<>(getAnnotations(description));
+ permissionContext = applyAnnotations(annotations, /* isTest= */ false);
+ } catch (AssumptionViolatedException e) {
+ Log.i(LOG_TAG, "Assumption failed during class setup", e);
+ mSkipTests = true;
+ mSkipTestsReason = e.getMessage();
+ } catch (AssertionError e) {
+ Log.i(LOG_TAG, "Assertion failed during class setup", e);
+ mFailTests = true;
+ mFailTestsReason = e.getMessage();
+ }
+
+ Log.d(LOG_TAG,
+ "Finished preparing state for suite "
+ + description.getClassName());
+
+ if (!mSkipTests && !mFailTests) {
+ // Tests may be skipped during the class setup
+ runAnnotatedMethods(testClass, BeforeClass.class);
+ }
+
+ base.evaluate();
+ } finally {
+ runAnnotatedMethods(testClass, AfterClass.class);
+
+ if (permissionContext != null) {
+ permissionContext.close();
+ }
+
+ if (!mSkipClassTeardown) {
+ teardownShareableState();
+ }
+
+ TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_DEFAULT);
}
-
- Log.d(LOG_TAG,
- "Finished preparing state for suite "
- + description.getClassName());
-
- if (!mSkipTests && !mFailTests) {
- // Tests may be skipped during the class setup
- runAnnotatedMethods(testClass, BeforeClass.class);
- }
-
- base.evaluate();
- } finally {
- runAnnotatedMethods(testClass, AfterClass.class);
-
- if (permissionContext != null) {
- permissionContext.close();
- }
-
- if (!mSkipClassTeardown) {
- teardownShareableState();
- }
-
- TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_DEFAULT);
}
- }
- };
+ };
+ });
}
private static final Map<Class<? extends Annotation>, Class<? extends Annotation>>
BANNED_ANNOTATIONS_TO_REPLACEMENTS = getBannedAnnotationsToReplacements();
+
private static Map<
Class<? extends Annotation>,
Class<? extends Annotation>> getBannedAnnotationsToReplacements() {
@@ -917,206 +959,243 @@
}
private void checkValidAnnotations(Description classDescription) {
- for (Method method : classDescription.getTestClass().getMethods()) {
- for (Map.Entry<
- Class<? extends Annotation>,
- Class<? extends Annotation>> bannedAnnotation
- : BANNED_ANNOTATIONS_TO_REPLACEMENTS.entrySet()) {
- if (method.isAnnotationPresent(bannedAnnotation.getKey())) {
- throw new IllegalStateException("Do not use "
- + bannedAnnotation.getKey().getCanonicalName()
- + " when using DeviceState, replace with "
- + bannedAnnotation.getValue().getCanonicalName());
+ mLogger.method("checkValidAnnotations", classDescription, () -> {
+ for (Method method : classDescription.getTestClass().getMethods()) {
+ for (Map.Entry<
+ Class<? extends Annotation>,
+ Class<? extends Annotation>> bannedAnnotation
+ : BANNED_ANNOTATIONS_TO_REPLACEMENTS.entrySet()) {
+ if (method.isAnnotationPresent(bannedAnnotation.getKey())) {
+ throw new IllegalStateException("Do not use "
+ + bannedAnnotation.getKey().getCanonicalName()
+ + " when using DeviceState, replace with "
+ + bannedAnnotation.getValue().getCanonicalName());
+ }
+ }
+
+ if (method.getAnnotation(BeforeClass.class) != null
+ || method.getAnnotation(AfterClass.class) != null) {
+ checkPublicStaticVoidNoArgs(method);
}
}
-
- if (method.getAnnotation(BeforeClass.class) != null
- || method.getAnnotation(AfterClass.class) != null) {
- checkPublicStaticVoidNoArgs(method);
- }
- }
+ });
}
private void checkPublicStaticVoidNoArgs(Method method) {
- if (method.getParameterTypes().length > 0) {
- throw new IllegalStateException(
- "Method " + method.getName() + " should have no parameters");
- }
- if (method.getReturnType() != Void.TYPE) {
- throw new IllegalStateException("Method " + method.getName() + "() should be void");
- }
- if (!Modifier.isStatic(method.getModifiers())) {
- throw new IllegalStateException("Method " + method.getName() + "() should be static");
- }
- if (!Modifier.isPublic(method.getModifiers())) {
- throw new IllegalStateException("Method " + method.getName() + "() should be public");
- }
+ mLogger.method("checkPublicStaticVoidNoArgs", method, () -> {
+ if (method.getParameterTypes().length > 0) {
+ throw new IllegalStateException(
+ "Method " + method.getName() + " should have no parameters");
+ }
+ if (method.getReturnType() != Void.TYPE) {
+ throw new IllegalStateException("Method " + method.getName() + "() should be void");
+ }
+ if (!Modifier.isStatic(method.getModifiers())) {
+ throw new IllegalStateException(
+ "Method " + method.getName() + "() should be static");
+ }
+ if (!Modifier.isPublic(method.getModifiers())) {
+ throw new IllegalStateException(
+ "Method " + method.getName() + "() should be public");
+ }
+ });
}
private void runAnnotatedMethods(
TestClass testClass, Class<? extends Annotation> annotation) throws Throwable {
-
- List<FrameworkMethod> methods = new ArrayList<>(testClass.getAnnotatedMethods(annotation));
- Collections.reverse(methods);
- for (FrameworkMethod method : methods) {
- try {
- method.invokeExplosively(testClass.getJavaClass());
- } catch (InvocationTargetException e) {
- throw e.getCause();
+ mLogger.method(Throwable.class, "runAnnotatedMethods", testClass, annotation, () -> {
+ List<FrameworkMethod> methods = new ArrayList<>(
+ testClass.getAnnotatedMethods(annotation));
+ Collections.reverse(methods);
+ for (FrameworkMethod method : methods) {
+ try {
+ method.invokeExplosively(testClass.getJavaClass());
+ } catch (InvocationTargetException e) {
+ throw e.getCause();
+ }
}
- }
+ });
}
private void requireRunOnUser(String[] userTypes, OptionalBoolean switchedToUser) {
- UserReference instrumentedUser = TestApis.users().instrumented();
+ mLogger.method("requireRunOnUser", userTypes, switchedToUser, () -> {
+ UserReference instrumentedUser = TestApis.users().instrumented();
- assumeTrue("This test only runs on users of type " + Arrays.toString(userTypes),
- Arrays.stream(userTypes).anyMatch(i -> i.equals(instrumentedUser.type().name())));
+ assumeTrue("This test only runs on users of type " + Arrays.toString(userTypes),
+ Arrays.stream(userTypes).anyMatch(
+ i -> i.equals(instrumentedUser.type().name())));
- mUsers.put(instrumentedUser.type(), instrumentedUser);
+ mUsers.put(instrumentedUser.type(), instrumentedUser);
- ensureSwitchedToUser(switchedToUser, instrumentedUser);
+ ensureSwitchedToUser(switchedToUser, instrumentedUser);
+ });
}
private void requireRunOnProfile(String userType,
OptionalBoolean installInstrumentedAppInParent,
boolean hasProfileOwner, boolean dpcIsPrimary, boolean useParentInstance,
OptionalBoolean switchedToParentUser, Set<String> affiliationIds) {
- UserReference instrumentedUser = TestApis.users().instrumented();
+ mLogger.method("requireRunOnProfile", userType, installInstrumentedAppInParent,
+ hasProfileOwner, dpcIsPrimary, useParentInstance, switchedToParentUser,
+ affiliationIds, () -> {
+ UserReference instrumentedUser = TestApis.users().instrumented();
- assumeTrue("This test only runs on users of type " + userType,
- instrumentedUser.type().name().equals(userType));
+ assumeTrue("This test only runs on users of type " + userType,
+ instrumentedUser.type().name().equals(userType));
- if (!mProfiles.containsKey(instrumentedUser.type())) {
- mProfiles.put(instrumentedUser.type(), new HashMap<>());
- }
+ if (!mProfiles.containsKey(instrumentedUser.type())) {
+ mProfiles.put(instrumentedUser.type(), new HashMap<>());
+ }
- mProfiles.get(instrumentedUser.type()).put(instrumentedUser.parent(), instrumentedUser);
+ mProfiles.get(instrumentedUser.type()).put(instrumentedUser.parent(),
+ instrumentedUser);
- if (installInstrumentedAppInParent.equals(OptionalBoolean.TRUE)) {
- TestApis.packages().find(sContext.getPackageName()).installExisting(
- instrumentedUser.parent());
- } else if (installInstrumentedAppInParent.equals(OptionalBoolean.FALSE)) {
- TestApis.packages().find(sContext.getPackageName()).uninstall(
- instrumentedUser.parent());
- }
+ if (installInstrumentedAppInParent.equals(OptionalBoolean.TRUE)) {
+ TestApis.packages().find(sContext.getPackageName()).installExisting(
+ instrumentedUser.parent());
+ } else if (installInstrumentedAppInParent.equals(OptionalBoolean.FALSE)) {
+ TestApis.packages().find(sContext.getPackageName()).uninstall(
+ instrumentedUser.parent());
+ }
- if (hasProfileOwner) {
- ensureHasProfileOwner(
- instrumentedUser, dpcIsPrimary, useParentInstance, affiliationIds);
- } else {
- ensureHasNoProfileOwner(instrumentedUser);
- }
+ if (hasProfileOwner) {
+ ensureHasProfileOwner(
+ instrumentedUser, dpcIsPrimary, useParentInstance, affiliationIds);
+ } else {
+ ensureHasNoProfileOwner(instrumentedUser);
+ }
- ensureSwitchedToUser(switchedToParentUser, instrumentedUser.parent());
+ ensureSwitchedToUser(switchedToParentUser, instrumentedUser.parent());
+ });
}
private void ensureSwitchedToUser(OptionalBoolean switchedtoUser, UserReference user) {
- if (switchedtoUser.equals(OptionalBoolean.TRUE)) {
- switchToUser(user);
- } else if (switchedtoUser.equals(OptionalBoolean.FALSE)) {
- switchFromUser(user);
- }
+ mLogger.method("ensureSwitchedToUser", switchedtoUser, user, () -> {
+ if (switchedtoUser.equals(OptionalBoolean.TRUE)) {
+ switchToUser(user);
+ } else if (switchedtoUser.equals(OptionalBoolean.FALSE)) {
+ switchFromUser(user);
+ }
+ });
}
private void requireFeature(String feature, FailureMode failureMode) {
- checkFailOrSkip("Device must have feature " + feature,
- TestApis.packages().features().contains(feature), failureMode);
+ mLogger.method("requireFeature", feature, failureMode, () -> {
+ checkFailOrSkip("Device must have feature " + feature,
+ TestApis.packages().features().contains(feature), failureMode);
+ });
}
private void requireDoesNotHaveFeature(String feature, FailureMode failureMode) {
- checkFailOrSkip("Device must not have feature " + feature,
- !TestApis.packages().features().contains(feature), failureMode);
+ mLogger.method("requireDoesNotHaveFeature", feature, failureMode, () -> {
+ checkFailOrSkip("Device must not have feature " + feature,
+ !TestApis.packages().features().contains(feature), failureMode);
+ });
}
private void requireNoPermissionsInstrumentation(String reason) {
- boolean instrumentingPermissions =
- TestApis.context()
- .instrumentedContext().getPackageName()
- .equals(mPermissionsInstrumentationPackage);
+ mLogger.method("requireNoPermissionsInstrumentation", reason, () -> {
+ boolean instrumentingPermissions =
+ TestApis.context()
+ .instrumentedContext().getPackageName()
+ .equals(mPermissionsInstrumentationPackage);
- checkFailOrSkip(
- "This test never runs using permissions instrumentation on this version"
- + " of Android: " + reason,
- !instrumentingPermissions,
- FailureMode.SKIP
- );
+ checkFailOrSkip(
+ "This test never runs using permissions instrumentation on this version"
+ + " of Android: " + reason,
+ !instrumentingPermissions,
+ FailureMode.SKIP
+ );
+ });
}
private void requirePermissionsInstrumentation(String reason) {
- mHasRequirePermissionInstrumentation = true;
- boolean instrumentingPermissions =
- TestApis.context()
- .instrumentedContext().getPackageName()
- .equals(mPermissionsInstrumentationPackage);
+ mLogger.method("requirePermissionsInstrumentation", reason, () -> {
+ mHasRequirePermissionInstrumentation = true;
+ boolean instrumentingPermissions =
+ TestApis.context()
+ .instrumentedContext().getPackageName()
+ .equals(mPermissionsInstrumentationPackage);
- checkFailOrSkip(
- "This test only runs when using permissions instrumentation on this"
- + " version of Android: " + reason,
- instrumentingPermissions,
- FailureMode.SKIP
- );
+ checkFailOrSkip(
+ "This test only runs when using permissions instrumentation on this"
+ + " version of Android: " + reason,
+ instrumentingPermissions,
+ FailureMode.SKIP
+ );
+ });
}
private void requireTargetSdkVersion(
int min, int max, FailureMode failureMode) {
+ mLogger.method("requireTargetSdkVersion", min, max, failureMode, () -> {
+ int targetSdkVersion = TestApis.packages().instrumented().targetSdkVersion();
- int targetSdkVersion = TestApis.packages().instrumented().targetSdkVersion();
-
- checkFailOrSkip(
- "TargetSdkVersion must be between " + min + " and " + max
- + " (inclusive) (version is " + targetSdkVersion + ")",
- min <= targetSdkVersion && max >= targetSdkVersion,
- failureMode
- );
+ checkFailOrSkip(
+ "TargetSdkVersion must be between " + min + " and " + max
+ + " (inclusive) (version is " + targetSdkVersion + ")",
+ min <= targetSdkVersion && max >= targetSdkVersion,
+ failureMode
+ );
+ });
}
private void requireSdkVersion(int min, int max, FailureMode failureMode) {
- requireSdkVersion(min, max, failureMode,
- "Sdk version must be between " + min + " and " + max + " (inclusive)");
+ mLogger.method("requireSdkVersion", min, max, failureMode, () -> {
+ requireSdkVersion(min, max, failureMode,
+ "Sdk version must be between " + min + " and " + max + " (inclusive)");
+ });
}
private void requireSdkVersion(
int min, int max, FailureMode failureMode, String failureMessage) {
- mMinSdkVersionCurrentTest = min;
- checkFailOrSkip(
- failureMessage + " (version is " + SDK_INT + ")",
- meetsSdkVersionRequirements(min, max),
- failureMode
- );
+ mLogger.method("requireSdkVersion", min, max, failureMode, failureMessage, () -> {
+ mMinSdkVersionCurrentTest = min;
+ checkFailOrSkip(
+ failureMessage + " (version is " + SDK_INT + ")",
+ meetsSdkVersionRequirements(min, max),
+ failureMode
+ );
+ });
}
private com.android.bedstead.nene.users.UserType requireUserSupported(
String userType, FailureMode failureMode) {
- com.android.bedstead.nene.users.UserType resolvedUserType =
- TestApis.users().supportedType(userType);
+ return mLogger.method("requireUserSupported", userType, failureMode, () -> {
+ com.android.bedstead.nene.users.UserType resolvedUserType =
+ TestApis.users().supportedType(userType);
- checkFailOrSkip(
- "Device must support user type " + userType
- + " only supports: " + TestApis.users().supportedTypes(),
- resolvedUserType != null, failureMode);
+ checkFailOrSkip(
+ "Device must support user type " + userType
+ + " only supports: " + TestApis.users().supportedTypes(),
+ resolvedUserType != null, failureMode);
- return resolvedUserType;
+ return resolvedUserType;
+ });
}
private void checkFailOrSkip(String message, boolean value, FailureMode failureMode) {
- if (failureMode.equals(FailureMode.FAIL)) {
- assertWithMessage(message).that(value).isTrue();
- } else if (failureMode.equals(FailureMode.SKIP)) {
- assumeTrue(message, value);
- } else {
- throw new IllegalStateException("Unknown failure mode: " + failureMode);
- }
+ mLogger.method("checkFailOrSkip", message, value, failureMode, () -> {
+ if (failureMode.equals(FailureMode.FAIL)) {
+ assertWithMessage(message).that(value).isTrue();
+ } else if (failureMode.equals(FailureMode.SKIP)) {
+ assumeTrue(message, value);
+ } else {
+ throw new IllegalStateException("Unknown failure mode: " + failureMode);
+ }
+ });
}
private void failOrSkip(String message, FailureMode failureMode) {
- if (failureMode.equals(FailureMode.FAIL)) {
- throw new AssertionError(message);
- } else if (failureMode.equals(FailureMode.SKIP)) {
- throw new AssumptionViolatedException(message);
- } else {
- throw new IllegalStateException("Unknown failure mode: " + failureMode);
- }
+ mLogger.method("failOrSkip", message, failureMode, () -> {
+ if (failureMode.equals(FailureMode.FAIL)) {
+ throw new AssertionError(message);
+ } else if (failureMode.equals(FailureMode.SKIP)) {
+ throw new AssumptionViolatedException(message);
+ } else {
+ throw new IllegalStateException("Unknown failure mode: " + failureMode);
+ }
+ });
}
private static final String LOG_TAG = "DeviceState";
@@ -1155,8 +1234,10 @@
* @throws IllegalStateException if there is no harrier-managed work profile
*/
public UserReference workProfile() {
- // Work profiles are currently only supported on the primary user
- return workProfile(/* forUser= */ UserType.PRIMARY_USER);
+ return mLogger.method("workProfile", () -> {
+ // Work profiles are currently only supported on the primary user
+ return workProfile(/* forUser= */ UserType.PRIMARY_USER);
+ });
}
/**
@@ -1168,7 +1249,9 @@
* @throws IllegalStateException if there is no harrier-managed work profile for the given user
*/
public UserReference workProfile(UserType forUser) {
- return workProfile(resolveUserTypeToUser(forUser));
+ return mLogger.method("workProfile", forUser, () -> {
+ return workProfile(resolveUserTypeToUser(forUser));
+ });
}
/**
@@ -1180,7 +1263,9 @@
* @throws IllegalStateException if there is no harrier-managed work profile for the given user
*/
public UserReference workProfile(UserReference forUser) {
- return profile(MANAGED_PROFILE_TYPE_NAME, forUser);
+ return mLogger.method("workProfile", forUser, () -> {
+ return profile(MANAGED_PROFILE_TYPE_NAME, forUser);
+ });
}
/**
@@ -1192,7 +1277,9 @@
* @throws IllegalStateException if there is no harrier-managed profile for the given user
*/
public UserReference profile(String profileType, UserType forUser) {
- return profile(profileType, resolveUserTypeToUser(forUser));
+ return mLogger.method("profile", profileType, forUser, () -> {
+ return profile(profileType, resolveUserTypeToUser(forUser));
+ });
}
/**
@@ -1207,7 +1294,9 @@
* @throws IllegalStateException if there is no harrier-managed profile
*/
public UserReference profile(String profileType) {
- return profile(profileType, /* forUser= */ UserType.INSTRUMENTED_USER);
+ return mLogger.method("profile", profileType, () -> {
+ return profile(profileType, /* forUser= */ UserType.INSTRUMENTED_USER);
+ });
}
/**
@@ -1219,15 +1308,17 @@
* @throws IllegalStateException if there is no harrier-managed profile for the given user
*/
public UserReference profile(String profileType, UserReference forUser) {
- com.android.bedstead.nene.users.UserType resolvedUserType =
- TestApis.users().supportedType(profileType);
+ return mLogger.method("profile", profileType, forUser, () -> {
+ com.android.bedstead.nene.users.UserType resolvedUserType =
+ TestApis.users().supportedType(profileType);
- if (resolvedUserType == null) {
- throw new IllegalStateException("Can not have a profile of type " + profileType
- + " as they are not supported on this device");
- }
+ if (resolvedUserType == null) {
+ throw new IllegalStateException("Can not have a profile of type " + profileType
+ + " as they are not supported on this device");
+ }
- return profile(resolvedUserType, forUser);
+ return profile(resolvedUserType, forUser);
+ });
}
/**
@@ -1240,26 +1331,29 @@
*/
public UserReference profile(
com.android.bedstead.nene.users.UserType userType, UserReference forUser) {
- if (userType == null || forUser == null) {
- throw new NullPointerException();
- }
-
- if (!mProfiles.containsKey(userType) || !mProfiles.get(userType).containsKey(forUser)) {
- UserReference parentUser = TestApis.users().instrumented().parent();
-
- if (parentUser != null) {
- if (mProfiles.containsKey(userType)
- && mProfiles.get(userType).containsKey(parentUser)) {
- return mProfiles.get(userType).get(parentUser);
- }
+ return mLogger.method("profile", userType, forUser, () -> {
+ if (userType == null || forUser == null) {
+ throw new NullPointerException();
}
- throw new IllegalStateException(
- "No harrier-managed profile of type " + userType + ". This method should only"
- + " be used when Harrier has been used to create the profile.");
- }
+ if (!mProfiles.containsKey(userType) || !mProfiles.get(userType).containsKey(forUser)) {
+ UserReference parentUser = TestApis.users().instrumented().parent();
- return mProfiles.get(userType).get(forUser);
+ if (parentUser != null) {
+ if (mProfiles.containsKey(userType)
+ && mProfiles.get(userType).containsKey(parentUser)) {
+ return mProfiles.get(userType).get(parentUser);
+ }
+ }
+
+ throw new IllegalStateException(
+ "No harrier-managed profile of type " + userType
+ + ". This method should only"
+ + " be used when Harrier has been used to create the profile.");
+ }
+
+ return mProfiles.get(userType).get(forUser);
+ });
}
/**
@@ -1271,7 +1365,8 @@
* @throws IllegalStateException if there is no harrier-managed tv profile
*/
public UserReference tvProfile() {
- return tvProfile(/* forUser= */ UserType.INSTRUMENTED_USER);
+ return mLogger.method("tvProfile", () ->
+ tvProfile(/* forUser= */ UserType.INSTRUMENTED_USER));
}
/**
@@ -1283,7 +1378,8 @@
* @throws IllegalStateException if there is no harrier-managed tv profile
*/
public UserReference tvProfile(UserType forUser) {
- return tvProfile(resolveUserTypeToUser(forUser));
+ return mLogger.method("tvProfile", forUser, () ->
+ tvProfile(resolveUserTypeToUser(forUser)));
}
/**
@@ -1295,16 +1391,18 @@
* @throws IllegalStateException if there is no harrier-managed tv profile
*/
public UserReference tvProfile(UserReference forUser) {
- return profile(TV_PROFILE_TYPE_NAME, forUser);
+ return mLogger.method("tvProfile", forUser, () ->
+ profile(TV_PROFILE_TYPE_NAME, forUser));
}
/**
* Get the user ID of the first human user on the device.
*/
public UserReference primaryUser() {
- return TestApis.users().all()
- .stream().filter(UserReference::isPrimary).findFirst()
- .orElseThrow(IllegalStateException::new);
+ return mLogger.method("primaryUser", () ->
+ TestApis.users().all()
+ .stream().filter(UserReference::isPrimary).findFirst()
+ .orElseThrow(IllegalStateException::new));
}
/**
@@ -1316,7 +1414,7 @@
* @throws IllegalStateException if there is no harrier-managed secondary user
*/
public UserReference secondaryUser() {
- return user(SECONDARY_USER_TYPE_NAME);
+ return mLogger.method("secondaryUser", () -> user(SECONDARY_USER_TYPE_NAME));
}
/**
@@ -1325,11 +1423,13 @@
* @throws IllegalStateException if there is no "other" user
*/
public UserReference otherUser() {
- if (mOtherUserType == null) {
- throw new IllegalStateException("No other user specified. Use @OtherUser");
- }
+ return mLogger.method("otherUser", () -> {
+ if (mOtherUserType == null) {
+ throw new IllegalStateException("No other user specified. Use @OtherUser");
+ }
- return resolveUserTypeToUser(mOtherUserType);
+ return resolveUserTypeToUser(mOtherUserType);
+ });
}
/**
@@ -1341,15 +1441,17 @@
* @throws IllegalStateException if there is no harrier-managed user of the correct type
*/
public UserReference user(String userType) {
- com.android.bedstead.nene.users.UserType resolvedUserType =
- TestApis.users().supportedType(userType);
+ return mLogger.method("user", userType, () -> {
+ com.android.bedstead.nene.users.UserType resolvedUserType =
+ TestApis.users().supportedType(userType);
- if (resolvedUserType == null) {
- throw new IllegalStateException("Can not have a user of type " + userType
- + " as they are not supported on this device");
- }
+ if (resolvedUserType == null) {
+ throw new IllegalStateException("Can not have a user of type " + userType
+ + " as they are not supported on this device");
+ }
- return user(resolvedUserType);
+ return user(resolvedUserType);
+ });
}
/**
@@ -1361,17 +1463,20 @@
* @throws IllegalStateException if there is no harrier-managed user of the correct type
*/
public UserReference user(com.android.bedstead.nene.users.UserType userType) {
- if (userType == null) {
- throw new NullPointerException();
- }
+ return mLogger.method("user", userType, () -> {
+ if (userType == null) {
+ throw new NullPointerException();
+ }
- if (!mUsers.containsKey(userType)) {
- throw new IllegalStateException(
- "No harrier-managed user of type " + userType + ". This method should only be"
- + "used when Harrier has been used to create the user.");
- }
+ if (!mUsers.containsKey(userType)) {
+ throw new IllegalStateException(
+ "No harrier-managed user of type " + userType
+ + ". This method should only be"
+ + "used when Harrier has been used to create the user.");
+ }
- return mUsers.get(userType);
+ return mUsers.get(userType);
+ });
}
private UserReference ensureHasProfile(
@@ -1382,134 +1487,152 @@
boolean profileOwnerIsPrimary,
boolean useParentInstance,
OptionalBoolean switchedToParentUser) {
- com.android.bedstead.nene.users.UserType resolvedUserType =
- requireUserSupported(profileType, FailureMode.SKIP);
+ return mLogger.method("ensureHasProfile", profileType, installInstrumentedApp,
+ forUser, hasProfileOwner, profileOwnerIsPrimary, useParentInstance,
+ switchedToParentUser, () -> {
+ com.android.bedstead.nene.users.UserType resolvedUserType =
+ requireUserSupported(profileType, FailureMode.SKIP);
- UserReference forUserReference = resolveUserTypeToUser(forUser);
+ UserReference forUserReference = resolveUserTypeToUser(forUser);
- UserReference profile =
- TestApis.users().findProfileOfType(resolvedUserType, forUserReference);
- if (profile == null) {
- if (profileType.equals(MANAGED_PROFILE_TYPE_NAME)) {
- // DO + work profile isn't a valid state
- ensureHasNoDeviceOwner();
- }
+ UserReference profile =
+ TestApis.users().findProfileOfType(resolvedUserType, forUserReference);
+ if (profile == null) {
+ if (profileType.equals(MANAGED_PROFILE_TYPE_NAME)) {
+ // DO + work profile isn't a valid state
+ ensureHasNoDeviceOwner();
+ }
- profile = createProfile(resolvedUserType, forUserReference);
- }
+ profile = createProfile(resolvedUserType, forUserReference);
+ }
- profile.start();
+ profile.start();
- if (installInstrumentedApp.equals(OptionalBoolean.TRUE)) {
- TestApis.packages().find(sContext.getPackageName()).installExisting(profile);
- } else if (installInstrumentedApp.equals(OptionalBoolean.FALSE)) {
- TestApis.packages().find(sContext.getPackageName()).uninstall(profile);
- }
+ if (installInstrumentedApp.equals(OptionalBoolean.TRUE)) {
+ TestApis.packages().find(sContext.getPackageName()).installExisting(
+ profile);
+ } else if (installInstrumentedApp.equals(OptionalBoolean.FALSE)) {
+ TestApis.packages().find(sContext.getPackageName()).uninstall(profile);
+ }
- if (!mProfiles.containsKey(resolvedUserType)) {
- mProfiles.put(resolvedUserType, new HashMap<>());
- }
+ if (!mProfiles.containsKey(resolvedUserType)) {
+ mProfiles.put(resolvedUserType, new HashMap<>());
+ }
- mProfiles.get(resolvedUserType).put(forUserReference, profile);
+ mProfiles.get(resolvedUserType).put(forUserReference, profile);
- if (hasProfileOwner) {
- ensureHasProfileOwner(
- profile, profileOwnerIsPrimary, useParentInstance, /* affiliationIds= */ null);
- }
+ if (hasProfileOwner) {
+ ensureHasProfileOwner(
+ profile, profileOwnerIsPrimary,
+ useParentInstance, /* affiliationIds= */
+ null);
+ }
- ensureSwitchedToUser(switchedToParentUser, forUserReference);
+ ensureSwitchedToUser(switchedToParentUser, forUserReference);
- return profile;
+ return profile;
+ });
}
private void ensureHasNoProfile(String profileType, UserType forUser) {
- UserReference forUserReference = resolveUserTypeToUser(forUser);
- com.android.bedstead.nene.users.UserType resolvedProfileType =
- TestApis.users().supportedType(profileType);
+ mLogger.method("ensureHasNoProfile", profileType, forUser, () -> {
+ UserReference forUserReference = resolveUserTypeToUser(forUser);
+ com.android.bedstead.nene.users.UserType resolvedProfileType =
+ TestApis.users().supportedType(profileType);
- if (resolvedProfileType == null) {
- // These profile types don't exist so there can't be any
- return;
- }
+ if (resolvedProfileType == null) {
+ // These profile types don't exist so there can't be any
+ return;
+ }
- UserReference profile =
- TestApis.users().findProfileOfType(
- resolvedProfileType,
- forUserReference);
- if (profile != null) {
- removeAndRecordUser(profile);
- }
+ UserReference profile =
+ TestApis.users().findProfileOfType(
+ resolvedProfileType,
+ forUserReference);
+ if (profile != null) {
+ removeAndRecordUser(profile);
+ }
+ });
}
private void ensureHasUser(
String userType, OptionalBoolean installInstrumentedApp,
OptionalBoolean switchedToUser) {
- com.android.bedstead.nene.users.UserType resolvedUserType =
- requireUserSupported(userType, FailureMode.SKIP);
+ mLogger.method("ensureHasUser", userType, installInstrumentedApp, switchedToUser, () -> {
+ com.android.bedstead.nene.users.UserType resolvedUserType =
+ requireUserSupported(userType, FailureMode.SKIP);
- Collection<UserReference> users = TestApis.users().findUsersOfType(resolvedUserType);
+ Collection<UserReference> users = TestApis.users().findUsersOfType(resolvedUserType);
- UserReference user = users.isEmpty() ? createUser(resolvedUserType)
- : users.iterator().next();
+ UserReference user = users.isEmpty() ? createUser(resolvedUserType)
+ : users.iterator().next();
- user.start();
+ user.start();
- if (installInstrumentedApp.equals(OptionalBoolean.TRUE)) {
- TestApis.packages().find(sContext.getPackageName()).installExisting(user);
- } else if (installInstrumentedApp.equals(OptionalBoolean.FALSE)) {
- TestApis.packages().find(sContext.getPackageName()).uninstall(user);
- }
+ if (installInstrumentedApp.equals(OptionalBoolean.TRUE)) {
+ TestApis.packages().find(sContext.getPackageName()).installExisting(user);
+ } else if (installInstrumentedApp.equals(OptionalBoolean.FALSE)) {
+ TestApis.packages().find(sContext.getPackageName()).uninstall(user);
+ }
- ensureSwitchedToUser(switchedToUser, user);
+ ensureSwitchedToUser(switchedToUser, user);
- mUsers.put(resolvedUserType, user);
+ mUsers.put(resolvedUserType, user);
+ });
}
/**
* Ensure that there is no user of the given type.
*/
private void ensureHasNoUser(String userType) {
- com.android.bedstead.nene.users.UserType resolvedUserType =
- TestApis.users().supportedType(userType);
+ mLogger.method("ensureHasNoUser", userType, () -> {
+ com.android.bedstead.nene.users.UserType resolvedUserType =
+ TestApis.users().supportedType(userType);
- if (resolvedUserType == null) {
- // These user types don't exist so there can't be any
- return;
- }
-
- for (UserReference secondaryUser : TestApis.users().findUsersOfType(resolvedUserType)) {
- if (secondaryUser.equals(TestApis.users().instrumented())) {
- throw new AssumptionViolatedException(
- "This test only runs on devices without a "
- + userType + " user. But the instrumented user is " + userType);
+ if (resolvedUserType == null) {
+ // These user types don't exist so there can't be any
+ return;
}
- removeAndRecordUser(secondaryUser);
- }
+
+ for (UserReference secondaryUser : TestApis.users().findUsersOfType(resolvedUserType)) {
+ if (secondaryUser.equals(TestApis.users().instrumented())) {
+ throw new AssumptionViolatedException(
+ "This test only runs on devices without a "
+ + userType + " user. But the instrumented user is " + userType);
+ }
+ removeAndRecordUser(secondaryUser);
+ }
+ });
}
private void removeAndRecordUser(UserReference userReference) {
- if (userReference == null) {
- return; // Nothing to remove
- }
+ mLogger.method("removeAndRecordUser", userReference, () -> {
+ if (userReference == null) {
+ return; // Nothing to remove
+ }
- switchFromUser(userReference);
+ switchFromUser(userReference);
- if (!mCreatedUsers.remove(userReference)) {
- mRemovedUsers.add(TestApis.users().createUser()
- .name(userReference.name())
- .type(userReference.type())
- .parent(userReference.parent()));
- }
+ if (!mCreatedUsers.remove(userReference)) {
+ mRemovedUsers.add(TestApis.users().createUser()
+ .name(userReference.name())
+ .type(userReference.type())
+ .parent(userReference.parent()));
+ }
- userReference.remove();
+ userReference.remove();
+ });
}
public void requireCanSupportAdditionalUser() {
- int maxUsers = getMaxNumberOfUsersSupported();
- int currentUsers = TestApis.users().all().size();
+ mLogger.method("requireCanSupportadditionalUser", () -> {
+ int maxUsers = getMaxNumberOfUsersSupported();
+ int currentUsers = TestApis.users().all().size();
- assumeTrue("The device does not have space for an additional user (" + currentUsers +
- " current users, " + maxUsers + " max users)", currentUsers + 1 <= maxUsers);
+ assumeTrue("The device does not have space for an additional user ("
+ + currentUsers + " current users, " + maxUsers + " max users)",
+ currentUsers + 1 <= maxUsers);
+ });
}
/**
@@ -1517,7 +1640,8 @@
* test has run.
*/
public BlockingBroadcastReceiver registerBroadcastReceiver(String action) {
- return registerBroadcastReceiver(action, /* checker= */ null);
+ return mLogger.method("registerBroadcastReceiver", action, () ->
+ registerBroadcastReceiver(action, /* checker= */ null));
}
/**
@@ -1526,12 +1650,14 @@
*/
public BlockingBroadcastReceiver registerBroadcastReceiver(
String action, Function<Intent, Boolean> checker) {
- BlockingBroadcastReceiver broadcastReceiver =
- new BlockingBroadcastReceiver(mContext, action, checker);
- broadcastReceiver.register();
- mRegisteredBroadcastReceivers.add(broadcastReceiver);
+ return mLogger.method("registerBroadcastReceiver", action, checker, () -> {
+ BlockingBroadcastReceiver broadcastReceiver =
+ new BlockingBroadcastReceiver(mContext, action, checker);
+ broadcastReceiver.register();
+ mRegisteredBroadcastReceivers.add(broadcastReceiver);
- return broadcastReceiver;
+ return broadcastReceiver;
+ });
}
/**
@@ -1540,7 +1666,8 @@
*/
public BlockingBroadcastReceiver registerBroadcastReceiverForUser(
UserReference user, String action) {
- return registerBroadcastReceiverForUser(user, action, /* checker= */ null);
+ return mLogger.method("registerBroadcastReceiverForUser", user, action,
+ () -> registerBroadcastReceiverForUser(user, action, /* checker= */ null));
}
/**
@@ -1549,16 +1676,18 @@
*/
public BlockingBroadcastReceiver registerBroadcastReceiverForUser(
UserReference user, String action, Function<Intent, Boolean> checker) {
- try (PermissionContext p =
- TestApis.permissions().withPermission(INTERACT_ACROSS_USERS_FULL)) {
- BlockingBroadcastReceiver broadcastReceiver =
- new BlockingBroadcastReceiver(
- TestApis.context().androidContextAsUser(user), action, checker);
- broadcastReceiver.register();
- mRegisteredBroadcastReceivers.add(broadcastReceiver);
+ return mLogger.method("registerBroadcastReceiverForUser", user, action, checker, () -> {
+ try (PermissionContext p =
+ TestApis.permissions().withPermission(INTERACT_ACROSS_USERS_FULL)) {
+ BlockingBroadcastReceiver broadcastReceiver =
+ new BlockingBroadcastReceiver(
+ TestApis.context().androidContextAsUser(user), action, checker);
+ broadcastReceiver.register();
+ mRegisteredBroadcastReceivers.add(broadcastReceiver);
- return broadcastReceiver;
- }
+ return broadcastReceiver;
+ }
+ });
}
/**
@@ -1566,7 +1695,8 @@
* test has run.
*/
public BlockingBroadcastReceiver registerBroadcastReceiverForAllUsers(String action) {
- return registerBroadcastReceiverForAllUsers(action, /* checker= */ null);
+ return mLogger.method("registerBroadcastReceiverForAllUsers", action,
+ () -> registerBroadcastReceiverForAllUsers(action, /* checker= */ null));
}
/**
@@ -1575,483 +1705,539 @@
*/
public BlockingBroadcastReceiver registerBroadcastReceiverForAllUsers(
String action, Function<Intent, Boolean> checker) {
+ return mLogger.method("registerBroadcastReceiverForAllUsers", () -> {
+ try (PermissionContext p =
+ TestApis.permissions().withPermission(INTERACT_ACROSS_USERS_FULL)) {
+ BlockingBroadcastReceiver broadcastReceiver =
+ new BlockingBroadcastReceiver(mContext, action, checker);
+ broadcastReceiver.registerForAllUsers();
- try (PermissionContext p =
- TestApis.permissions().withPermission(INTERACT_ACROSS_USERS_FULL)) {
- BlockingBroadcastReceiver broadcastReceiver =
- new BlockingBroadcastReceiver(mContext, action, checker);
- broadcastReceiver.registerForAllUsers();
+ mRegisteredBroadcastReceivers.add(broadcastReceiver);
- mRegisteredBroadcastReceivers.add(broadcastReceiver);
-
- return broadcastReceiver;
- }
+ return broadcastReceiver;
+ }
+ });
}
private UserReference resolveUserTypeToUser(UserType userType) {
- switch (userType) {
- case SYSTEM_USER:
- return TestApis.users().system();
- case INSTRUMENTED_USER:
- return TestApis.users().instrumented();
- case CURRENT_USER:
- return TestApis.users().current();
- case PRIMARY_USER:
- return primaryUser();
- case SECONDARY_USER:
- return secondaryUser();
- case WORK_PROFILE:
- return workProfile();
- case TV_PROFILE:
- return tvProfile();
- case DPC_USER:
- return dpc().user();
- case ANY:
- throw new IllegalStateException("ANY UserType can not be used here");
- default:
- throw new IllegalArgumentException("Unknown user type " + userType);
- }
+ return mLogger.method("resolveUserTypeToUser", userType, () -> {
+ switch (userType) {
+ case SYSTEM_USER:
+ return TestApis.users().system();
+ case INSTRUMENTED_USER:
+ return TestApis.users().instrumented();
+ case CURRENT_USER:
+ return TestApis.users().current();
+ case PRIMARY_USER:
+ return primaryUser();
+ case SECONDARY_USER:
+ return secondaryUser();
+ case WORK_PROFILE:
+ return workProfile();
+ case TV_PROFILE:
+ return tvProfile();
+ case DPC_USER:
+ return dpc().user();
+ case ANY:
+ throw new IllegalStateException("ANY UserType can not be used here");
+ default:
+ throw new IllegalArgumentException("Unknown user type " + userType);
+ }
+ });
}
private void teardownNonShareableState() {
- mProfiles.clear();
- mUsers.clear();
+ mLogger.method("teardownNonShareableState", () -> {
+ mProfiles.clear();
+ mUsers.clear();
- for (BlockingBroadcastReceiver broadcastReceiver : mRegisteredBroadcastReceivers) {
- broadcastReceiver.unregisterQuietly();
- }
- mRegisteredBroadcastReceivers.clear();
- mPrimaryPolicyManager = null;
- mOtherUserType = null;
- mTestApps.clear();
+ for (BlockingBroadcastReceiver broadcastReceiver : mRegisteredBroadcastReceivers) {
+ broadcastReceiver.unregisterQuietly();
+ }
+ mRegisteredBroadcastReceivers.clear();
+ mPrimaryPolicyManager = null;
+ mOtherUserType = null;
+ mTestApps.clear();
- mTestAppProvider.restore();
+ mTestAppProvider.restore();
+ });
}
private Set<TestAppInstance> mInstalledTestApps = new HashSet<>();
private Set<TestAppInstance> mUninstalledTestApps = new HashSet<>();
private void teardownShareableState() {
- if (mOriginalSwitchedUser != null) {
- if (!mOriginalSwitchedUser.exists()) {
- Log.d(LOG_TAG, "Could not switch back to original user "
- + mOriginalSwitchedUser
- + " as it does not exist. Switching to initial instead.");
- TestApis.users().initial().switchTo();
- } else {
- mOriginalSwitchedUser.switchTo();
- }
- mOriginalSwitchedUser = null;
- }
-
- if (mHasChangedDeviceOwner) {
- if (mOriginalDeviceOwner == null) {
- if (mDeviceOwner != null) {
- mDeviceOwner.remove();
+ mLogger.method("teardownShareableState", () -> {
+ if (mOriginalSwitchedUser != null) {
+ if (!mOriginalSwitchedUser.exists()) {
+ Log.d(LOG_TAG, "Could not switch back to original user "
+ + mOriginalSwitchedUser
+ + " as it does not exist. Switching to initial instead.");
+ TestApis.users().initial().switchTo();
+ } else {
+ mOriginalSwitchedUser.switchTo();
}
- } else if (!mOriginalDeviceOwner.equals(mDeviceOwner)) {
- if (mDeviceOwner != null) {
- mDeviceOwner.remove();
+ mOriginalSwitchedUser = null;
+ }
+
+ if (mHasChangedDeviceOwner) {
+ if (mOriginalDeviceOwner == null) {
+ if (mDeviceOwner != null) {
+ mDeviceOwner.remove();
+ }
+ } else if (!mOriginalDeviceOwner.equals(mDeviceOwner)) {
+ if (mDeviceOwner != null) {
+ mDeviceOwner.remove();
+ }
+ TestApis.devicePolicy().setDeviceOwner(
+ mOriginalDeviceOwner.componentName());
}
- TestApis.devicePolicy().setDeviceOwner(
- mOriginalDeviceOwner.componentName());
- }
- mHasChangedDeviceOwner = false;
- mOriginalDeviceOwner = null;
- }
-
- for (Map.Entry<UserReference, DevicePolicyController> originalProfileOwner :
- mChangedProfileOwners.entrySet()) {
-
- ProfileOwner currentProfileOwner =
- TestApis.devicePolicy().getProfileOwner(originalProfileOwner.getKey());
-
- if (Objects.equal(currentProfileOwner, originalProfileOwner.getValue())) {
- continue; // No need to restore
+ mHasChangedDeviceOwner = false;
+ mOriginalDeviceOwner = null;
}
- if (currentProfileOwner != null) {
- currentProfileOwner.remove();
+ for (Map.Entry<UserReference, DevicePolicyController> originalProfileOwner :
+ mChangedProfileOwners.entrySet()) {
+
+ ProfileOwner currentProfileOwner =
+ TestApis.devicePolicy().getProfileOwner(originalProfileOwner.getKey());
+
+ if (Objects.equal(currentProfileOwner, originalProfileOwner.getValue())) {
+ continue; // No need to restore
+ }
+
+ if (currentProfileOwner != null) {
+ currentProfileOwner.remove();
+ }
+
+ if (originalProfileOwner.getValue() != null) {
+ TestApis.devicePolicy().setProfileOwner(originalProfileOwner.getKey(),
+ originalProfileOwner.getValue().componentName());
+ }
+ }
+ mChangedProfileOwners.clear();
+
+ for (UserReference user : mUsersSetPasswords) {
+ if (mCreatedUsers.contains(user)) {
+ continue; // Will be removed anyway
+ }
+ user.clearPassword();
}
- if (originalProfileOwner.getValue() != null) {
- TestApis.devicePolicy().setProfileOwner(originalProfileOwner.getKey(),
- originalProfileOwner.getValue().componentName());
+ mUsersSetPasswords.clear();
+
+ for (UserReference user : mCreatedUsers) {
+ user.remove();
}
- }
- mChangedProfileOwners.clear();
- for (UserReference user : mUsersSetPasswords) {
- if (mCreatedUsers.contains(user)) {
- continue; // Will be removed anyway
+ mCreatedUsers.clear();
+
+ for (UserBuilder userBuilder : mRemovedUsers) {
+ userBuilder.create();
}
- user.clearPassword();
- }
- mUsersSetPasswords.clear();
+ mRemovedUsers.clear();
- for (UserReference user : mCreatedUsers) {
- user.remove();
- }
+ for (TestAppInstance installedTestApp : mInstalledTestApps) {
+ installedTestApp.uninstall();
+ }
+ mInstalledTestApps.clear();
- mCreatedUsers.clear();
+ for (TestAppInstance uninstalledTestApp : mUninstalledTestApps) {
+ uninstalledTestApp.testApp().install(uninstalledTestApp.user());
+ }
+ mUninstalledTestApps.clear();
- for (UserBuilder userBuilder : mRemovedUsers) {
- userBuilder.create();
- }
-
- mRemovedUsers.clear();
-
- for (TestAppInstance installedTestApp : mInstalledTestApps) {
- installedTestApp.uninstall();
- }
- mInstalledTestApps.clear();
-
- for (TestAppInstance uninstalledTestApp : mUninstalledTestApps) {
- uninstalledTestApp.testApp().install(uninstalledTestApp.user());
- }
- mUninstalledTestApps.clear();
-
- if (mOriginalBluetoothEnabled != null) {
- TestApis.bluetooth().setEnabled(mOriginalBluetoothEnabled);
- mOriginalBluetoothEnabled = null;
- }
+ if (mOriginalBluetoothEnabled != null) {
+ TestApis.bluetooth().setEnabled(mOriginalBluetoothEnabled);
+ mOriginalBluetoothEnabled = null;
+ }
+ });
}
private UserReference createProfile(
com.android.bedstead.nene.users.UserType profileType, UserReference parent) {
- requireCanSupportAdditionalUser();
- try {
- UserReference user = TestApis.users().createUser()
- .parent(parent)
- .type(profileType)
- .createAndStart();
- mCreatedUsers.add(user);
- return user;
- } catch (NeneException e) {
- throw new IllegalStateException("Error creating profile of type " + profileType, e);
- }
+ return mLogger.method("createProfile", profileType, parent, () -> {
+ requireCanSupportAdditionalUser();
+ try {
+ UserReference user = TestApis.users().createUser()
+ .parent(parent)
+ .type(profileType)
+ .createAndStart();
+ mCreatedUsers.add(user);
+ return user;
+ } catch (NeneException e) {
+ throw new IllegalStateException("Error creating profile of type " + profileType, e);
+ }
+ });
}
private UserReference createUser(com.android.bedstead.nene.users.UserType userType) {
- requireCanSupportAdditionalUser();
- try {
- UserReference user = TestApis.users().createUser()
- .type(userType)
- .createAndStart();
- mCreatedUsers.add(user);
- return user;
- } catch (NeneException e) {
- throw new IllegalStateException("Error creating user of type " + userType, e);
- }
+ return mLogger.method("createUser", userType, () -> {
+ requireCanSupportAdditionalUser();
+ try {
+ UserReference user = TestApis.users().createUser()
+ .type(userType)
+ .createAndStart();
+ mCreatedUsers.add(user);
+ return user;
+ } catch (NeneException e) {
+ throw new IllegalStateException("Error creating user of type " + userType, e);
+ }
+ });
}
private int getMaxNumberOfUsersSupported() {
- try {
- return ShellCommand.builder("pm get-max-users")
- .validate((output) -> output.startsWith("Maximum supported users:"))
- .executeAndParseOutput(
- (output) -> Integer.parseInt(output.split(": ", 2)[1].trim()));
- } catch (AdbException e) {
- throw new IllegalStateException("Invalid command output", e);
- }
+ return mLogger.method("getMaxNumberOfUsersSupported", () -> {
+ try {
+ return ShellCommand.builder("pm get-max-users")
+ .validate((output) -> output.startsWith("Maximum supported users:"))
+ .executeAndParseOutput(
+ (output) -> Integer.parseInt(output.split(": ", 2)[1]
+ .trim()));
+ } catch (AdbException e) {
+ throw new IllegalStateException("Invalid command output", e);
+ }
+ });
}
private void ensureHasDelegate(
EnsureHasDelegate.AdminType adminType, List<String> scopes, boolean isPrimary) {
- RemotePolicyManager dpc = getDeviceAdmin(adminType);
+ mLogger.method("ensureHasDelegate", adminType, scopes, isPrimary, () -> {
+ RemotePolicyManager dpc = getDeviceAdmin(adminType);
- boolean specifiesAdminType = adminType != EnsureHasDelegate.AdminType.PRIMARY;
- boolean currentPrimaryPolicyManagerIsNotDelegator = mPrimaryPolicyManager != dpc;
+ boolean specifiesAdminType = adminType != EnsureHasDelegate.AdminType.PRIMARY;
+ boolean currentPrimaryPolicyManagerIsNotDelegator =
+ !Objects.equal(mPrimaryPolicyManager, dpc);
- if (isPrimary && mPrimaryPolicyManager != null
- && (specifiesAdminType || currentPrimaryPolicyManagerIsNotDelegator)) {
- throw new IllegalStateException(
- "Only one DPC can be marked as primary per test (current primary is "
- + mPrimaryPolicyManager + ")");
- }
-
- if (!dpc.user().equals(TestApis.users().instrumented())) {
- // INTERACT_ACROSS_USERS_FULL is required for RemoteDPC
- ensureCanGetPermission(INTERACT_ACROSS_USERS_FULL);
- }
-
- ensureTestAppInstalled(RemoteDelegate.sTestApp, dpc.user());
- RemoteDelegate delegate = new RemoteDelegate(RemoteDelegate.sTestApp, dpc().user());
- dpc.devicePolicyManager().setDelegatedScopes(
- dpc.componentName(), delegate.packageName(), scopes);
-
- if (isPrimary) {
- mPrimaryPolicyManager = delegate;
- }
- }
-
- private void ensureHasNoDelegate(EnsureHasNoDelegate.AdminType adminType) {
- if (adminType == EnsureHasNoDelegate.AdminType.ANY) {
- for (UserReference user : TestApis.users().all()) {
- ensureTestAppNotInstalled(RemoteDelegate.sTestApp, user);
- }
- return;
- }
- RemotePolicyManager dpc =
- adminType == EnsureHasNoDelegate.AdminType.PRIMARY ? mPrimaryPolicyManager
- : adminType == EnsureHasNoDelegate.AdminType.DEVICE_OWNER ? deviceOwner()
- : adminType == EnsureHasNoDelegate.AdminType.PROFILE_OWNER ? profileOwner() : null;
- if (dpc == null) {
- throw new IllegalStateException("Unknown Admin Type " + adminType);
- }
-
- ensureTestAppNotInstalled(RemoteDelegate.sTestApp, dpc.user());
- }
-
- private void ensureTestAppInstalled(
- String key, String packageName, UserType onUser, boolean isPrimary) {
- TestApp testApp = mTestAppProvider.query()
- .wherePackageName().isEqualTo(packageName)
- .get();
-
- TestAppInstance testAppInstance = ensureTestAppInstalled(
- testApp, resolveUserTypeToUser(onUser));
-
- mTestApps.put(key, testAppInstance);
-
- if (isPrimary) {
- if (mPrimaryPolicyManager != null) {
+ if (isPrimary && mPrimaryPolicyManager != null
+ && (specifiesAdminType || currentPrimaryPolicyManagerIsNotDelegator)) {
throw new IllegalStateException(
"Only one DPC can be marked as primary per test (current primary is "
+ mPrimaryPolicyManager + ")");
}
- mPrimaryPolicyManager = new RemoteTestApp(testAppInstance);
- }
+ if (!dpc.user().equals(TestApis.users().instrumented())) {
+ // INTERACT_ACROSS_USERS_FULL is required for RemoteDPC
+ ensureCanGetPermission(INTERACT_ACROSS_USERS_FULL);
+ }
+
+ ensureTestAppInstalled(RemoteDelegate.sTestApp, dpc.user());
+ RemoteDelegate delegate = new RemoteDelegate(RemoteDelegate.sTestApp, dpc().user());
+ dpc.devicePolicyManager().setDelegatedScopes(
+ dpc.componentName(), delegate.packageName(), scopes);
+
+ if (isPrimary) {
+ mPrimaryPolicyManager = delegate;
+ }
+ });
+ }
+
+ private void ensureHasNoDelegate(EnsureHasNoDelegate.AdminType adminType) {
+ mLogger.method("ensureHasNoDelegate", adminType, () -> {
+ if (adminType == EnsureHasNoDelegate.AdminType.ANY) {
+ for (UserReference user : TestApis.users().all()) {
+ ensureTestAppNotInstalled(RemoteDelegate.sTestApp, user);
+ }
+ return;
+ }
+ RemotePolicyManager dpc =
+ adminType == EnsureHasNoDelegate.AdminType.PRIMARY ? mPrimaryPolicyManager
+ : adminType == EnsureHasNoDelegate.AdminType.DEVICE_OWNER
+ ? deviceOwner()
+ : adminType == EnsureHasNoDelegate.AdminType.PROFILE_OWNER
+ ? profileOwner() : null;
+ if (dpc == null) {
+ throw new IllegalStateException("Unknown Admin Type " + adminType);
+ }
+
+ ensureTestAppNotInstalled(RemoteDelegate.sTestApp, dpc.user());
+ });
+ }
+
+ private void ensureTestAppInstalled(
+ String key, String packageName, UserType onUser, boolean isPrimary) {
+ mLogger.method("ensureTestAppInstalled", key, packageName, onUser, isPrimary, () -> {
+ TestApp testApp = mTestAppProvider.query()
+ .wherePackageName().isEqualTo(packageName)
+ .get();
+
+ TestAppInstance testAppInstance = ensureTestAppInstalled(
+ testApp, resolveUserTypeToUser(onUser));
+
+ mTestApps.put(key, testAppInstance);
+
+ if (isPrimary) {
+ if (mPrimaryPolicyManager != null) {
+ throw new IllegalStateException(
+ "Only one DPC can be marked as primary per test (current primary is "
+ + mPrimaryPolicyManager + ")");
+ }
+
+ mPrimaryPolicyManager = new RemoteTestApp(testAppInstance);
+ }
+ });
}
private void ensureTestAppHasPermission(
String testAppKey, String[] permissions, int minVersion, int maxVersion) {
- if (!mTestApps.containsKey(testAppKey)) {
- throw new NeneException("No testapp with given key. Use @EnsureTestAppInstalled");
- }
+ mLogger.method("ensureTestAppHasPermission", testAppKey, permissions, minVersion,
+ maxVersion, () -> {
+ checkTestAppExistsWithKey(testAppKey);
- mTestApps.get(testAppKey).permissions()
- .withPermissionOnVersionBetween(minVersion, maxVersion, permissions);
-
+ mTestApps.get(testAppKey).permissions()
+ .withPermissionOnVersionBetween(minVersion, maxVersion, permissions);
+ });
}
private void ensureTestAppHasAppOp(
String testAppKey, String[] appOps, int minVersion, int maxVersion) {
- if (!mTestApps.containsKey(testAppKey)) {
- throw new NeneException("No testapp with given key. Use @EnsureTestAppInstalled");
- }
+ mLogger.method("ensureTestAppHasAppOp", testAppKey, appOps, minVersion, maxVersion, () -> {
+ checkTestAppExistsWithKey(testAppKey);
- mTestApps.get(testAppKey).permissions()
- .withAppOpOnVersionBetween(minVersion, maxVersion, appOps);
+ mTestApps.get(testAppKey).permissions()
+ .withAppOpOnVersionBetween(minVersion, maxVersion, appOps);
+ });
+ }
+
+ private void checkTestAppExistsWithKey(String testAppKey) {
+ if (!mTestApps.containsKey(testAppKey)) {
+ throw new NeneException(
+ "No testapp with key " + testAppKey + ". Use @EnsureTestAppInstalled."
+ + "Valid Test apps: " + mTestApps);
+ }
}
private RemotePolicyManager getDeviceAdmin(EnsureHasDelegate.AdminType adminType) {
- switch (adminType) {
- case DEVICE_OWNER:
- return deviceOwner();
- case PROFILE_OWNER:
- return profileOwner();
- case PRIMARY:
- return dpc();
- default:
- throw new IllegalStateException("Unknown device admin type " + adminType);
- }
+ return mLogger.method("getDeviceAdmin", adminType, () -> {
+ switch (adminType) {
+ case DEVICE_OWNER:
+ return deviceOwner();
+ case PROFILE_OWNER:
+ return profileOwner();
+ case PRIMARY:
+ return dpc();
+ default:
+ throw new IllegalStateException("Unknown device admin type " + adminType);
+ }
+ });
}
private TestAppInstance ensureTestAppInstalled(TestApp testApp, UserReference user) {
- Package pkg = TestApis.packages().find(testApp.packageName());
- if (pkg != null && TestApis.packages().find(testApp.packageName()).installedOnUser(user)) {
- return testApp.instance(user);
- }
+ return mLogger.method("ensureTestAppInstalled", testApp, user, () -> {
+ Package pkg = TestApis.packages().find(testApp.packageName());
+ if (pkg != null && TestApis.packages().find(testApp.packageName()).installedOnUser(
+ user)) {
+ return testApp.instance(user);
+ }
- TestAppInstance testAppInstance = testApp.install(user);
- mInstalledTestApps.add(testAppInstance);
- return testAppInstance;
+ TestAppInstance testAppInstance = testApp.install(user);
+ mInstalledTestApps.add(testAppInstance);
+ return testAppInstance;
+ });
}
private void ensureTestAppNotInstalled(TestApp testApp, UserReference user) {
- Package pkg = TestApis.packages().find(testApp.packageName());
- if (pkg == null || !TestApis.packages().find(testApp.packageName()).installedOnUser(user)) {
- return;
- }
+ mLogger.method("ensureTestAppNotInstalled", testApp, user, () -> {
+ Package pkg = TestApis.packages().find(testApp.packageName());
+ if (pkg == null || !TestApis.packages().find(testApp.packageName()).installedOnUser(
+ user)) {
+ return;
+ }
- TestAppInstance instance = testApp.instance(user);
+ TestAppInstance instance = testApp.instance(user);
- if (mInstalledTestApps.contains(instance)) {
- mInstalledTestApps.remove(instance);
- } else {
- mUninstalledTestApps.add(instance);
- }
+ if (mInstalledTestApps.contains(instance)) {
+ mInstalledTestApps.remove(instance);
+ } else {
+ mUninstalledTestApps.add(instance);
+ }
- testApp.uninstall(user);
+ testApp.uninstall(user);
+ });
}
private void ensureHasDeviceOwner(FailureMode failureMode, boolean isPrimary,
Set<String> affiliationIds) {
- // TODO(scottjonathan): Should support non-remotedpc device owner (default to remotedpc)
+ mLogger.method("ensureHasDeviceOwner", failureMode, isPrimary, affiliationIds, () -> {
+ // TODO(scottjonathan): Should support non-remotedpc device owner (default to remotedpc)
- UserReference userReference = TestApis.users().system();
+ UserReference userReference = TestApis.users().system();
- if (isPrimary && mPrimaryPolicyManager != null && !userReference.equals(
- mPrimaryPolicyManager.user())) {
- throw new IllegalStateException(
- "Only one DPC can be marked as primary per test (current primary is "
- + mPrimaryPolicyManager + ")");
- }
- if (!userReference.equals(TestApis.users().instrumented())) {
- // INTERACT_ACROSS_USERS_FULL is required for RemoteDPC
- ensureCanGetPermission(INTERACT_ACROSS_USERS_FULL);
- }
-
- DeviceOwner currentDeviceOwner = TestApis.devicePolicy().getDeviceOwner();
-
- if (currentDeviceOwner != null
- && currentDeviceOwner.componentName().equals(RemoteDpc.DPC_COMPONENT_NAME)) {
- mDeviceOwner = currentDeviceOwner;
- } else {
- UserReference instrumentedUser = TestApis.users().instrumented();
-
- if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)) {
- // Prior to S we can't set device owner if there are other users on the device
-
- if (instrumentedUser.id() != 0) {
- // If we're not on the system user we can't reach the required state
- throw new AssumptionViolatedException(
- "Can't set Device Owner when running on non-system-user"
- + " on this version of Android");
- }
-
- for (UserReference u : TestApis.users().all()) {
- if (u.equals(instrumentedUser)) {
- // Can't remove the user we're running on
- continue;
- }
- try {
- removeAndRecordUser(u);
- } catch (NeneException e) {
- failOrSkip(
- "Error removing user to prepare for DeviceOwner: " + e.toString(),
- failureMode);
- }
- }
+ if (isPrimary && mPrimaryPolicyManager != null && !userReference.equals(
+ mPrimaryPolicyManager.user())) {
+ throw new IllegalStateException(
+ "Only one DPC can be marked as primary per test (current primary is "
+ + mPrimaryPolicyManager + ")");
+ }
+ if (!userReference.equals(TestApis.users().instrumented())) {
+ // INTERACT_ACROSS_USERS_FULL is required for RemoteDPC
+ ensureCanGetPermission(INTERACT_ACROSS_USERS_FULL);
}
- // TODO(scottjonathan): Remove accounts
- ensureHasNoProfileOwner(userReference);
+ DeviceOwner currentDeviceOwner = TestApis.devicePolicy().getDeviceOwner();
- if (!mHasChangedDeviceOwner) {
- mOriginalDeviceOwner = currentDeviceOwner;
- mHasChangedDeviceOwner = true;
+ if (currentDeviceOwner != null
+ && currentDeviceOwner.componentName().equals(RemoteDpc.DPC_COMPONENT_NAME)) {
+ mDeviceOwner = currentDeviceOwner;
+ } else {
+ UserReference instrumentedUser = TestApis.users().instrumented();
+
+ if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)) {
+ // Prior to S we can't set device owner if there are other users on the device
+
+ if (instrumentedUser.id() != 0) {
+ // If we're not on the system user we can't reach the required state
+ throw new AssumptionViolatedException(
+ "Can't set Device Owner when running on non-system-user"
+ + " on this version of Android");
+ }
+
+ for (UserReference u : TestApis.users().all()) {
+ if (u.equals(instrumentedUser)) {
+ // Can't remove the user we're running on
+ continue;
+ }
+ try {
+ removeAndRecordUser(u);
+ } catch (NeneException e) {
+ failOrSkip(
+ "Error removing user to prepare for DeviceOwner: "
+ + e.toString(),
+ failureMode);
+ }
+ }
+ }
+
+ // TODO(scottjonathan): Remove accounts
+ ensureHasNoProfileOwner(userReference);
+
+ if (!mHasChangedDeviceOwner) {
+ mOriginalDeviceOwner = currentDeviceOwner;
+ mHasChangedDeviceOwner = true;
+ }
+
+ mDeviceOwner = RemoteDpc.setAsDeviceOwner().devicePolicyController();
}
- mDeviceOwner = RemoteDpc.setAsDeviceOwner().devicePolicyController();
- }
+ if (isPrimary) {
+ mPrimaryPolicyManager = RemoteDpc.forDevicePolicyController(mDeviceOwner);
+ }
- if (isPrimary) {
- mPrimaryPolicyManager = RemoteDpc.forDevicePolicyController(mDeviceOwner);
- }
-
- RemoteDpc.forDevicePolicyController(mDeviceOwner)
- .devicePolicyManager()
- .setAffiliationIds(REMOTE_DPC_COMPONENT_NAME, affiliationIds);
+ RemoteDpc.forDevicePolicyController(mDeviceOwner)
+ .devicePolicyManager()
+ .setAffiliationIds(REMOTE_DPC_COMPONENT_NAME, affiliationIds);
+ });
}
private void ensureHasProfileOwner(UserType onUser, boolean isPrimary,
boolean useParentInstance, Set<String> affiliationIds) {
- // TODO(scottjonathan): Should support non-remotedpc profile owner (default to remotedpc)
- UserReference user = resolveUserTypeToUser(onUser);
- ensureHasProfileOwner(user, isPrimary, useParentInstance, affiliationIds);
+ mLogger.method("ensureHasProfileOwner",
+ onUser, isPrimary, useParentInstance, affiliationIds, () -> {
+ // TODO(scottjonathan): Should support non-remotedpc profile owner
+ // (default to remotedpc)
+ UserReference user = resolveUserTypeToUser(onUser);
+ ensureHasProfileOwner(user, isPrimary, useParentInstance, affiliationIds);
+ });
}
private void ensureHasProfileOwner(
UserReference user, boolean isPrimary, boolean useParentInstance,
Set<String> affiliationIds) {
- if (isPrimary && mPrimaryPolicyManager != null
- && !user.equals(mPrimaryPolicyManager.user())) {
- throw new IllegalStateException("Only one DPC can be marked as primary per test");
- }
+ mLogger.method("ensureHasProfileOwner", user, isPrimary, useParentInstance,
+ affiliationIds, () -> {
+ if (isPrimary && mPrimaryPolicyManager != null
+ && !user.equals(mPrimaryPolicyManager.user())) {
+ throw new IllegalStateException(
+ "Only one DPC can be marked as primary per test");
+ }
- if (!user.equals(TestApis.users().instrumented())) {
- // INTERACT_ACROSS_USERS_FULL is required for RemoteDPC
- ensureCanGetPermission(INTERACT_ACROSS_USERS_FULL);
- }
+ if (!user.equals(TestApis.users().instrumented())) {
+ // INTERACT_ACROSS_USERS_FULL is required for RemoteDPC
+ ensureCanGetPermission(INTERACT_ACROSS_USERS_FULL);
+ }
- ProfileOwner currentProfileOwner = TestApis.devicePolicy().getProfileOwner(user);
- DeviceOwner currentDeviceOwner = TestApis.devicePolicy().getDeviceOwner();
+ ProfileOwner currentProfileOwner = TestApis.devicePolicy().getProfileOwner(
+ user);
+ DeviceOwner currentDeviceOwner = TestApis.devicePolicy().getDeviceOwner();
- if (currentDeviceOwner != null && currentDeviceOwner.user().equals(user)) {
- // Can't have DO and PO on the same user
- ensureHasNoDeviceOwner();
- }
+ if (currentDeviceOwner != null && currentDeviceOwner.user().equals(user)) {
+ // Can't have DO and PO on the same user
+ ensureHasNoDeviceOwner();
+ }
- if (currentProfileOwner != null
- && currentProfileOwner.componentName().equals(
- RemoteDpc.DPC_COMPONENT_NAME)) {
- mProfileOwners.put(user, currentProfileOwner);
- } else {
+ if (currentProfileOwner != null && currentProfileOwner.componentName()
+ .equals(RemoteDpc.DPC_COMPONENT_NAME)) {
+ mProfileOwners.put(user, currentProfileOwner);
+ } else {
+ if (!mChangedProfileOwners.containsKey(user)) {
+ mChangedProfileOwners.put(user, currentProfileOwner);
+ }
+
+ mProfileOwners.put(user,
+ RemoteDpc.setAsProfileOwner(user).devicePolicyController());
+ }
+
+ if (isPrimary) {
+ if (useParentInstance) {
+ mPrimaryPolicyManager = new RemoteDpcUsingParentInstance(
+ RemoteDpc.forDevicePolicyController(
+ mProfileOwners.get(user)).devicePolicyController());
+ } else {
+ mPrimaryPolicyManager =
+ RemoteDpc.forDevicePolicyController(mProfileOwners.get(user));
+ }
+ }
+
+ if (affiliationIds != null) {
+ RemoteDpc profileOwner = profileOwner(user);
+ profileOwner.devicePolicyManager()
+ .setAffiliationIds(REMOTE_DPC_COMPONENT_NAME, affiliationIds);
+ }
+ });
+ }
+
+ private void ensureHasNoDeviceOwner() {
+ mLogger.method("ensureHasNoDeviceOwner", () -> {
+ DeviceOwner deviceOwner = TestApis.devicePolicy().getDeviceOwner();
+
+ if (deviceOwner == null) {
+ return;
+ }
+
+ if (!mHasChangedDeviceOwner) {
+ mOriginalDeviceOwner = deviceOwner;
+ mHasChangedDeviceOwner = true;
+ }
+
+ mDeviceOwner = null;
+ deviceOwner.remove();
+ });
+ }
+
+ private void ensureHasNoProfileOwner(UserType onUser) {
+ mLogger.method("ensureHasNoProfileOwner", onUser, () -> {
+ UserReference user = resolveUserTypeToUser(onUser);
+
+ ensureHasNoProfileOwner(user);
+ });
+ }
+
+ private void ensureHasNoProfileOwner(UserReference user) {
+ mLogger.method("ensureHasNoProfileOwner", user, () -> {
+ ProfileOwner currentProfileOwner = TestApis.devicePolicy().getProfileOwner(user);
+
+ if (currentProfileOwner == null) {
+ return;
+ }
+
if (!mChangedProfileOwners.containsKey(user)) {
mChangedProfileOwners.put(user, currentProfileOwner);
}
- mProfileOwners.put(user, RemoteDpc.setAsProfileOwner(user).devicePolicyController());
- }
-
- if (isPrimary) {
- if (useParentInstance) {
- mPrimaryPolicyManager = new RemoteDpcUsingParentInstance(
- RemoteDpc.forDevicePolicyController(
- mProfileOwners.get(user)).devicePolicyController());
- } else {
- mPrimaryPolicyManager =
- RemoteDpc.forDevicePolicyController(mProfileOwners.get(user));
- }
- }
-
- if (affiliationIds != null) {
- RemoteDpc profileOwner = profileOwner(user);
- profileOwner.devicePolicyManager()
- .setAffiliationIds(REMOTE_DPC_COMPONENT_NAME, affiliationIds);
- }
- }
-
- private void ensureHasNoDeviceOwner() {
- DeviceOwner deviceOwner = TestApis.devicePolicy().getDeviceOwner();
-
- if (deviceOwner == null) {
- return;
- }
-
- if (!mHasChangedDeviceOwner) {
- mOriginalDeviceOwner = deviceOwner;
- mHasChangedDeviceOwner = true;
- }
-
- mDeviceOwner = null;
- deviceOwner.remove();
- }
-
- private void ensureHasNoProfileOwner(UserType onUser) {
- UserReference user = resolveUserTypeToUser(onUser);
-
- ensureHasNoProfileOwner(user);
- }
-
- private void ensureHasNoProfileOwner(UserReference user) {
-
- ProfileOwner currentProfileOwner = TestApis.devicePolicy().getProfileOwner(user);
-
- if (currentProfileOwner == null) {
- return;
- }
-
- if (!mChangedProfileOwners.containsKey(user)) {
- mChangedProfileOwners.put(user, currentProfileOwner);
- }
-
- TestApis.devicePolicy().getProfileOwner(user).remove();
- mProfileOwners.remove(user);
+ TestApis.devicePolicy().getProfileOwner(user).remove();
+ mProfileOwners.remove(user);
+ });
}
/**
@@ -2062,16 +2248,19 @@
* <p>If the device owner is not a RemoteDPC then an exception will be thrown
*/
public RemoteDpc deviceOwner() {
- if (mDeviceOwner == null) {
- throw new IllegalStateException("No Harrier-managed device owner. This method should "
- + "only be used when Harrier was used to set the Device Owner.");
- }
- if (!mDeviceOwner.componentName().equals(REMOTE_DPC_COMPONENT_NAME)) {
- throw new IllegalStateException("The device owner is not a RemoteDPC."
- + " You must use Nene to query for this device owner.");
- }
+ return mLogger.method("deviceOwner", () -> {
+ if (mDeviceOwner == null) {
+ throw new IllegalStateException(
+ "No Harrier-managed device owner. This method should "
+ + "only be used when Harrier was used to set the Device Owner.");
+ }
+ if (!mDeviceOwner.componentName().equals(REMOTE_DPC_COMPONENT_NAME)) {
+ throw new IllegalStateException("The device owner is not a RemoteDPC."
+ + " You must use Nene to query for this device owner.");
+ }
- return RemoteDpc.forDevicePolicyController(mDeviceOwner);
+ return RemoteDpc.forDevicePolicyController(mDeviceOwner);
+ });
}
/**
@@ -2082,7 +2271,9 @@
* <p>If the profile owner is not a RemoteDPC then an exception will be thrown.
*/
public RemoteDpc profileOwner() {
- return profileOwner(UserType.INSTRUMENTED_USER);
+ return mLogger.method("profileOwner", () -> {
+ return profileOwner(UserType.INSTRUMENTED_USER);
+ });
}
/**
@@ -2093,11 +2284,13 @@
* <p>If the profile owner is not a RemoteDPC then an exception will be thrown.
*/
public RemoteDpc profileOwner(UserType onUser) {
- if (onUser == null) {
- throw new NullPointerException();
- }
+ return mLogger.method("profileOwner", onUser, () -> {
+ if (onUser == null) {
+ throw new NullPointerException();
+ }
- return profileOwner(resolveUserTypeToUser(onUser));
+ return profileOwner(resolveUserTypeToUser(onUser));
+ });
}
/**
@@ -2108,70 +2301,79 @@
* <p>If the profile owner is not a RemoteDPC then an exception will be thrown.
*/
public RemoteDpc profileOwner(UserReference onUser) {
- if (onUser == null) {
- throw new NullPointerException();
- }
+ return mLogger.method("profileOwner", onUser, () -> {
+ if (onUser == null) {
+ throw new NullPointerException();
+ }
- if (!mProfileOwners.containsKey(onUser)) {
- throw new IllegalStateException("No Harrier-managed profile owner. This method should "
- + "only be used when Harrier was used to set the Profile Owner.");
- }
+ if (!mProfileOwners.containsKey(onUser)) {
+ throw new IllegalStateException(
+ "No Harrier-managed profile owner. This method should "
+ + "only be used when Harrier was used to set the Profile Owner.");
+ }
- DevicePolicyController profileOwner = mProfileOwners.get(onUser);
+ DevicePolicyController profileOwner = mProfileOwners.get(onUser);
- if (!profileOwner.componentName().equals(REMOTE_DPC_COMPONENT_NAME)) {
- throw new IllegalStateException("The profile owner is not a RemoteDPC."
- + " You must use Nene to query for this profile owner.");
- }
+ if (!profileOwner.componentName().equals(REMOTE_DPC_COMPONENT_NAME)) {
+ throw new IllegalStateException("The profile owner is not a RemoteDPC."
+ + " You must use Nene to query for this profile owner.");
+ }
- return RemoteDpc.forDevicePolicyController(profileOwner);
+ return RemoteDpc.forDevicePolicyController(profileOwner);
+ });
}
private void requirePackageInstalled(
String packageName, UserType forUser, FailureMode failureMode) {
+ mLogger.method("requirePackageInstalled", packageName, forUser, failureMode, () -> {
+ Package pkg = TestApis.packages().find(packageName);
- Package pkg = TestApis.packages().find(packageName);
-
- if (forUser.equals(UserType.ANY)) {
- checkFailOrSkip(
- packageName + " is required to be installed",
- !pkg.installedOnUsers().isEmpty(),
- failureMode);
- } else {
- checkFailOrSkip(
- packageName + " is required to be installed for " + forUser,
- pkg.installedOnUser(resolveUserTypeToUser(forUser)),
- failureMode);
- }
+ if (forUser.equals(UserType.ANY)) {
+ checkFailOrSkip(
+ packageName + " is required to be installed",
+ !pkg.installedOnUsers().isEmpty(),
+ failureMode);
+ } else {
+ checkFailOrSkip(
+ packageName + " is required to be installed for " + forUser,
+ pkg.installedOnUser(resolveUserTypeToUser(forUser)),
+ failureMode);
+ }
+ });
}
private void requirePackageNotInstalled(
String packageName, UserType forUser, FailureMode failureMode) {
- Package pkg = TestApis.packages().find(packageName);
+ mLogger.method("requirePackageNotInstalled", packageName, forUser,
+ failureMode, () -> {
+ Package pkg = TestApis.packages().find(packageName);
- if (forUser.equals(UserType.ANY)) {
- checkFailOrSkip(
- packageName + " is required to be not installed",
- pkg.installedOnUsers().isEmpty(),
- failureMode);
- } else {
- checkFailOrSkip(
- packageName + " is required to be not installed for " + forUser,
- !pkg.installedOnUser(resolveUserTypeToUser(forUser)),
- failureMode);
- }
+ if (forUser.equals(UserType.ANY)) {
+ checkFailOrSkip(
+ packageName + " is required to be not installed",
+ pkg.installedOnUsers().isEmpty(),
+ failureMode);
+ } else {
+ checkFailOrSkip(
+ packageName + " is required to be not installed for " + forUser,
+ !pkg.installedOnUser(resolveUserTypeToUser(forUser)),
+ failureMode);
+ }
+ });
}
private void ensurePackageNotInstalled(
String packageName, UserType forUser) {
- Package pkg = TestApis.packages().find(packageName);
+ mLogger.method("ensurePackageNotInstalled", packageName, forUser, () -> {
+ Package pkg = TestApis.packages().find(packageName);
- if (forUser.equals(UserType.ANY)) {
- pkg.uninstallFromAllUsers();
- } else {
- UserReference user = resolveUserTypeToUser(forUser);
- pkg.uninstall(user);
- }
+ if (forUser.equals(UserType.ANY)) {
+ pkg.uninstallFromAllUsers();
+ } else {
+ UserReference user = resolveUserTypeToUser(forUser);
+ pkg.uninstall(user);
+ }
+ });
}
/**
@@ -2189,28 +2391,30 @@
* <p>If the profile owner or device owner is not a RemoteDPC then an exception will be thrown.
*/
public RemotePolicyManager dpc() {
- if (mPrimaryPolicyManager != null) {
- return mPrimaryPolicyManager;
- }
-
- if (mProfileOwners.containsKey(TestApis.users().instrumented())) {
- DevicePolicyController profileOwner =
- mProfileOwners.get(TestApis.users().instrumented());
-
-
- if (profileOwner.componentName().equals(REMOTE_DPC_COMPONENT_NAME)) {
- return RemoteDpc.forDevicePolicyController(profileOwner);
- }
- }
-
- if (mDeviceOwner != null) {
- if (mDeviceOwner.componentName().equals(REMOTE_DPC_COMPONENT_NAME)) {
- return RemoteDpc.forDevicePolicyController(mDeviceOwner);
+ return mLogger.method("dpc", () -> {
+ if (mPrimaryPolicyManager != null) {
+ return mPrimaryPolicyManager;
}
- }
+ if (mProfileOwners.containsKey(TestApis.users().instrumented())) {
+ DevicePolicyController profileOwner =
+ mProfileOwners.get(TestApis.users().instrumented());
- throw new IllegalStateException("No Harrier-managed profile owner or device owner.");
+
+ if (profileOwner.componentName().equals(REMOTE_DPC_COMPONENT_NAME)) {
+ return RemoteDpc.forDevicePolicyController(profileOwner);
+ }
+ }
+
+ if (mDeviceOwner != null) {
+ if (mDeviceOwner.componentName().equals(REMOTE_DPC_COMPONENT_NAME)) {
+ return RemoteDpc.forDevicePolicyController(mDeviceOwner);
+ }
+
+ }
+
+ throw new IllegalStateException("No Harrier-managed profile owner or device owner.");
+ });
}
/**
@@ -2220,178 +2424,210 @@
* automatically remove test apps use the {@link EnsureTestAppInstalled} annotation.
*/
public TestAppProvider testApps() {
- return mTestAppProvider;
+ return mLogger.method("testApps", () -> {
+ return mTestAppProvider;
+ });
}
/**
* Get a test app installed with @EnsureTestAppInstalled with no key.
*/
public TestAppInstance testApp() {
- return testApp(DEFAULT_TEST_APP_KEY);
+ return mLogger.method("testApp", () -> {
+ return testApp(DEFAULT_TEST_APP_KEY);
+ });
}
/**
* Get a test app installed with `@EnsureTestAppInstalled` with the given key.
*/
public TestAppInstance testApp(String key) {
- if (!mTestApps.containsKey(key)) {
- throw new NeneException("No testapp with given key. Use @EnsureTestAppInstalled");
- }
+ return mLogger.method("testApp", key, () -> {
+ if (!mTestApps.containsKey(key)) {
+ throw new NeneException("No testapp with given key. Use @EnsureTestAppInstalled");
+ }
- return mTestApps.get(key);
+ return mTestApps.get(key);
+ });
}
private void ensureCanGetPermission(String permission) {
- if (mPermissionsInstrumentationPackage == null) {
- // We just need to check if we can get it generally
+ mLogger.method("ensureCanGetPermission", permission, () -> {
+ if (mPermissionsInstrumentationPackage == null) {
+ // We just need to check if we can get it generally
- if (TestApis.permissions().usablePermissions().contains(permission)) {
- return;
+ if (TestApis.permissions().usablePermissions().contains(permission)) {
+ return;
+ }
+
+ if (TestApis.packages().instrumented().isInstantApp()) {
+ // Instant Apps aren't able to know the permissions of shell so we can't know
+ // if we
+ // can adopt it - we'll assume we can adopt and log
+ Log.i(LOG_TAG,
+ "Assuming we can get permission " + permission
+ + " as running on instant app");
+ return;
+ }
+
+ TestApis.permissions().throwPermissionException(
+ "Can not get required permission", permission);
}
- if (TestApis.packages().instrumented().isInstantApp()) {
- // Instant Apps aren't able to know the permissions of shell so we can't know if we
- // can adopt it - we'll assume we can adopt and log
- Log.i(LOG_TAG,
- "Assuming we can get permission " + permission
- + " as running on instant app");
- return;
+ if (TestApis.permissions().adoptablePermissions().contains(permission)) {
+ requireNoPermissionsInstrumentation("Requires permission " + permission);
+ } else if (mPermissionsInstrumentationPackagePermissions.contains(permission)) {
+ requirePermissionsInstrumentation("Requires permission " + permission);
+ } else {
+ // Can't get permission at all - error (including the permissions for both)
+ TestApis.permissions().throwPermissionException(
+ "Can not get permission " + permission + " including by instrumenting "
+ + mPermissionsInstrumentationPackage
+ + "\n " + mPermissionsInstrumentationPackage + " permissions: "
+ + mPermissionsInstrumentationPackagePermissions,
+ permission
+ );
}
-
- TestApis.permissions().throwPermissionException(
- "Can not get required permission", permission);
- }
-
- if (TestApis.permissions().adoptablePermissions().contains(permission)) {
- requireNoPermissionsInstrumentation("Requires permission " + permission);
- } else if (mPermissionsInstrumentationPackagePermissions.contains(permission)) {
- requirePermissionsInstrumentation("Requires permission " + permission);
- } else {
- // Can't get permission at all - error (including the permissions for both)
- TestApis.permissions().throwPermissionException(
- "Can not get permission " + permission + " including by instrumenting "
- + mPermissionsInstrumentationPackage
- + "\n " + mPermissionsInstrumentationPackage + " permissions: "
- + mPermissionsInstrumentationPackagePermissions,
- permission
- );
- }
+ });
}
private void switchToUser(UserReference user) {
- UserReference currentUser = TestApis.users().current();
- if (!currentUser.equals(user)) {
- if (mOriginalSwitchedUser == null) {
- mOriginalSwitchedUser = currentUser;
+ mLogger.method("switchToUser", user, () -> {
+ UserReference currentUser = TestApis.users().current();
+ if (!currentUser.equals(user)) {
+ if (mOriginalSwitchedUser == null) {
+ mOriginalSwitchedUser = currentUser;
+ }
+ user.switchTo();
}
- user.switchTo();
- }
+ });
}
private void switchFromUser(UserReference user) {
- UserReference currentUser = TestApis.users().current();
- if (!currentUser.equals(user)) {
- return;
- }
-
- // We need to find a different user to switch to
- // full users only, starting with lowest ID
- List<UserReference> users = new ArrayList<>(TestApis.users().all());
- users.sort(Comparator.comparingInt(UserReference::id));
-
- for (UserReference otherUser : users) {
- if (otherUser.equals(user)) {
- continue;
+ mLogger.method("switchFromUser", user, () -> {
+ UserReference currentUser = TestApis.users().current();
+ if (!currentUser.equals(user)) {
+ return;
}
- if (otherUser.parent() != null) {
- continue;
+ // We need to find a different user to switch to
+ // full users only, starting with lowest ID
+ List<UserReference> users = new ArrayList<>(TestApis.users().all());
+ users.sort(Comparator.comparingInt(UserReference::id));
+
+ for (UserReference otherUser : users) {
+ if (otherUser.equals(user)) {
+ continue;
+ }
+
+ if (otherUser.parent() != null) {
+ continue;
+ }
+
+ switchToUser(otherUser);
+ return;
}
- switchToUser(otherUser);
- return;
- }
-
- // There are no users to switch to so we'll create one
- ensureHasUser(SECONDARY_USER_TYPE_NAME,
- /* installInstrumentedApp= */ OptionalBoolean.ANY,
- /* switchedToUser= */ OptionalBoolean.TRUE);
+ // There are no users to switch to so we'll create one
+ ensureHasUser(SECONDARY_USER_TYPE_NAME,
+ /* installInstrumentedApp= */ OptionalBoolean.ANY,
+ /* switchedToUser= */ OptionalBoolean.TRUE);
+ });
}
private void requireNotHeadlessSystemUserMode() {
- assumeFalse("This test is not supported on headless system user devices",
- TestApis.users().isHeadlessSystemUserMode());
+ mLogger.method("requireNotHeadlessSystemUserMode", () -> {
+ assumeFalse("This test is not supported on headless system user devices",
+ TestApis.users().isHeadlessSystemUserMode());
+ });
}
private void requireHeadlessSystemUserMode() {
- assumeTrue("This test is only supported on headless system user devices",
- TestApis.users().isHeadlessSystemUserMode());
+ mLogger.method("requireHeadlessSystemUserMode", () -> {
+ assumeTrue("This test is only supported on headless system user devices",
+ TestApis.users().isHeadlessSystemUserMode());
+ });
}
private void requireLowRamDevice(String reason, FailureMode failureMode) {
- checkFailOrSkip(reason,
- TestApis.context().instrumentedContext()
- .getSystemService(ActivityManager.class)
- .isLowRamDevice(),
- failureMode);
+ mLogger.method("requireLowRamDevice", reason, failureMode, () -> {
+ checkFailOrSkip(reason,
+ TestApis.context().instrumentedContext()
+ .getSystemService(ActivityManager.class)
+ .isLowRamDevice(),
+ failureMode);
+ });
}
private void requireNotLowRamDevice(String reason, FailureMode failureMode) {
- checkFailOrSkip(reason,
- !TestApis.context().instrumentedContext()
- .getSystemService(ActivityManager.class)
- .isLowRamDevice(),
- failureMode);
+ mLogger.method("requireNotLowRamDevice", reason, failureMode, () -> {
+ checkFailOrSkip(reason,
+ !TestApis.context().instrumentedContext()
+ .getSystemService(ActivityManager.class)
+ .isLowRamDevice(),
+ failureMode);
+ });
}
private void ensureScreenIsOn() {
- TestApis.device().wakeUp();
+ mLogger.method("ensureScreenIsOn", () -> {
+ TestApis.device().wakeUp();
+ });
}
private void ensurePasswordSet(UserType forUser, String password) {
- UserReference user = resolveUserTypeToUser(forUser);
+ mLogger.method("ensurePasswordSet", forUser, password, () -> {
+ UserReference user = resolveUserTypeToUser(forUser);
- if (user.hasPassword()) {
- return;
- }
+ if (user.hasPassword()) {
+ return;
+ }
- try {
- user.setPassword(password);
- } catch (NeneException e) {
- throw new AssertionError("Require password set but error when setting password", e);
- }
- mUsersSetPasswords.add(user);
+ try {
+ user.setPassword(password);
+ } catch (NeneException e) {
+ throw new AssertionError("Require password set but error when setting "
+ + "password on user " + user, e);
+ }
+ mUsersSetPasswords.add(user);
+ });
}
private void ensurePasswordNotSet(UserType forUser) {
- UserReference user = resolveUserTypeToUser(forUser);
+ mLogger.method("ensurePasswordNotSet", forUser, () -> {
+ UserReference user = resolveUserTypeToUser(forUser);
- if (!user.hasPassword()) {
- return;
- }
+ if (!user.hasPassword()) {
+ return;
+ }
- try {
- user.clearPassword(DEFAULT_PASSWORD);
- } catch (NeneException e
- ) {
- throw new AssertionError(
- "Test requires user " + user + " does not have a password. "
- + "Password is set and is not DEFAULT_PASSWORD.");
- }
- mUsersSetPasswords.remove(user);
+ try {
+ user.clearPassword(DEFAULT_PASSWORD);
+ } catch (NeneException e
+ ) {
+ throw new AssertionError(
+ "Test requires user " + user + " does not have a password. "
+ + "Password is set and is not DEFAULT_PASSWORD.");
+ }
+ mUsersSetPasswords.remove(user);
+ });
}
private void ensureBluetoothEnabled() {
- if (mOriginalBluetoothEnabled == null) {
- mOriginalBluetoothEnabled = TestApis.bluetooth().isEnabled();
- }
- TestApis.bluetooth().setEnabled(true);
+ mLogger.method("ensureBluetoothEnabled", () -> {
+ if (mOriginalBluetoothEnabled == null) {
+ mOriginalBluetoothEnabled = TestApis.bluetooth().isEnabled();
+ }
+ TestApis.bluetooth().setEnabled(true);
+ });
}
private void ensureBluetoothDisabled() {
- if (mOriginalBluetoothEnabled == null) {
- mOriginalBluetoothEnabled = TestApis.bluetooth().isEnabled();
- }
- TestApis.bluetooth().setEnabled(false);
+ mLogger.method("ensureBluetoothDisabled", () -> {
+ if (mOriginalBluetoothEnabled == null) {
+ mOriginalBluetoothEnabled = TestApis.bluetooth().isEnabled();
+ }
+ TestApis.bluetooth().setEnabled(false);
+ });
}
}
diff --git a/common/device-side/bedstead/nene/common/src/main/java/com/android/bedstead/nene/logging/CommonLogger.java b/common/device-side/bedstead/nene/common/src/main/java/com/android/bedstead/nene/logging/CommonLogger.java
new file mode 100644
index 0000000..7bf2a5e
--- /dev/null
+++ b/common/device-side/bedstead/nene/common/src/main/java/com/android/bedstead/nene/logging/CommonLogger.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.nene.logging;
+
+import java.util.function.Supplier;
+
+/**
+ * Methods used for logging.
+ */
+public interface CommonLogger {
+
+ interface RunnableThrows<T extends Throwable> {
+ void run() throws T;
+ }
+
+ interface SupplierThrows<V, T extends Throwable> {
+ V get() throws T;
+ }
+
+ void constructor(Runnable method);
+ void constructor(Object... args);
+ void constructor(Object arg1, Runnable method);
+ void constructor(Object arg1, Object arg2, Runnable method);
+ void constructor(Object arg1, Object arg2, Object arg3, Runnable method);
+ void constructor(Object arg1, Object arg2, Object arg3, Object arg4, Runnable method);
+ void constructor(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Runnable method);
+ void constructor(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Runnable method);
+ void constructor(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Runnable method);
+
+ void method(String name, Runnable method);
+ void method(String name, Object arg1, Runnable method);
+ void method(String name, Object arg1, Object arg2, Runnable method);
+ void method(String name, Object arg1, Object arg2, Object arg3, Runnable method);
+ void method(String name, Object arg1, Object arg2, Object arg3, Object arg4, Runnable method);
+ void method(String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Runnable method);
+ void method(String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Runnable method);
+ void method(String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Runnable method);
+
+ <T extends Throwable> void method(Class<T> throwableClass, String name, RunnableThrows<T> method) throws T;
+ <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1, RunnableThrows<T> method) throws T;
+ <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1, Object arg2, RunnableThrows<T> method) throws T;
+ <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1, Object arg2, Object arg3, RunnableThrows<T> method) throws T;
+ <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1, Object arg2, Object arg3, Object arg4, RunnableThrows<T> method) throws T;
+ <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, RunnableThrows<T> method) throws T;
+ <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, RunnableThrows<T> method) throws T;
+ <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, RunnableThrows<T> method) throws T;
+
+ <R> R method(String name, Supplier<R> method);
+ <R> R method(String name, Object arg1, Supplier<R> method);
+ <R> R method(String name, Object arg1, Object arg2, Supplier<R> method);
+ <R> R method(String name, Object arg1, Object arg2, Object arg3, Supplier<R> method);
+ <R> R method(String name, Object arg1, Object arg2, Object arg3, Object arg4, Supplier<R> method);
+ <R> R method(String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Supplier<R> method);
+ <R> R method(String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Supplier<R> method);
+ <R> R method(String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Supplier<R> method);
+
+ <T extends Throwable, R> R method(Class<T> throwableClass, String name, SupplierThrows<R, T> method) throws T;
+ <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1, SupplierThrows<R, T> method) throws T;
+ <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1, Object arg2, SupplierThrows<R, T> method) throws T;
+ <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1, Object arg2, Object arg3, SupplierThrows<R, T> method) throws T;
+ <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1, Object arg2, Object arg3, Object arg4, SupplierThrows<R, T> method) throws T;
+ <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, SupplierThrows<R, T> method) throws T;
+ <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, SupplierThrows<R, T> method) throws T;
+ <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, SupplierThrows<R, T> method) throws T;
+}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/TestApis.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/TestApis.java
index 5a4cf4e..7fa094f 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/TestApis.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/TestApis.java
@@ -24,6 +24,7 @@
import com.android.bedstead.nene.device.Device;
import com.android.bedstead.nene.devicepolicy.DevicePolicy;
import com.android.bedstead.nene.inputmethods.InputMethods;
+import com.android.bedstead.nene.instrumentation.Instrumentation;
import com.android.bedstead.nene.location.Locations;
import com.android.bedstead.nene.notifications.Notifications;
import com.android.bedstead.nene.packages.Packages;
@@ -111,6 +112,12 @@
return InputMethods.sInstance;
}
+ /** Access Test APIs related to instrumentation. */
+ @Experimental
+ public static Instrumentation instrumentation() {
+ return Instrumentation.sInstance;
+ }
+
/** @deprecated Use statically */
@Deprecated()
public TestApis() {
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/accessibility/Accessibility.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/accessibility/Accessibility.java
index bf3e235..1df7804 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/accessibility/Accessibility.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/accessibility/Accessibility.java
@@ -22,6 +22,7 @@
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.annotations.Experimental;
+import com.android.bedstead.nene.logging.Logger;
import java.util.Set;
import java.util.stream.Collectors;
@@ -35,8 +36,10 @@
private static final AccessibilityManager sAccessibilityManager =
TestApis.context().instrumentedContext().getSystemService(AccessibilityManager.class);
- private Accessibility() {
+ private final Logger mLogger = Logger.forInstance(this);
+ private Accessibility() {
+ mLogger.constructor();
}
/**
@@ -45,10 +48,11 @@
* <p>See {@link AccessibilityManager#getInstalledAccessibilityServiceList()}.
*/
public Set<AccessibilityService> installedAccessibilityServices() {
- return sAccessibilityManager
- .getInstalledAccessibilityServiceList().stream()
- .map(AccessibilityService::new)
- .collect(Collectors.toSet());
+ return mLogger.method("installedAccessibilityServices", () ->
+ sAccessibilityManager
+ .getInstalledAccessibilityServiceList().stream()
+ .map(AccessibilityService::new)
+ .collect(Collectors.toSet()));
}
/**
@@ -57,9 +61,10 @@
* <p>See {@link AccessibilityManager#getEnabledAccessibilityServiceList(int)}.
*/
public Set<AccessibilityService> enabledAccessibilityServices() {
- return sAccessibilityManager
- .getEnabledAccessibilityServiceList(FEEDBACK_ALL_MASK)
- .stream().map(AccessibilityService::new)
- .collect(Collectors.toSet());
+ return mLogger.method("enabledAccessibilityServices", () ->
+ sAccessibilityManager
+ .getEnabledAccessibilityServiceList(FEEDBACK_ALL_MASK)
+ .stream().map(AccessibilityService::new)
+ .collect(Collectors.toSet()));
}
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/accessibility/AccessibilityService.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/accessibility/AccessibilityService.java
index 834f3aa..e85b7a5 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/accessibility/AccessibilityService.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/accessibility/AccessibilityService.java
@@ -19,6 +19,7 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.logging.Logger;
import com.android.bedstead.nene.packages.Package;
/**
@@ -26,14 +27,18 @@
*/
public final class AccessibilityService {
- private final AccessibilityServiceInfo mServiceInfo;
+ private AccessibilityServiceInfo mServiceInfo;
+ private final Logger mLogger = Logger.forInstance(this);
AccessibilityService(AccessibilityServiceInfo serviceInfo) {
- mServiceInfo = serviceInfo;
+ mLogger.constructor(serviceInfo, () -> {
+ mServiceInfo = serviceInfo;
+ });
}
/** The package of the accessibility service. */
public Package pkg() {
- return TestApis.packages().find(mServiceInfo.getResolveInfo().serviceInfo.packageName);
+ return mLogger.method("pkg", () ->
+ TestApis.packages().find(mServiceInfo.getResolveInfo().serviceInfo.packageName));
}
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java
index 1a8e578..aeabf3d 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java
@@ -32,6 +32,7 @@
import android.content.Intent;
import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.logging.Logger;
import com.android.bedstead.nene.permissions.PermissionContext;
import com.android.bedstead.nene.utils.Poll;
import com.android.compatibility.common.util.BlockingBroadcastReceiver;
@@ -46,86 +47,98 @@
sContext.getSystemService(BluetoothManager.class);
private static final BluetoothAdapter sBluetoothAdapter = sBluetoothManager.getAdapter();
- private Bluetooth() {
+ private final Logger mLogger = Logger.forInstance(this);
+ private Bluetooth() {
+ mLogger.constructor();
}
/** Enable or disable bluetooth on the device. */
public void setEnabled(boolean enabled) {
- if (isEnabled() == enabled) {
- return;
- }
+ mLogger.method("setEnabled", enabled, () -> {
+ if (isEnabled() == enabled) {
+ return;
+ }
- if (enabled) {
- enable();
- } else {
- disable();
- }
+ if (enabled) {
+ enable();
+ } else {
+ disable();
+ }
+ });
}
private void enable() {
- try (PermissionContext p =
- TestApis.permissions()
- .withPermission(BLUETOOTH_CONNECT, INTERACT_ACROSS_USERS_FULL)
- .withPermissionOnVersionAtLeast(T, NETWORK_SETTINGS)) {
- BlockingBroadcastReceiver r = BlockingBroadcastReceiver.create(
- sContext,
- BluetoothAdapter.ACTION_STATE_CHANGED,
- this::isStateEnabled).register();
+ mLogger.method("enable", () -> {
+ try (PermissionContext p =
+ TestApis.permissions()
+ .withPermission(BLUETOOTH_CONNECT, INTERACT_ACROSS_USERS_FULL)
+ .withPermissionOnVersionAtLeast(T, NETWORK_SETTINGS)) {
+ BlockingBroadcastReceiver r = BlockingBroadcastReceiver.create(
+ sContext,
+ BluetoothAdapter.ACTION_STATE_CHANGED,
+ this::isStateEnabled).register();
- try {
- assertThat(sBluetoothAdapter.enable()).isTrue();
+ try {
+ assertThat(sBluetoothAdapter.enable()).isTrue();
- r.awaitForBroadcast();
- Poll.forValue("Bluetooth Enabled", this::isEnabled)
- .toBeEqualTo(true)
- .errorOnFail()
- .await();
- } finally {
- r.unregisterQuietly();
+ r.awaitForBroadcast();
+ Poll.forValue("Bluetooth Enabled", this::isEnabled)
+ .toBeEqualTo(true)
+ .errorOnFail()
+ .await();
+ } finally {
+ r.unregisterQuietly();
+ }
}
- }
+ });
}
private void disable() {
- try (PermissionContext p =
- TestApis.permissions()
- .withPermission(BLUETOOTH_CONNECT, INTERACT_ACROSS_USERS_FULL)
- .withPermissionOnVersionAtLeast(T, NETWORK_SETTINGS)) {
- BlockingBroadcastReceiver r = BlockingBroadcastReceiver.create(
- sContext,
- BluetoothAdapter.ACTION_STATE_CHANGED,
- this::isStateDisabled).register();
+ mLogger.method("disable", () -> {
+ try (PermissionContext p =
+ TestApis.permissions()
+ .withPermission(BLUETOOTH_CONNECT, INTERACT_ACROSS_USERS_FULL)
+ .withPermissionOnVersionAtLeast(T, NETWORK_SETTINGS)) {
+ BlockingBroadcastReceiver r = BlockingBroadcastReceiver.create(
+ sContext,
+ BluetoothAdapter.ACTION_STATE_CHANGED,
+ this::isStateDisabled).register();
- try {
- assertThat(sBluetoothAdapter.disable()).isTrue();
+ try {
+ assertThat(sBluetoothAdapter.disable()).isTrue();
- r.awaitForBroadcast();
- Poll.forValue("Bluetooth Enabled", this::isEnabled)
- .toBeEqualTo(false)
- .errorOnFail()
- .await();
- } finally {
- r.unregisterQuietly();
+ r.awaitForBroadcast();
+ Poll.forValue("Bluetooth Enabled", this::isEnabled)
+ .toBeEqualTo(false)
+ .errorOnFail()
+ .await();
+ } finally {
+ r.unregisterQuietly();
+ }
}
- }
+ });
}
/** {@code true} if bluetooth is enabled. */
public boolean isEnabled() {
- try (PermissionContext p =
- TestApis.permissions().withPermissionOnVersionAtMost(R, BLUETOOTH)) {
- return sBluetoothAdapter.isEnabled();
- }
+ return mLogger.method("isEnabled", () -> {
+ try (PermissionContext p =
+ TestApis.permissions().withPermissionOnVersionAtMost(R, BLUETOOTH)) {
+ return sBluetoothAdapter.isEnabled();
+ }
+ });
}
private boolean isStateEnabled(Intent intent) {
- return intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)
- == BluetoothAdapter.STATE_ON;
+ return mLogger.method("isStateEnabled", intent, () ->
+ intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)
+ == BluetoothAdapter.STATE_ON);
}
private boolean isStateDisabled(Intent intent) {
- return intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)
- == BluetoothAdapter.STATE_OFF;
+ return mLogger.method("isStateDisabled", intent, () ->
+ intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)
+ == BluetoothAdapter.STATE_OFF);
}
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/DeviceOwner.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/DeviceOwner.java
index 24bbaee..b88c054 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/DeviceOwner.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/DeviceOwner.java
@@ -146,6 +146,7 @@
Poll.forValue(() -> dpm.isRemovingAdmin(mComponentName, mUser.id()))
.toNotBeEqualTo(true)
+ .timeout(Duration.ofMinutes(5))
.errorOnFail()
.await();
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/DevicePolicy.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/DevicePolicy.java
index dd6a3e9..528d532 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/DevicePolicy.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/DevicePolicy.java
@@ -21,6 +21,7 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.os.Build.VERSION.SDK_INT;
+import static com.android.bedstead.nene.permissions.CommonPermissions.FORCE_DEVICE_POLICY_MANAGER_LOGS;
import static com.android.bedstead.nene.permissions.CommonPermissions.MANAGE_DEVICE_ADMINS;
import static com.android.bedstead.nene.permissions.CommonPermissions.MANAGE_PROFILE_AND_DEVICE_OWNERS;
@@ -47,12 +48,9 @@
import com.android.bedstead.nene.utils.ShellCommand;
import com.android.bedstead.nene.utils.ShellCommandUtils;
import com.android.bedstead.nene.utils.Versions;
-import com.android.compatibility.common.util.PollingCheck;
import java.time.Duration;
-import java.util.Arrays;
import java.util.Collection;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -99,7 +97,8 @@
return false; // Just retry on old versions as we don't have stderr
}
if (ex instanceof AdbException) {
- if (((AdbException) ex).error().contains("is being removed")) {
+ String error = ((AdbException) ex).error();
+ if (error.contains("is being removed")) {
return false;
}
}
@@ -173,17 +172,16 @@
// TODO(b/187925230): If it fails, we check for terminal failure states - and if not
// we retry because if the DO/PO was recently removed, it can take some time
// to be allowed to set it again
- retryIfNotTerminal(
- () -> {
+ Retry.logic(() -> {
devicePolicyManager.setActiveAdmin(deviceOwnerComponent,
/* refreshing= */ true, user.id());
setDeviceOwnerOnly(devicePolicyManager,
deviceOwnerComponent, "Nene", user.id());
- },
- () -> checkForTerminalDeviceOwnerFailures(
- user, deviceOwnerComponent, /* allowAdditionalUsers= */ true),
- NeneException.class, IllegalArgumentException.class);
- } catch (IllegalStateException | SecurityException e) {
+ }).terminalException((e) -> checkForTerminalDeviceOwnerFailures(
+ user, deviceOwnerComponent, /* allowAdditionalUsers= */ true))
+ .timeout(Duration.ofMinutes(5))
+ .run();
+ } catch (Throwable e) {
throw new NeneException("Error setting device owner", e);
}
} finally {
@@ -234,44 +232,6 @@
}
}
- /**
- * Runs {@code operation}. If it fails, runs {@code terminalCheck} and then retries
- * {@code operation} until it does not fail or for a maximum of 30 seconds.
- *
- * <p>The {@code operation} is considered to be successful if it does not throw an exception
- */
- private void retryIfNotTerminal(
- Runnable operation, Runnable terminalCheck,
- Class<? extends RuntimeException>... exceptions) {
- Set<Class<? extends RuntimeException>> exceptionSet =
- new HashSet<>(Arrays.asList(exceptions));
- try {
- operation.run();
- } catch (RuntimeException e) {
- if (!exceptionSet.contains(e.getClass())) {
- throw e;
- }
-
- terminalCheck.run();
-
- try {
- PollingCheck.waitFor(() -> {
- try {
- operation.run();
- return true;
- } catch (RuntimeException e2) {
- if (!exceptionSet.contains(e2.getClass())) {
- throw e2;
- }
- return false;
- }
- });
- } catch (AssertionError e3) {
- operation.run();
- }
- }
- }
-
private DeviceOwner setDeviceOwnerPreS(ComponentName deviceOwnerComponent) {
UserReference user = TestApis.users().system();
@@ -282,18 +242,23 @@
// TODO(b/187925230): If it fails, we check for terminal failure states - and if not
// we retry because if the device owner was recently removed, it can take some time
// to be allowed to set it again
- retryIfNotTerminal(
- () -> command.executeOrThrowNeneException("Could not set device owner for user "
- + user + " component " + deviceOwnerComponent),
- () -> checkForTerminalDeviceOwnerFailures(
- user, deviceOwnerComponent, /* allowAdditionalUsers= */ false));
+
+ try {
+ Retry.logic(command::execute)
+ .terminalException((e) -> checkForTerminalDeviceOwnerFailures(
+ user, deviceOwnerComponent, /* allowAdditionalUsers= */ false))
+ .timeout(Duration.ofMinutes(5))
+ .run();
+ } catch (Throwable e) {
+ throw new NeneException("Error setting device owner", e);
+ }
return new DeviceOwner(user,
TestApis.packages().find(
deviceOwnerComponent.getPackageName()), deviceOwnerComponent);
}
- private void checkForTerminalDeviceOwnerFailures(
+ private boolean checkForTerminalDeviceOwnerFailures(
UserReference user, ComponentName deviceOwnerComponent, boolean allowAdditionalUsers) {
DeviceOwner deviceOwner = getDeviceOwner();
if (deviceOwner != null) {
@@ -328,6 +293,8 @@
}
// TODO(scottjonathan): Check accounts
+
+ return false;
}
private boolean componentCanBeSetAsDeviceAdmin(ComponentName component, UserReference user) {
@@ -390,4 +357,28 @@
.getPolicyExemptApps();
}
}
+
+ @Experimental
+ public void forceNetworkLogs() {
+ try (PermissionContext p = TestApis.permissions().withPermission(FORCE_DEVICE_POLICY_MANAGER_LOGS)) {
+ long throttle = TestApis.context()
+ .instrumentedContext()
+ .getSystemService(DevicePolicyManager.class)
+ .forceNetworkLogs();
+
+ if (throttle == -1) {
+ throw new NeneException("Error forcing network logs: returned -1");
+ }
+ if (throttle == 0) {
+ return;
+ }
+ try {
+ Thread.sleep(throttle);
+ } catch (InterruptedException e) {
+ throw new NeneException("Error waiting for network log throttle", e);
+ }
+
+ forceNetworkLogs();
+ }
+ }
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java
index a259203..ce73f43 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java
@@ -138,6 +138,7 @@
Poll.forValue(() -> dpm.isRemovingAdmin(mComponentName, mUser.id()))
.toNotBeEqualTo(true)
+ .timeout(Duration.ofMinutes(5))
.errorOnFail()
.await();
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/instrumentation/Arguments.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/instrumentation/Arguments.java
new file mode 100644
index 0000000..8a4578a
--- /dev/null
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/instrumentation/Arguments.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.nene.instrumentation;
+
+import android.os.Bundle;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+/** Access to Instrumentation Arguments. */
+public final class Arguments {
+
+ public static final Arguments sInstance = new Arguments();
+
+ private final Bundle mArguments = InstrumentationRegistry.getArguments();
+
+ private Arguments() {
+ }
+
+ /** Gets int instrumentation arg. */
+ public int getInt(String key) {
+ return mArguments.getInt(key);
+ }
+
+ /** Gets int instrumentation arg. */
+ public int getInt(String key, int defaultValue) {
+ return mArguments.getInt(key, defaultValue);
+ }
+
+ /** Gets boolean instrumentation arg. */
+ public boolean getBoolean(String key) {
+ return mArguments.getBoolean(key);
+ }
+
+ /** Gets boolean instrumentation arg. */
+ public boolean getBoolean(String key, boolean defaultValue) {
+ return mArguments.getBoolean(key, defaultValue);
+ }
+
+ /** Gets string instrumentation arg. */
+ public String getString(String key) {
+ return mArguments.getString(key);
+ }
+
+ /** Gets string instrumentation arg. */
+ public String getString(String key, String defaultValue) {
+ return mArguments.getString(key, defaultValue);
+ }
+
+}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/instrumentation/Instrumentation.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/instrumentation/Instrumentation.java
new file mode 100644
index 0000000..1a0d4d1
--- /dev/null
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/instrumentation/Instrumentation.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.nene.instrumentation;
+
+/** Test APIs related to Instrumentation. */
+public final class Instrumentation {
+ public static final Instrumentation sInstance = new Instrumentation();
+
+ private Instrumentation() {
+
+ }
+
+ /** Interact with instrumentation arguments. */
+ public Arguments arguments() {
+ return Arguments.sInstance;
+ }
+}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/location/LocationProvider.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/location/LocationProvider.java
index 3551aae..7bddceb 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/location/LocationProvider.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/location/LocationProvider.java
@@ -16,8 +16,8 @@
package com.android.bedstead.nene.location;
-import static com.android.bedstead.nene.appops.AppOpsMode.ALLOWED;
import static com.android.bedstead.nene.appops.AppOpsMode.DEFAULT;
+import static com.android.bedstead.nene.appops.CommonAppOps.OPSTR_MOCK_LOCATION;
import android.app.AppOpsManager;
import android.content.Context;
@@ -27,6 +27,7 @@
import android.os.SystemClock;
import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.permissions.PermissionContext;
/** A test location provider on the device. */
public final class LocationProvider implements AutoCloseable {
@@ -49,18 +50,18 @@
}
private void addTestProvider() {
- // TODO(b/215671032): Allow app op to be adopted with permissions
- TestApis.packages().instrumented().appOps().set(AppOpsManager.OPSTR_MOCK_LOCATION, ALLOWED);
- sLocationManager.addTestProvider(sProviderName,
- /* requiresNetwork= */ true,
- /* requiresSatellite= */ false,
- /* requiresCell= */ true,
- /* hasMonetaryCost= */ false,
- /* supportsAltitude= */ false,
- /* supportsSpeed= */ false,
- /* supportsBearing= */ false,
- Criteria.POWER_MEDIUM,
- Criteria.ACCURACY_COARSE);
+ try (PermissionContext p = TestApis.permissions().withAppOp(OPSTR_MOCK_LOCATION)) {
+ sLocationManager.addTestProvider(sProviderName,
+ /* requiresNetwork= */ true,
+ /* requiresSatellite= */ false,
+ /* requiresCell= */ true,
+ /* hasMonetaryCost= */ false,
+ /* supportsAltitude= */ false,
+ /* supportsSpeed= */ false,
+ /* supportsBearing= */ false,
+ Criteria.POWER_MEDIUM,
+ Criteria.ACCURACY_COARSE);
+ }
}
private void enableTestProvider() {
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/logging/AdbLogger.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/logging/AdbLogger.java
new file mode 100644
index 0000000..fa15935
--- /dev/null
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/logging/AdbLogger.java
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.nene.logging;
+
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+/**
+ * {@link Logger} which passes all logs to ADB.
+ */
+public final class AdbLogger implements Logger {
+
+ public static final String KEY = "ADB";
+
+ private final String mTag;
+
+ AdbLogger(Object instance) {
+ mTag = "NNL_" + instance.getClass().getCanonicalName() + "@"
+ + Integer.toHexString(instance.hashCode());
+ }
+
+ @Override
+ public void constructor(Runnable method) {
+ constructor(method, new Object[]{});
+ }
+
+ @Override
+ public void constructor(Object... args) {
+ constructor(() -> {}, args);
+ }
+
+ @Override
+ public void constructor(Object arg1, Runnable method) {
+ constructor(method, arg1);
+ }
+
+ @Override
+ public void constructor(Object arg1, Object arg2, Runnable method) {
+ constructor(method, arg1, arg2);
+ }
+
+ @Override
+ public void constructor(Object arg1, Object arg2, Object arg3, Runnable method) {
+ constructor(method, arg1, arg2, arg3);
+ }
+
+ @Override
+ public void constructor(Object arg1, Object arg2, Object arg3, Object arg4, Runnable method) {
+ constructor(method, arg1, arg2, arg3, arg4);
+ }
+
+ @Override
+ public void constructor(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5,
+ Runnable method) {
+ constructor(method, arg1, arg2, arg3, arg4, arg5);
+ }
+
+ @Override
+ public void constructor(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5,
+ Object arg6, Runnable method) {
+ constructor(method, arg1, arg2, arg3, arg4, arg5, arg6);
+ }
+
+ @Override
+ public void constructor(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5,
+ Object arg6, Object arg7, Runnable method) {
+ constructor(method, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ }
+
+ private void constructor(Runnable method, Object... args) {
+ begin("constructor", args);
+ try {
+ method.run();
+ end();
+ } catch (Throwable t) {
+ exception(t);
+ throw t;
+ }
+ }
+
+ @Override
+ public void method(String name, Runnable method) {
+ method(method, name);
+ }
+
+ @Override
+ public void method(String name, Object arg1, Runnable method) {
+ method(method, name, arg1);
+ }
+
+ @Override
+ public void method(String name, Object arg1, Object arg2, Runnable method) {
+ method(method, name, arg1, arg2);
+ }
+
+ @Override
+ public void method(String name, Object arg1, Object arg2, Object arg3, Runnable method) {
+ method(method, name, arg1, arg2, arg3);
+ }
+
+ @Override
+ public void method(String name, Object arg1, Object arg2, Object arg3, Object arg4,
+ Runnable method) {
+ method(method, name, arg1, arg2, arg3, arg4);
+ }
+
+ @Override
+ public void method(String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5,
+ Runnable method) {
+ method(method, name, arg1, arg2, arg3, arg4, arg5);
+ }
+
+ @Override
+ public void method(String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5,
+ Object arg6, Runnable method) {
+ method(method, name, arg1, arg2, arg3, arg4, arg5, arg6);
+ }
+
+ @Override
+ public void method(String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5,
+ Object arg6, Object arg7, Runnable method) {
+ method(method, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name,
+ RunnableThrows<T> method) throws T {
+ method(method, name);
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1,
+ RunnableThrows<T> method) throws T {
+ method(method, name, arg1);
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, RunnableThrows<T> method) throws T {
+ method(method, name, arg1, arg2);
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, RunnableThrows<T> method) throws T {
+ method(method, name, arg1, arg2, arg3);
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, RunnableThrows<T> method) throws T {
+ method(method, name, arg1, arg2, arg3, arg4);
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, Object arg5, RunnableThrows<T> method) throws T {
+ method(method, name, arg1, arg2, arg3, arg4, arg5);
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, Object arg5, Object arg6,
+ RunnableThrows<T> method) throws T {
+ method(method, name, arg1, arg2, arg3, arg4, arg5, arg6);
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7,
+ RunnableThrows<T> method) throws T {
+ method(method, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ }
+
+ private void method(Runnable method, String name, Object... args) {
+ begin(name, args);
+ try {
+ method.run();
+ end();
+ } catch (Throwable t) {
+ exception(t);
+ throw t;
+ }
+ }
+
+ private <T extends Throwable> void method(
+ RunnableThrows<T> method, String name, Object... args) throws T {
+ begin(name, args);
+ try {
+ method.run();
+ end();
+ } catch (Throwable t) {
+ exception(t);
+ throw t;
+ }
+ }
+
+ @Override
+ public <R> R method(String name, Supplier<R> method) {
+ return method(method, name);
+ }
+
+ @Override
+ public <R> R method(String name, Object arg1, Supplier<R> method) {
+ return method(method, name, arg1);
+ }
+
+ @Override
+ public <R> R method(String name, Object arg1, Object arg2, Supplier<R> method) {
+ return method(method, name, arg1, arg2);
+ }
+
+ @Override
+ public <R> R method(String name, Object arg1, Object arg2, Object arg3, Supplier<R> method) {
+ return method(method, name, arg1, arg2, arg3);
+ }
+
+ @Override
+ public <R> R method(String name, Object arg1, Object arg2, Object arg3, Object arg4,
+ Supplier<R> method) {
+ return method(method, name, arg1, arg2, arg3, arg4);
+ }
+
+ @Override
+ public <R> R method(String name, Object arg1, Object arg2, Object arg3, Object arg4,
+ Object arg5, Supplier<R> method) {
+ return method(method, name, arg1, arg2, arg3, arg4, arg5);
+ }
+
+ @Override
+ public <R> R method(String name, Object arg1, Object arg2, Object arg3, Object arg4,
+ Object arg5, Object arg6, Supplier<R> method) {
+ return method(method, name, arg1, arg2, arg3, arg4, arg5, arg6);
+ }
+
+ @Override
+ public <R> R method(String name, Object arg1, Object arg2, Object arg3, Object arg4,
+ Object arg5, Object arg6, Object arg7, Supplier<R> method) {
+ return method(method, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name,
+ SupplierThrows<R, T> method) throws T {
+ return method(method, name);
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1,
+ SupplierThrows<R, T> method) throws T {
+ return method(method, name, arg1);
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, SupplierThrows<R, T> method) throws T {
+ return method(method, name, arg1, arg2);
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, SupplierThrows<R, T> method) throws T {
+ return method(method, name, arg1, arg2, arg3);
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, SupplierThrows<R, T> method) throws T {
+ return method(method, name, arg1, arg2, arg3, arg4);
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, Object arg5, SupplierThrows<R, T> method)
+ throws T {
+ return method(method, name, arg1, arg2, arg3, arg4, arg5);
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, Object arg5, Object arg6,
+ SupplierThrows<R, T> method) throws T {
+ return method(method, name, arg1, arg2, arg3, arg4, arg5, arg6);
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7,
+ SupplierThrows<R, T> method) throws T {
+ return method(method, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ }
+
+ private <R> R method(Supplier<R> method, String name, Object... args) {
+ begin(name, args);
+ try {
+ R value = method.get();
+ end(value);
+ return value;
+ } catch (Throwable t) {
+ exception(t);
+ throw t;
+ }
+ }
+
+ private <R, T extends Throwable> R method(
+ SupplierThrows<R, T> method, String name, Object... args) throws T {
+ begin(name, args);
+ try {
+ R value = method.get();
+ end(value);
+ return value;
+ } catch (Throwable t) {
+ exception(t);
+ throw t;
+ }
+ }
+
+ private void begin(String title, Object... args) {
+ Log.i(mTag, "BEGIN " + title + formatArgs(args));
+ }
+
+ private void exception(Throwable t) {
+ Log.i(mTag, "END EXCEPTION (" + t + ")");
+ }
+
+ private void end(Object ret) {
+ Log.i(mTag, "END (" + ret + ")");
+ }
+
+ private void end() {
+ Log.i(mTag, "END");
+ }
+
+ private String formatArgs(Object[] args) {
+ if (args.length == 0) {
+ return "";
+ }
+
+ return " (" + Arrays.stream(args).map(Object::toString)
+ .collect(Collectors.joining(", ")) + ")";
+ }
+}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/logging/Logger.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/logging/Logger.java
new file mode 100644
index 0000000..44a5df3e
--- /dev/null
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/logging/Logger.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.nene.logging;
+
+import com.android.bedstead.nene.TestApis;
+
+import java.util.function.Function;
+
+/**
+ * Logger used for tests and test infrastructure.
+ *
+ * <p>By default, logs will be dropped silently.
+ *
+ * <p>To change this, pass the LOGGING instrumentation argument.
+ *
+ * <p>E.g. {@code -- --instrumentation-arg LOGGING ADB} to log to ADB.
+ */
+public interface Logger extends CommonLogger {
+
+ /**
+ * The key to use to pass in the type of logger to use.
+ *
+ * <p>Defaults to silently dropping logs.
+ */
+ String LOGGER_KEY = "LOGGER";
+
+ Function<Object, Logger> LOG_CONSTRUCTOR =
+ TestApis.instrumentation().arguments().getString(LOGGER_KEY, "")
+ .equals(AdbLogger.KEY) ? AdbLogger::new : (object) -> VoidLogger.sInstance;
+
+ /** Create a {@link Logger} for the given object. */
+ static Logger forInstance(Object object) {
+ return LOG_CONSTRUCTOR.apply(object);
+ }
+}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/logging/VoidLogger.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/logging/VoidLogger.java
new file mode 100644
index 0000000..53ff8a0
--- /dev/null
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/logging/VoidLogger.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.nene.logging;
+
+import java.util.function.Supplier;
+
+/**
+ * {@link Logger} which drops all logs.
+ */
+public final class VoidLogger implements Logger {
+
+ public static final VoidLogger sInstance = new VoidLogger();
+
+ private VoidLogger() {
+
+ }
+
+ @Override
+ public void constructor(Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public void constructor(Object... args) {
+
+ }
+
+ @Override
+ public void constructor(Object arg1, Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public void constructor(Object arg1, Object arg2, Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public void constructor(Object arg1, Object arg2, Object arg3, Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public void constructor(Object arg1, Object arg2, Object arg3, Object arg4, Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public void constructor(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5,
+ Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public void constructor(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5,
+ Object arg6, Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public void constructor(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5,
+ Object arg6, Object arg7, Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public void method(String name, Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public void method(String name, Object arg1, Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public void method(String name, Object arg1, Object arg2, Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public void method(String name, Object arg1, Object arg2, Object arg3, Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public void method(String name, Object arg1, Object arg2, Object arg3, Object arg4,
+ Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public void method(String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5,
+ Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public void method(String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5,
+ Object arg6, Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public void method(String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5,
+ Object arg6, Object arg7, Runnable method) {
+ method.run();
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name,
+ RunnableThrows<T> method) throws T {
+ method.run();
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1,
+ RunnableThrows<T> method) throws T {
+ method.run();
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, RunnableThrows<T> method) throws T {
+ method.run();
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, RunnableThrows<T> method) throws T {
+ method.run();
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, RunnableThrows<T> method) throws T {
+ method.run();
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, Object arg5, RunnableThrows<T> method) throws T {
+ method.run();
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, Object arg5, Object arg6,
+ RunnableThrows<T> method) throws T {
+ method.run();
+ }
+
+ @Override
+ public <T extends Throwable> void method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7,
+ RunnableThrows<T> method) throws T {
+ method.run();
+ }
+
+ @Override
+ public <R> R method(String name, Supplier<R> method) {
+ return method.get();
+ }
+
+ @Override
+ public <R> R method(String name, Object arg1, Supplier<R> method) {
+ return method.get();
+ }
+
+ @Override
+ public <R> R method(String name, Object arg1, Object arg2, Supplier<R> method) {
+ return method.get();
+ }
+
+ @Override
+ public <R> R method(String name, Object arg1, Object arg2, Object arg3, Supplier<R> method) {
+ return method.get();
+ }
+
+ @Override
+ public <R> R method(String name, Object arg1, Object arg2, Object arg3, Object arg4,
+ Supplier<R> method) {
+ return method.get();
+ }
+
+ @Override
+ public <R> R method(String name, Object arg1, Object arg2, Object arg3, Object arg4,
+ Object arg5, Supplier<R> method) {
+ return method.get();
+ }
+
+ @Override
+ public <R> R method(String name, Object arg1, Object arg2, Object arg3, Object arg4,
+ Object arg5, Object arg6, Supplier<R> method) {
+ return method.get();
+ }
+
+ @Override
+ public <R> R method(String name, Object arg1, Object arg2, Object arg3, Object arg4,
+ Object arg5, Object arg6, Object arg7, Supplier<R> method) {
+ return method.get();
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name,
+ SupplierThrows<R, T> method) throws T {
+ return method.get();
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1,
+ SupplierThrows<R, T> method) throws T {
+ return method.get();
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, SupplierThrows<R, T> method) throws T {
+ return method.get();
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, SupplierThrows<R, T> method) throws T {
+ return method.get();
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, SupplierThrows<R, T> method) throws T {
+ return method.get();
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, Object arg5, SupplierThrows<R, T> method)
+ throws T {
+ return method.get();
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, Object arg5, Object arg6,
+ SupplierThrows<R, T> method) throws T {
+ return method.get();
+ }
+
+ @Override
+ public <T extends Throwable, R> R method(Class<T> throwableClass, String name, Object arg1,
+ Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7,
+ SupplierThrows<R, T> method) throws T {
+ return method.get();
+ }
+}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Poll.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Poll.java
index d687ab9..6592463 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Poll.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Poll.java
@@ -60,7 +60,7 @@
private static final String LOG_TAG = Poll.class.getName();
private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(30);
- private static final long SLEEP_MILLIS = 200;
+ private static final long SLEEP_MILLIS = 200; // TODO(b/223768343): Allow configuring
private final String mValueName;
private final ValueSupplier<E> mSupplier;
private ValueChecker<E> mChecker = (v) -> true;
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Retry.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Retry.java
index cb44d26..8038795 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Retry.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Retry.java
@@ -16,6 +16,8 @@
package com.android.bedstead.nene.utils;
+import android.util.Log;
+
import com.android.bedstead.nene.exceptions.NeneException;
import com.android.bedstead.nene.exceptions.PollValueFailedException;
@@ -35,6 +37,8 @@
*/
public final class Retry<E> {
+ private static final String LOG_TAG = "Retry";
+
private final Poll<E> mPoll;
/**
@@ -86,6 +90,7 @@
return mPoll.await();
} catch (PollValueFailedException e) {
// We know there will be an exception cause because we aren't validating the value
+ Log.e(LOG_TAG, "Failure in retries", e);
throw e.getCause();
}
}
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/info/DelegatedAdminReceiverInfo.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/info/DelegatedAdminReceiverInfo.java
new file mode 100644
index 0000000..f4f78e7
--- /dev/null
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/info/DelegatedAdminReceiverInfo.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.queryable.info;
+
+import android.app.admin.DelegatedAdminReceiver;
+
+/**
+ * Wrapper for information about a {@link DelegatedAdminReceiver}.
+ *
+ * <p>This is used instead of {@link DelegatedAdminReceiver} so that it can be easily serialized.
+ */
+@SuppressWarnings("NewApi")
+public class DelegatedAdminReceiverInfo extends BroadcastReceiverInfo {
+ public DelegatedAdminReceiverInfo(DelegatedAdminReceiver delegatedAdminReceiver) {
+ super(delegatedAdminReceiver);
+ }
+
+ public DelegatedAdminReceiverInfo(
+ Class<? extends DelegatedAdminReceiver> delegatedAdminReceiverClass) {
+ super(delegatedAdminReceiverClass);
+ }
+
+ public DelegatedAdminReceiverInfo(String delegatedAdminReceiverClassName) {
+ super(delegatedAdminReceiverClassName);
+ }
+
+ @Override
+ public String toString() {
+ return "DelegatedAdminReceiver{"
+ + "broadcastReceiver=" + super.toString()
+ + "}";
+ }
+}
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/DelegatedAdminReceiverQuery.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/DelegatedAdminReceiverQuery.java
new file mode 100644
index 0000000..0e5098b
--- /dev/null
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/DelegatedAdminReceiverQuery.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.queryable.queries;
+
+import android.app.admin.DelegatedAdminReceiver;
+
+import com.android.queryable.Queryable;
+import com.android.queryable.info.DelegatedAdminReceiverInfo;
+
+/** Query for a {@link DelegatedAdminReceiver}. */
+public interface DelegatedAdminReceiverQuery<E extends Queryable>
+ extends Query<DelegatedAdminReceiverInfo> {
+
+ static DelegatedAdminReceiverQuery<DelegatedAdminReceiverQuery<?>> delegatedAdminReceiver() {
+ return new DelegatedAdminReceiverQueryHelper<>();
+ }
+
+ BroadcastReceiverQuery<E> broadcastReceiver();
+}
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/DelegatedAdminReceiverQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/DelegatedAdminReceiverQueryHelper.java
new file mode 100644
index 0000000..befdc77
--- /dev/null
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/DelegatedAdminReceiverQueryHelper.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.queryable.queries;
+
+import com.android.queryable.Queryable;
+import com.android.queryable.info.DelegatedAdminReceiverInfo;
+
+/** Implementation of {@link DelegatedAdminReceiverQuery}. */
+public final class DelegatedAdminReceiverQueryHelper<E extends Queryable>
+ implements DelegatedAdminReceiverQuery<E> {
+
+ private final E mQuery;
+ private final BroadcastReceiverQueryHelper<E> mBroadcastReceiverQueryHelper;
+
+ DelegatedAdminReceiverQueryHelper() {
+ mQuery = (E) this;
+ mBroadcastReceiverQueryHelper = new BroadcastReceiverQueryHelper<>(mQuery);
+ }
+
+ public DelegatedAdminReceiverQueryHelper(E query) {
+ mQuery = query;
+ mBroadcastReceiverQueryHelper = new BroadcastReceiverQueryHelper<>(query);
+ }
+
+ @Override
+ public BroadcastReceiverQuery<E> broadcastReceiver() {
+ return mBroadcastReceiverQueryHelper;
+ }
+
+ /** {@code true} if all filters are met by {@code value}. */
+ @Override
+ public boolean matches(DelegatedAdminReceiverInfo value) {
+ return mBroadcastReceiverQueryHelper.matches(value);
+ }
+
+ @Override
+ public String describeQuery(String fieldName) {
+ return Queryable.joinQueryStrings(
+ mBroadcastReceiverQueryHelper.describeQuery(fieldName + ".broadcastReceiver")
+ );
+ }
+}
diff --git a/common/device-side/bedstead/queryable/src/test/java/com/android/queryable/info/DelegatedAdminReceiverInfoTest.java b/common/device-side/bedstead/queryable/src/test/java/com/android/queryable/info/DelegatedAdminReceiverInfoTest.java
new file mode 100644
index 0000000..3e34752
--- /dev/null
+++ b/common/device-side/bedstead/queryable/src/test/java/com/android/queryable/info/DelegatedAdminReceiverInfoTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.queryable.info;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.admin.DelegatedAdminReceiver;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class DelegatedAdminReceiverInfoTest {
+
+ private static final Class<? extends DelegatedAdminReceiver> TEST_DEVICE_ADMIN_RECEIVER_CLASS =
+ DelegatedAdminReceiver.class;
+ private static final String TEST_DEVICE_ADMIN_RECEIVER_CLASS_NAME =
+ DelegatedAdminReceiver.class.getName();
+ private static final String TEST_DEVICE_ADMIN_RECEIVER_SIMPLE_NAME =
+ DelegatedAdminReceiver.class.getSimpleName();
+ private static final DelegatedAdminReceiver TEST_DEVICE_ADMIN_RECEIVER_INSTANCE =
+ new DelegatedAdminReceiver();
+
+ @Test
+ public void classConstructor_setsClassName() {
+ DelegatedAdminReceiverInfo delegatedAdminReceiverInfo = new DelegatedAdminReceiverInfo(
+ TEST_DEVICE_ADMIN_RECEIVER_CLASS);
+
+ assertThat(delegatedAdminReceiverInfo.className())
+ .isEqualTo(TEST_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+ }
+
+ @Test
+ public void instanceConstructor_setsClassName() {
+ DelegatedAdminReceiverInfo delegatedAdminReceiverInfo = new DelegatedAdminReceiverInfo(
+ TEST_DEVICE_ADMIN_RECEIVER_INSTANCE);
+
+ assertThat(delegatedAdminReceiverInfo.className())
+ .isEqualTo(TEST_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+ }
+
+ @Test
+ public void stringConstructor_setsClassName() {
+ DelegatedAdminReceiverInfo delegatedAdminReceiverInfo = new DelegatedAdminReceiverInfo(
+ TEST_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+
+ assertThat(delegatedAdminReceiverInfo.className())
+ .isEqualTo(TEST_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+ }
+
+ @Test
+ public void simpleName_getsSimpleName() {
+ DelegatedAdminReceiverInfo delegatedAdminReceiverInfo = new DelegatedAdminReceiverInfo(
+ TEST_DEVICE_ADMIN_RECEIVER_CLASS_NAME);
+
+ assertThat(delegatedAdminReceiverInfo.simpleName())
+ .isEqualTo(TEST_DEVICE_ADMIN_RECEIVER_SIMPLE_NAME);
+ }
+}
diff --git a/common/device-side/bedstead/testapp/CommonManifest.xml b/common/device-side/bedstead/testapp/CommonManifest.xml
index 836db22..c3232fa 100644
--- a/common/device-side/bedstead/testapp/CommonManifest.xml
+++ b/common/device-side/bedstead/testapp/CommonManifest.xml
@@ -140,7 +140,9 @@
<uses-permission android:name="android.permission.SET_PROCESS_LIMIT" />
<uses-permission android:name="android.permission.SET_ALWAYS_FINISH" />
<uses-permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES" />
- <uses-permission android:name="android.permission.ACCESS_SUPPLEMENTAL_APIS" />
+ <uses-permission android:name="android.permission.ACCESS_ADSERVICES_TOPICS" />
+ <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
+ <uses-permission android:name="android.permission.ACCESS_ADSERVICES_CUSTOM_AUDIENCES" />
<uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
@@ -193,4 +195,4 @@
android:exported="true" />
</application>
<uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28"/>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml b/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml
index 6740e5e..2dbab47 100644
--- a/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml
+++ b/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml
@@ -21,6 +21,16 @@
<application>
<!-- Don't allow this test app to be returned by queries unless filtered by package name -->
<meta-data android:name="testapp-package-query-only" android:value="true" />
+
+ <receiver android:name="com.android.bedstead.testapp.BaseTestAppDelegatedAdminReceiver"
+ android:permission="android.permission.BIND_DEVICE_ADMIN"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.app.action.CHOOSE_PRIVATE_KEY_ALIAS"/>
+ <action android:name="android.app.action.NETWORK_LOGS_AVAILABLE"/>
+ <action android:name="android.app.action.SECURITY_LOGS_AVAILABLE"/>
+ </intent-filter>
+ </receiver>
</application>
<uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28"/>
</manifest>
\ No newline at end of file
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java
index 966fb95..3c45313 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java
@@ -26,28 +26,50 @@
import com.android.eventlib.events.activities.ActivityStoppedEvent;
import com.android.eventlib.events.broadcastreceivers.BroadcastReceivedEvent;
import com.android.eventlib.events.broadcastreceivers.BroadcastReceiverEvents;
+import com.android.eventlib.events.delegatedadminreceivers.DelegatedAdminChoosePrivateKeyAliasEvent;
+import com.android.eventlib.events.delegatedadminreceivers.DelegatedAdminChoosePrivateKeyAliasEvent.DelegatedAdminChoosePrivateKeyAliasEventQuery;
+import com.android.eventlib.events.delegatedadminreceivers.DelegatedAdminReceiverEvents;
+import com.android.eventlib.events.delegatedadminreceivers.DelegatedAdminSecurityLogsAvailableEvent;
+import com.android.eventlib.events.delegatedadminreceivers.DelegatedAdminSecurityLogsAvailableEvent.DelegatedAdminSecurityLogsAvailableEventQuery;
+import com.android.eventlib.events.deviceadminreceivers.DelegatedAdminNetworkLogsAvailableEvent;
+import com.android.eventlib.events.deviceadminreceivers.DelegatedAdminNetworkLogsAvailableEvent.DelegatedAdminNetworkLogsAvailableEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminBugreportFailedEvent;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminBugreportSharedEvent;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminBugreportSharingDeclinedEvent;
+import com.android.eventlib.events.deviceadminreceivers.DeviceAdminBugreportSharingDeclinedEvent.DeviceAdminBugreportSharingDeclinedEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminChoosePrivateKeyAliasEvent;
+import com.android.eventlib.events.deviceadminreceivers.DeviceAdminChoosePrivateKeyAliasEvent.DeviceAdminChoosePrivateKeyAliasEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminDisableRequestedEvent;
+import com.android.eventlib.events.deviceadminreceivers.DeviceAdminDisableRequestedEvent.DeviceAdminDisableRequestedEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminDisabledEvent;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminEnabledEvent;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminLockTaskModeEnteringEvent;
+import com.android.eventlib.events.deviceadminreceivers.DeviceAdminLockTaskModeEnteringEvent.DeviceAdminLockTaskModeEnteringEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminLockTaskModeExitingEvent;
+import com.android.eventlib.events.deviceadminreceivers.DeviceAdminLockTaskModeExitingEvent.DeviceAdminLockTaskModeExitingEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminNetworkLogsAvailableEvent;
+import com.android.eventlib.events.deviceadminreceivers.DeviceAdminNetworkLogsAvailableEvent.DeviceAdminNetworkLogsAvailableEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminOperationSafetyStateChangedEvent;
+import com.android.eventlib.events.deviceadminreceivers.DeviceAdminOperationSafetyStateChangedEvent.DeviceAdminOperationSafetyStateChangedEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminPasswordChangedEvent;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminPasswordExpiringEvent;
+import com.android.eventlib.events.deviceadminreceivers.DeviceAdminPasswordExpiringEvent.DeviceAdminPasswordExpiringEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminPasswordFailedEvent;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminPasswordSucceededEvent;
+import com.android.eventlib.events.deviceadminreceivers.DeviceAdminPasswordSucceededEvent.DeviceAdminPasswordSucceededEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminProfileProvisioningCompleteEvent;
+import com.android.eventlib.events.deviceadminreceivers.DeviceAdminProfileProvisioningCompleteEvent.DeviceAdminProfileProvisioningCompleteEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminReadyForUserInitializationEvent;
+import com.android.eventlib.events.deviceadminreceivers.DeviceAdminReadyForUserInitializationEvent.DeviceAdminReadyForUserInitializationEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminReceiverEvents;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminSecurityLogsAvailableEvent;
+import com.android.eventlib.events.deviceadminreceivers.DeviceAdminSecurityLogsAvailableEvent.DeviceAdminSecurityLogsAvailableEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminSystemUpdatePendingEvent;
+import com.android.eventlib.events.deviceadminreceivers.DeviceAdminSystemUpdatePendingEvent.DeviceAdminSystemUpdatePendingEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent;
+import com.android.eventlib.events.deviceadminreceivers.DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminTransferOwnershipCompleteEvent;
+import com.android.eventlib.events.deviceadminreceivers.DeviceAdminTransferOwnershipCompleteEvent.DeviceAdminTransferOwnershipCompleteEventQuery;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminUserAddedEvent;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminUserRemovedEvent;
import com.android.eventlib.events.deviceadminreceivers.DeviceAdminUserStartedEvent;
@@ -73,7 +95,7 @@
* <p>{@code #poll} can be used to fetch results, and the result can be asserted on.
*/
public class TestAppEvents implements ActivityEvents, BroadcastReceiverEvents,
- DeviceAdminReceiverEvents, ServiceEvents {
+ DeviceAdminReceiverEvents, DelegatedAdminReceiverEvents, ServiceEvents {
private final TestAppInstance mTestApp;
@@ -152,14 +174,14 @@
}
@Override
- public DeviceAdminBugreportSharingDeclinedEvent.DeviceAdminBugreportSharingDeclinedEventQuery bugReportSharingDeclined() {
+ public DeviceAdminBugreportSharingDeclinedEventQuery bugReportSharingDeclined() {
return DeviceAdminBugreportSharingDeclinedEvent.queryPackage(
mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
- public DeviceAdminChoosePrivateKeyAliasEvent.DeviceAdminChoosePrivateKeyAliasEventQuery choosePrivateKeyAlias() {
+ public DeviceAdminChoosePrivateKeyAliasEventQuery choosePrivateKeyAlias() {
return DeviceAdminChoosePrivateKeyAliasEvent.queryPackage(
mTestApp.packageName())
.onUser(mTestApp.user());
@@ -173,7 +195,7 @@
}
@Override
- public DeviceAdminDisableRequestedEvent.DeviceAdminDisableRequestedEventQuery deviceAdminDisableRequested() {
+ public DeviceAdminDisableRequestedEventQuery deviceAdminDisableRequested() {
return DeviceAdminDisableRequestedEvent.queryPackage(
mTestApp.packageName())
.onUser(mTestApp.user());
@@ -187,28 +209,28 @@
}
@Override
- public DeviceAdminLockTaskModeEnteringEvent.DeviceAdminLockTaskModeEnteringEventQuery lockTaskModeEntering() {
+ public DeviceAdminLockTaskModeEnteringEventQuery lockTaskModeEntering() {
return DeviceAdminLockTaskModeEnteringEvent.queryPackage(
mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
- public DeviceAdminLockTaskModeExitingEvent.DeviceAdminLockTaskModeExitingEventQuery lockTaskModeExiting() {
+ public DeviceAdminLockTaskModeExitingEventQuery lockTaskModeExiting() {
return DeviceAdminLockTaskModeExitingEvent.queryPackage(
mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
- public DeviceAdminNetworkLogsAvailableEvent.DeviceAdminNetworkLogsAvailableEventQuery networkLogsAvailable() {
+ public DeviceAdminNetworkLogsAvailableEventQuery networkLogsAvailable() {
return DeviceAdminNetworkLogsAvailableEvent.queryPackage(
mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
- public DeviceAdminOperationSafetyStateChangedEvent.DeviceAdminOperationSafetyStateChangedEventQuery operationSafetyStateChanged() {
+ public DeviceAdminOperationSafetyStateChangedEventQuery operationSafetyStateChanged() {
return DeviceAdminOperationSafetyStateChangedEvent.queryPackage(
mTestApp.packageName())
.onUser(mTestApp.user());
@@ -222,7 +244,7 @@
}
@Override
- public DeviceAdminPasswordExpiringEvent.DeviceAdminPasswordExpiringEventQuery passwordExpiring() {
+ public DeviceAdminPasswordExpiringEventQuery passwordExpiring() {
return DeviceAdminPasswordExpiringEvent.queryPackage(
mTestApp.packageName())
.onUser(mTestApp.user());
@@ -236,49 +258,49 @@
}
@Override
- public DeviceAdminPasswordSucceededEvent.DeviceAdminPasswordSucceededEventQuery passwordSucceeded() {
+ public DeviceAdminPasswordSucceededEventQuery passwordSucceeded() {
return DeviceAdminPasswordSucceededEvent.queryPackage(
mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
- public DeviceAdminProfileProvisioningCompleteEvent.DeviceAdminProfileProvisioningCompleteEventQuery profileProvisioningComplete() {
+ public DeviceAdminProfileProvisioningCompleteEventQuery profileProvisioningComplete() {
return DeviceAdminProfileProvisioningCompleteEvent.queryPackage(
mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
- public DeviceAdminReadyForUserInitializationEvent.DeviceAdminReadyForUserInitializationEventQuery readyForUserInitialization() {
+ public DeviceAdminReadyForUserInitializationEventQuery readyForUserInitialization() {
return DeviceAdminReadyForUserInitializationEvent.queryPackage(
mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
- public DeviceAdminSecurityLogsAvailableEvent.DeviceAdminSecurityLogsAvailableEventQuery securityLogsAvailable() {
+ public DeviceAdminSecurityLogsAvailableEventQuery securityLogsAvailable() {
return DeviceAdminSecurityLogsAvailableEvent.queryPackage(
mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
- public DeviceAdminSystemUpdatePendingEvent.DeviceAdminSystemUpdatePendingEventQuery systemUpdatePending() {
+ public DeviceAdminSystemUpdatePendingEventQuery systemUpdatePending() {
return DeviceAdminSystemUpdatePendingEvent.queryPackage(
mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
- public DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery transferAffiliatedProfileOwnershipComplete() {
+ public DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery transferAffiliatedProfileOwnershipComplete() {
return DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.queryPackage(
mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
- public DeviceAdminTransferOwnershipCompleteEvent.DeviceAdminTransferOwnershipCompleteEventQuery transferOwnershipComplete() {
+ public DeviceAdminTransferOwnershipCompleteEventQuery transferOwnershipComplete() {
return DeviceAdminTransferOwnershipCompleteEvent.queryPackage(
mTestApp.packageName())
.onUser(mTestApp.user());
@@ -390,4 +412,24 @@
.onUser(mTestApp.user());
}
+ @Override
+ public DelegatedAdminChoosePrivateKeyAliasEventQuery delegateChoosePrivateKeyAlias() {
+ return DelegatedAdminChoosePrivateKeyAliasEvent.queryPackage(
+ mTestApp.testApp().packageName())
+ .onUser(mTestApp.user());
+ }
+
+ @Override
+ public DelegatedAdminNetworkLogsAvailableEventQuery delegateNetworkLogsAvailable() {
+ return DelegatedAdminNetworkLogsAvailableEvent.queryPackage(
+ mTestApp.testApp().packageName())
+ .onUser(mTestApp.user());
+ }
+
+ @Override
+ public DelegatedAdminSecurityLogsAvailableEventQuery delegateSecurityLogsAvailable() {
+ return DelegatedAdminSecurityLogsAvailableEvent.queryPackage(
+ mTestApp.testApp().packageName())
+ .onUser(mTestApp.user());
+ }
}
diff --git a/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/BaseTestAppDelegatedAdminReceiver.java b/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/BaseTestAppDelegatedAdminReceiver.java
new file mode 100644
index 0000000..2e3de42
--- /dev/null
+++ b/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/BaseTestAppDelegatedAdminReceiver.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.testapp;
+
+import android.app.admin.DelegatedAdminReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import com.android.eventlib.premade.EventLibDelegatedAdminReceiver;
+
+/**
+ * Implementation of {@link DelegatedAdminReceiver} which logs events in response to callbacks and
+ * supports TestApp Features.
+ */
+public class BaseTestAppDelegatedAdminReceiver extends EventLibDelegatedAdminReceiver {
+ @Override
+ public String onChoosePrivateKeyAlias(Context context, Intent intent, int uid, Uri uri,
+ String alias) {
+ return super.onChoosePrivateKeyAlias(context, intent, uid, uri, alias);
+ }
+
+ @Override
+ public void onNetworkLogsAvailable(Context context, Intent intent, long batchToken,
+ int networkLogsCount) {
+ super.onNetworkLogsAvailable(context, intent, batchToken, networkLogsCount);
+ }
+
+ @Override
+ public void onSecurityLogsAvailable(Context context, Intent intent) {
+ super.onSecurityLogsAvailable(context, intent);
+ }
+}
diff --git a/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java b/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java
index b5ee589..3d8e256 100644
--- a/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java
+++ b/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java
@@ -88,7 +88,6 @@
try {
return super.instantiateReceiver(classLoader, className, intent);
} catch (ClassNotFoundException e) {
-
if (className.endsWith("DeviceAdminReceiver")) {
Log.d(LOG_TAG, "Broadcast Receiver class (" + className
+ ") not found, routing to TestAppDeviceAdminReceiver");
@@ -98,6 +97,15 @@
intent);
receiver.setOverrideDeviceAdminReceiverClassName(className);
return receiver;
+ } else if (className.endsWith("DelegatedAdminReceiver")) {
+ Log.d(LOG_TAG, "Broadcast Receiver class (" + className
+ + ") not found, routing to TestAppDelegatedAdminReceiver");
+ BaseTestAppDelegatedAdminReceiver receiver = (BaseTestAppDelegatedAdminReceiver)
+ super.instantiateReceiver(
+ classLoader, BaseTestAppDelegatedAdminReceiver.class.getName(),
+ intent);
+ receiver.setOverrideDelegatedAdminReceiverClassName(className);
+ return receiver;
}
Log.d(LOG_TAG, "Broadcast Receiver class (" + className
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
index 0235d69..532dbe5 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
@@ -43,7 +43,8 @@
public class PackageDeviceInfo extends DeviceInfo {
private static final String PLATFORM = "android";
- private static final String PLATFORM_PERMISSION_PREFIX = "android.";
+ private static final String PLATFORM_ANDROID_PERMISSION_PREFIX = "android.permission.";
+ private static final String PLATFORM_MANIFEST_PERMISSION_PREFIX = "android.Manifest.permission.";
private static final String PACKAGE = "package";
private static final String NAME = "name";
@@ -54,6 +55,7 @@
private static final String TARGET_SDK = "target_sdk";
private static final String REQUESTED_PERMISSIONS = "requested_permissions";
+ private static final String DEFINED_PERMISSIONS = "defined_permissions";
private static final String PERMISSION_NAME = "name";
private static final String PERMISSION_FLAGS = "flags";
private static final String PERMISSION_GROUP = "permission_group";
@@ -61,6 +63,7 @@
private static final String PERMISSION_PROTECTION_FLAGS = "protection_level_flags";
private static final String PERMISSION_IS_GRANTED = "is_granted";
+
private static final String PERMISSION_TYPE = "type";
private static final int PERMISSION_TYPE_SYSTEM = 1;
private static final int PERMISSION_TYPE_OEM = 2;
@@ -84,6 +87,21 @@
private static final String CONFIG_ACCESSIBILITY_SERVICE = "config_defaultAccessibilityService";
private static final String DEFAULT_ACCESSIBILITY_SERVICE = "is_default_accessibility_service";
+ private static final HashSet<String> ADDITIONAL_ANDROID_PERMISSIONS = new HashSet<>(Arrays.asList(new String[] {
+ "com.android.voicemail.permission.ADD_VOICEMAIL",
+ "com.android.voicemail.permission.WRITE_VOICEMAIL",
+ "com.android.voicemail.permission.READ_VOICEMAIL",
+ "com.android.browser.permission.READ_HISTORY_BOOKMARKS",
+ "com.android.browser.permission.WRITE_HISTORY_BOOKMARKS",
+ "com.android.alarm.permission.SET_ALARM",
+ "com.android.launcher.permission.INSTALL_SHORTCUT",
+ "com.android.launcher.permission.UNINSTALL_SHORTCUT",
+ "com.android.permission.INSTALL_EXISTING_PACKAGES",
+ "com.android.permission.USE_INSTALLER_V2",
+ "com.android.permission.USE_SYSTEM_DATA_LOADERS",
+ "android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE"
+ }));
+
@Override
protected void collectDeviceInfo(DeviceInfoStore store) throws Exception {
@@ -111,7 +129,9 @@
store.addResult(NAME, pkg.packageName);
store.addResult(VERSION_NAME, pkg.versionName);
- collectPermissions(store, pm, platformPermissions, pkg);
+ collectRequestedPermissions(store, pm, platformPermissions, pkg);
+ collectDefinedPermissions(store, platformPermissions, pkg);
+
collectionApplicationInfo(store, pm, pkg);
store.addResult(HAS_DEFAULT_NOTIFICATION_ACCESS,
@@ -138,7 +158,7 @@
store.endArray(); // "package"
}
- private static void collectPermissions(DeviceInfoStore store,
+ private static void collectRequestedPermissions(DeviceInfoStore store,
PackageManager pm,
Set<String> systemPermissions,
PackageInfo pkg) throws IOException
@@ -152,20 +172,7 @@
final PermissionInfo pi = pm.getPermissionInfo(permission, 0);
store.startGroup();
- store.addResult(PERMISSION_NAME, permission);
- writePermissionsDetails(pi, store);
-
- final boolean isPlatformPermission = systemPermissions.contains(permission);
- if (isPlatformPermission) {
- final boolean isAndroidPermission = permission.startsWith(PLATFORM_PERMISSION_PREFIX);
- if (isAndroidPermission) {
- store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_SYSTEM);
- } else {
- store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_OEM);
- }
- } else {
- store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_CUSTOM);
- }
+ writePermissionsDetails(pi, store, systemPermissions);
boolean isGranted = pm.checkPermission(
permission, pkg.packageName) == pm.PERMISSION_GRANTED;
@@ -180,6 +187,27 @@
store.endArray();
}
+ private static void collectDefinedPermissions(DeviceInfoStore store,
+ Set<String> systemPermissions,
+ PackageInfo pkg) throws IOException {
+ if (pkg.permissions != null && pkg.permissions.length > 0) {
+ store.startArray(DEFINED_PERMISSIONS);
+ for (PermissionInfo permission : pkg.permissions) {
+ if (permission == null) continue;
+ // Ignore "android" package defined AOSP permissions.
+ if (pkg.packageName.equals(PLATFORM)
+ && isAndroidPermission(permission.name))
+ continue;
+
+ store.startGroup();
+ writePermissionsDetails(permission, store, systemPermissions);
+ store.endGroup();
+
+ }
+ store.endArray();
+ }
+ }
+
private static void collectionApplicationInfo(DeviceInfoStore store,
PackageManager pm,
PackageInfo pkg) throws IOException {
@@ -231,8 +259,12 @@
return sharedPermissions.contains(PackageDeviceInfo.INSTALL_PACKAGES_PERMISSION);
}
- private static void writePermissionsDetails(PermissionInfo pi, DeviceInfoStore store)
- throws IOException {
+ private static void writePermissionsDetails(PermissionInfo pi,
+ DeviceInfoStore store,
+ Set<String> systemPermissions) throws IOException {
+ final String permissionName = pi.name;
+ store.addResult(PERMISSION_NAME, permissionName);
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
store.addResult(PERMISSION_FLAGS, pi.flags);
} else {
@@ -250,6 +282,18 @@
store.addResult(PERMISSION_PROTECTION_FLAGS,
pi.protectionLevel & ~PermissionInfo.PROTECTION_MASK_BASE);
}
+
+ final boolean isPlatformPermission = systemPermissions.contains(permissionName);
+ if (isPlatformPermission) {
+ final boolean isAndroidPermission = isAndroidPermission(permissionName);
+ if (isAndroidPermission) {
+ store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_SYSTEM);
+ } else {
+ store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_OEM);
+ }
+ } else {
+ store.addResult(PERMISSION_TYPE, PERMISSION_TYPE_CUSTOM);
+ }
}
private Set<String> getActiveDeviceAdminPackages() {
@@ -297,5 +341,14 @@
.getResources()
.getIdentifier(name, type, "android");
}
+
+ /** Return a boolean value to whether the permission is an android permission defined by android package */
+ private static boolean isAndroidPermission(String permissionName) {
+ if(permissionName.startsWith(PLATFORM_ANDROID_PERMISSION_PREFIX)
+ || permissionName.startsWith(PLATFORM_MANIFEST_PERMISSION_PREFIX)
+ || ADDITIONAL_ANDROID_PERMISSIONS.contains(permissionName))
+ return true;
+ return false;
+ }
}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/StorageDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/StorageDeviceInfo.java
index 767f1d9..8f1d450 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/StorageDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/StorageDeviceInfo.java
@@ -16,6 +16,7 @@
package com.android.compatibility.common.deviceinfo;
import android.os.Environment;
+import android.os.SystemProperties;
import android.util.Log;
import com.android.compatibility.common.util.DeviceInfoStore;
@@ -57,12 +58,15 @@
store.addResult("num_emulated", emulated);
store.addListResult("raw_partition", scanPartitions());
+
+ boolean hasCompress = SystemProperties.getInt("vold.has_compress", 0) != 0 ? true : false;
+ store.addResult("compression", hasCompress);
}
private List<String> scanPartitions() {
List<String> partitionList = new ArrayList<>();
try {
- Process df = new ProcessBuilder("df -k").start();
+ Process df = Runtime.getRuntime().exec("df -k");
Scanner scanner = new Scanner(df.getInputStream());
try {
while (scanner.hasNextLine()) {
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/CarrierPrivilegeUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/CarrierPrivilegeUtils.java
index 2b174a7..edf0077 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/CarrierPrivilegeUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/CarrierPrivilegeUtils.java
@@ -16,7 +16,7 @@
package com.android.compatibility.common.util;
-import static android.telephony.TelephonyManager.CarrierPrivilegesListener;
+import static android.telephony.TelephonyManager.CarrierPrivilegesCallback;
import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
@@ -58,10 +58,10 @@
private final boolean mGain;
private final boolean mIsShell;
private final TelephonyManager mTelephonyManager;
- private final CarrierPrivilegesListener mCarrierPrivilegesListener;
+ private final CarrierPrivilegesCallback mCarrierPrivilegesCallback;
/**
- * Construct a {@link CarrierPrivilegesListener} to monitor carrier privileges change.
+ * Construct a {@link CarrierPrivilegesCallback} to monitor carrier privileges change.
* @param c context
* @param subId subscriptionId to listen to
* @param gain true if wait to grant carrier privileges, false if wait to revoke
@@ -76,26 +76,25 @@
TelephonyManager.class).createForSubscriptionId(subId);
Objects.requireNonNull(mTelephonyManager);
- mCarrierPrivilegesListener =
- (privilegedPackageNames, privilegedUids) -> {
- if (mTelephonyManager.hasCarrierPrivileges() == mGain) {
- mLatch.countDown();
- }
- };
+ mCarrierPrivilegesCallback = (privilegedPackageNames, privilegedUids) -> {
+ if (mTelephonyManager.hasCarrierPrivileges() == mGain) {
+ mLatch.countDown();
+ }
+ };
// Run with shell identify only when caller is not Shell to avoid overriding current
// SHELL permissions
if (mIsShell) {
- mTelephonyManager.addCarrierPrivilegesListener(
+ mTelephonyManager.registerCarrierPrivilegesCallback(
SubscriptionManager.getSlotIndex(subId),
mContext.getMainExecutor(),
- mCarrierPrivilegesListener);
+ mCarrierPrivilegesCallback);
} else {
runWithShellPermissionIdentity(() -> {
- mTelephonyManager.addCarrierPrivilegesListener(
+ mTelephonyManager.registerCarrierPrivilegesCallback(
SubscriptionManager.getSlotIndex(subId),
mContext.getMainExecutor(),
- mCarrierPrivilegesListener);
+ mCarrierPrivilegesCallback);
}, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
}
}
@@ -105,11 +104,12 @@
if (mTelephonyManager == null) return;
if (mIsShell) {
- mTelephonyManager.removeCarrierPrivilegesListener(mCarrierPrivilegesListener);
+ mTelephonyManager.unregisterCarrierPrivilegesCallback(mCarrierPrivilegesCallback);
} else {
- runWithShellPermissionIdentity(() -> {
- mTelephonyManager.removeCarrierPrivilegesListener(mCarrierPrivilegesListener);
- }, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+ runWithShellPermissionIdentity(
+ () -> mTelephonyManager.unregisterCarrierPrivilegesCallback(
+ mCarrierPrivilegesCallback),
+ Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
}
}
diff --git a/hostsidetests/appcompat/strictjavapackages/Android.bp b/hostsidetests/appcompat/strictjavapackages/Android.bp
index a2b4581..272be12 100644
--- a/hostsidetests/appcompat/strictjavapackages/Android.bp
+++ b/hostsidetests/appcompat/strictjavapackages/Android.bp
@@ -23,6 +23,7 @@
libs: [
"tradefed",
"compatibility-host-util",
+ "cts-tradefed",
],
static_libs: [
"compat-classpaths-testing",
@@ -34,6 +35,9 @@
"general-tests",
"mts-mainline-infra",
],
- data: [":SharedLibraryInfoTestApp"],
+ data: [
+ ":SharedLibraryInfoTestApp",
+ ":StrictJavaPackagesTestApp",
+ ],
per_testcase_directory: true,
}
diff --git a/hostsidetests/appcompat/strictjavapackages/app/Android.bp b/hostsidetests/appcompat/strictjavapackages/app/Android.bp
new file mode 100644
index 0000000..47e7f00
--- /dev/null
+++ b/hostsidetests/appcompat/strictjavapackages/app/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "StrictJavaPackagesTestApp",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.core",
+ ],
+ sdk_version: "test_current",
+ test_suites: [
+ "ats",
+ "cts",
+ "gts",
+ "general-tests",
+ "mts",
+ "tvts",
+ ],
+}
diff --git a/hostsidetests/appcompat/strictjavapackages/app/AndroidManifest.xml b/hostsidetests/appcompat/strictjavapackages/app/AndroidManifest.xml
new file mode 100644
index 0000000..6ac77db
--- /dev/null
+++ b/hostsidetests/appcompat/strictjavapackages/app/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.compat.sjp.app"
+ android:targetSandboxVersion="2">
+ <application android:requestLegacyExternalStorage="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.compat.sjp.app" />
+</manifest>
diff --git a/hostsidetests/appcompat/strictjavapackages/app/src/android/compat/sjp/app/ApexDeviceTest.java b/hostsidetests/appcompat/strictjavapackages/app/src/android/compat/sjp/app/ApexDeviceTest.java
new file mode 100644
index 0000000..fa98fe6
--- /dev/null
+++ b/hostsidetests/appcompat/strictjavapackages/app/src/android/compat/sjp/app/ApexDeviceTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.compat.sjp.app;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.content.pm.PackageManager;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Device-side helper app for obtaining Apex info.
+ *
+ * <p>It is not technically a test as it simply collects information, but it simplifies the usage
+ * and communication with host-side tests.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ApexDeviceTest {
+
+ @Before
+ public void before() {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity();
+ }
+
+ @After
+ public void after() {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+
+ /**
+ * Collects all apk-in-apex apps on the device and writes them to disk.
+ */
+ @Test
+ public void testCollectApkInApexPaths() throws Exception {
+ Path detailsFilepath = new File("/sdcard/apk-in-apex-paths.txt").toPath();
+ final PackageManager pm = InstrumentationRegistry.getInstrumentation().getTargetContext()
+ .getPackageManager();
+ assertNotNull("No package manager instance!", pm);
+ final Set<String> lines = pm.getInstalledPackages(0).stream()
+ .map(pkg -> pkg.applicationInfo.sourceDir)
+ .filter(sourceDir -> sourceDir != null && sourceDir.contains("/apex/"))
+ .collect(Collectors.toSet());
+ Files.write(detailsFilepath, lines);
+ }
+}
diff --git a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
index cff7c22..1912811 100644
--- a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
+++ b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
@@ -20,12 +20,14 @@
import static android.compat.testing.Classpaths.ClasspathType.SYSTEMSERVERCLASSPATH;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assume.assumeTrue;
import android.compat.testing.Classpaths;
import android.compat.testing.SharedLibraryInfo;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.modules.utils.build.testing.DeviceSdkLevel;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
@@ -33,10 +35,13 @@
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.testtype.junit4.BeforeClassWithInfo;
+import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap;
@@ -48,6 +53,7 @@
import org.junit.runner.RunWith;
import java.io.IOException;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Stream;
@@ -64,12 +70,14 @@
public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
private static final String ANDROID_TEST_MOCK_JAR = "/system/framework/android.test.mock.jar";
+ private static final String TEST_HELPER_PACKAGE = "android.compat.sjp.app";
+ private static final String TEST_HELPER_APK = "StrictJavaPackagesTestApp.apk";
private static ImmutableList<String> sBootclasspathJars;
private static ImmutableList<String> sSystemserverclasspathJars;
private static ImmutableList<String> sSharedLibJars;
private static ImmutableList<SharedLibraryInfo> sSharedLibs;
- private static ImmutableSetMultimap<String, String> sJarsToClasses;
+ private static ImmutableMultimap<String, String> sJarsToClasses;
private DeviceSdkLevel mDeviceSdkLevel;
@@ -205,6 +213,7 @@
"Landroid/hardware/usb/gadget/V1_2/UsbSpeed;",
"Landroid/os/CreateAppDataArgs;",
"Landroid/os/CreateAppDataResult;",
+ "Landroid/os/ReconcileSdkDataArgs;",
"Lcom/android/internal/util/FrameworkStatsLog;"
);
@@ -311,7 +320,418 @@
"Lorg/chromium/net/UrlRequest;",
"Lorg/chromium/net/UrlResponseInfo;"
);
-
+ // TODO: b/223837004
+ private static final ImmutableSet<String> BLUETOOTH_APK_IN_APEX_BURNDOWN_LIST =
+ ImmutableSet.of(
+ // Already duplicate in BCP.
+ "Landroid/hidl/base/V1_0/DebugInfo;",
+ "Landroid/hidl/base/V1_0/IBase;",
+ // /apex/com.android.bluetooth/javalib/framework-bluetooth.jar
+ "Lcom/android/bluetooth/x/android/sysprop/AdbProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/ApkVerityProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/BluetoothProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/CarProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/ContactsProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/CryptoProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/DeviceProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/DisplayProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/HdmiProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/HypervisorProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/InputProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/MediaProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/NetworkProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/OtaProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/PowerProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/SetupWizardProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/SocProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/TelephonyProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/TraceProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/VndkProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/VoldProperties;",
+ "Lcom/android/bluetooth/x/android/sysprop/WifiProperties;",
+ "Lcom/android/bluetooth/x/com/android/modules/utils/ISynchronousResultReceiver;",
+ "Lcom/android/bluetooth/x/com/android/modules/utils/SynchronousResultReceiver-IA;",
+ "Lcom/android/bluetooth/x/com/android/modules/utils/SynchronousResultReceiver;",
+ // /system/framework/services.jar
+ "Landroid/net/DataStallReportParcelable;",
+ "Landroid/net/DhcpResultsParcelable;",
+ "Landroid/net/IIpMemoryStore;",
+ "Landroid/net/IIpMemoryStoreCallbacks;",
+ "Landroid/net/INetworkMonitor;",
+ "Landroid/net/INetworkMonitorCallbacks;",
+ "Landroid/net/INetworkStackConnector;",
+ "Landroid/net/INetworkStackStatusCallback;",
+ "Landroid/net/InformationElementParcelable;",
+ "Landroid/net/InitialConfigurationParcelable;",
+ "Landroid/net/IpMemoryStoreClient;",
+ "Landroid/net/Layer2InformationParcelable;",
+ "Landroid/net/Layer2PacketParcelable;",
+ "Landroid/net/NattKeepalivePacketDataParcelable;",
+ "Landroid/net/NetworkFactory;",
+ "Landroid/net/NetworkFactoryShim;",
+ "Landroid/net/NetworkMonitorManager;",
+ "Landroid/net/NetworkTestResultParcelable;",
+ "Landroid/net/PrivateDnsConfigParcel;",
+ "Landroid/net/ProvisioningConfigurationParcelable;",
+ "Landroid/net/ScanResultInfoParcelable;",
+ "Landroid/net/TcpKeepalivePacketDataParcelable;",
+ "Landroid/net/dhcp/DhcpLeaseParcelable;",
+ "Landroid/net/dhcp/DhcpServingParamsParcel;",
+ "Landroid/net/dhcp/IDhcpEventCallbacks;",
+ "Landroid/net/dhcp/IDhcpServer;",
+ "Landroid/net/dhcp/IDhcpServerCallbacks;",
+ "Landroid/net/ip/IIpClient;",
+ "Landroid/net/ip/IIpClientCallbacks;",
+ "Landroid/net/ip/IpClientCallbacks;",
+ "Landroid/net/ip/IpClientManager;",
+ "Landroid/net/ip/IpClientUtil;",
+ "Landroid/net/ipmemorystore/Blob;",
+ "Landroid/net/ipmemorystore/IOnBlobRetrievedListener;",
+ "Landroid/net/ipmemorystore/IOnL2KeyResponseListener;",
+ "Landroid/net/ipmemorystore/IOnNetworkAttributesRetrievedListener;",
+ "Landroid/net/ipmemorystore/IOnSameL3NetworkResponseListener;",
+ "Landroid/net/ipmemorystore/IOnStatusAndCountListener;",
+ "Landroid/net/ipmemorystore/IOnStatusListener;",
+ "Landroid/net/ipmemorystore/NetworkAttributes;",
+ "Landroid/net/ipmemorystore/NetworkAttributesParcelable;",
+ "Landroid/net/ipmemorystore/OnBlobRetrievedListener;",
+ "Landroid/net/ipmemorystore/OnDeleteStatusListener;",
+ "Landroid/net/ipmemorystore/OnL2KeyResponseListener;",
+ "Landroid/net/ipmemorystore/OnNetworkAttributesRetrievedListener;",
+ "Landroid/net/ipmemorystore/OnSameL3NetworkResponseListener;",
+ "Landroid/net/ipmemorystore/OnStatusListener;",
+ "Landroid/net/ipmemorystore/SameL3NetworkResponse;",
+ "Landroid/net/ipmemorystore/SameL3NetworkResponseParcelable;",
+ "Landroid/net/ipmemorystore/Status;",
+ "Landroid/net/ipmemorystore/StatusParcelable;",
+ "Landroid/net/networkstack/NetworkStackClientBase;",
+ "Landroid/net/networkstack/aidl/NetworkMonitorParameters;",
+ "Landroid/net/networkstack/aidl/dhcp/DhcpOption;",
+ "Landroid/net/networkstack/aidl/ip/ReachabilityLossInfoParcelable;",
+ "Landroid/net/networkstack/aidl/ip/ReachabilityLossReason;",
+ "Landroid/net/networkstack/aidl/quirks/IPv6ProvisioningLossQuirk;",
+ "Landroid/net/networkstack/aidl/quirks/IPv6ProvisioningLossQuirkParcelable;",
+ "Landroid/net/shared/InitialConfiguration;",
+ "Landroid/net/shared/IpConfigurationParcelableUtil;",
+ "Landroid/net/shared/Layer2Information;",
+ "Landroid/net/shared/ParcelableUtil;",
+ "Landroid/net/shared/PrivateDnsConfig;",
+ "Landroid/net/shared/ProvisioningConfiguration;",
+ "Landroid/net/util/KeepalivePacketDataUtil;",
+ "Landroid/net/IpMemoryStore;",
+ "Landroid/net/NetworkFactoryLegacyImpl;",
+ "Landroid/net/networkstack/ModuleNetworkStackClient;",
+ "Landroid/net/NetworkFactoryImpl;",
+ // /system/framework/framework.jar
+ "Landroid/bluetooth/BluetoothProtoEnums;",
+ "Landroid/bluetooth/a2dp/BluetoothA2dpProtoEnums;",
+ "Landroid/bluetooth/hci/BluetoothHciProtoEnums;",
+ "Landroid/bluetooth/hfp/BluetoothHfpProtoEnums;",
+ "Landroid/bluetooth/smp/BluetoothSmpProtoEnums;",
+ "Landroid/hardware/radio/V1_0/ActivityStatsInfo;",
+ "Landroid/hardware/radio/V1_0/ApnAuthType;",
+ "Landroid/hardware/radio/V1_0/ApnTypes;",
+ "Landroid/hardware/radio/V1_0/AppState;",
+ "Landroid/hardware/radio/V1_0/AppStatus;",
+ "Landroid/hardware/radio/V1_0/AppType;",
+ "Landroid/hardware/radio/V1_0/Call;",
+ "Landroid/hardware/radio/V1_0/CallForwardInfo;",
+ "Landroid/hardware/radio/V1_0/CallForwardInfoStatus;",
+ "Landroid/hardware/radio/V1_0/CallPresentation;",
+ "Landroid/hardware/radio/V1_0/CallState;",
+ "Landroid/hardware/radio/V1_0/CardState;",
+ "Landroid/hardware/radio/V1_0/CardStatus;",
+ "Landroid/hardware/radio/V1_0/Carrier;",
+ "Landroid/hardware/radio/V1_0/CarrierMatchType;",
+ "Landroid/hardware/radio/V1_0/CarrierRestrictions;",
+ "Landroid/hardware/radio/V1_0/CdmaBroadcastSmsConfigInfo;",
+ "Landroid/hardware/radio/V1_0/CdmaCallWaiting;",
+ "Landroid/hardware/radio/V1_0/CdmaCallWaitingNumberPlan;",
+ "Landroid/hardware/radio/V1_0/CdmaCallWaitingNumberPresentation;",
+ "Landroid/hardware/radio/V1_0/CdmaCallWaitingNumberType;",
+ "Landroid/hardware/radio/V1_0/CdmaDisplayInfoRecord;",
+ "Landroid/hardware/radio/V1_0/CdmaInfoRecName;",
+ "Landroid/hardware/radio/V1_0/CdmaInformationRecord;",
+ "Landroid/hardware/radio/V1_0/CdmaInformationRecords;",
+ "Landroid/hardware/radio/V1_0/CdmaLineControlInfoRecord;",
+ "Landroid/hardware/radio/V1_0/CdmaNumberInfoRecord;",
+ "Landroid/hardware/radio/V1_0/CdmaOtaProvisionStatus;",
+ "Landroid/hardware/radio/V1_0/CdmaRedirectingNumberInfoRecord;",
+ "Landroid/hardware/radio/V1_0/CdmaRedirectingReason;",
+ "Landroid/hardware/radio/V1_0/CdmaRoamingType;",
+ "Landroid/hardware/radio/V1_0/CdmaSignalInfoRecord;",
+ "Landroid/hardware/radio/V1_0/CdmaSignalStrength;",
+ "Landroid/hardware/radio/V1_0/CdmaSmsAck;",
+ "Landroid/hardware/radio/V1_0/CdmaSmsAddress;",
+ "Landroid/hardware/radio/V1_0/CdmaSmsDigitMode;",
+ "Landroid/hardware/radio/V1_0/CdmaSmsErrorClass;",
+ "Landroid/hardware/radio/V1_0/CdmaSmsMessage;",
+ "Landroid/hardware/radio/V1_0/CdmaSmsNumberMode;",
+ "Landroid/hardware/radio/V1_0/CdmaSmsNumberPlan;",
+ "Landroid/hardware/radio/V1_0/CdmaSmsNumberType;",
+ "Landroid/hardware/radio/V1_0/CdmaSmsSubaddress;",
+ "Landroid/hardware/radio/V1_0/CdmaSmsSubaddressType;",
+ "Landroid/hardware/radio/V1_0/CdmaSmsWriteArgs;",
+ "Landroid/hardware/radio/V1_0/CdmaSmsWriteArgsStatus;",
+ "Landroid/hardware/radio/V1_0/CdmaSubscriptionSource;",
+ "Landroid/hardware/radio/V1_0/CdmaT53AudioControlInfoRecord;",
+ "Landroid/hardware/radio/V1_0/CdmaT53ClirInfoRecord;",
+ "Landroid/hardware/radio/V1_0/CellIdentity;",
+ "Landroid/hardware/radio/V1_0/CellIdentityCdma;",
+ "Landroid/hardware/radio/V1_0/CellIdentityGsm;",
+ "Landroid/hardware/radio/V1_0/CellIdentityLte;",
+ "Landroid/hardware/radio/V1_0/CellIdentityTdscdma;",
+ "Landroid/hardware/radio/V1_0/CellIdentityWcdma;",
+ "Landroid/hardware/radio/V1_0/CellInfo;",
+ "Landroid/hardware/radio/V1_0/CellInfoCdma;",
+ "Landroid/hardware/radio/V1_0/CellInfoGsm;",
+ "Landroid/hardware/radio/V1_0/CellInfoLte;",
+ "Landroid/hardware/radio/V1_0/CellInfoTdscdma;",
+ "Landroid/hardware/radio/V1_0/CellInfoType;",
+ "Landroid/hardware/radio/V1_0/CellInfoWcdma;",
+ "Landroid/hardware/radio/V1_0/CfData;",
+ "Landroid/hardware/radio/V1_0/ClipStatus;",
+ "Landroid/hardware/radio/V1_0/Clir;",
+ "Landroid/hardware/radio/V1_0/DataCallFailCause;",
+ "Landroid/hardware/radio/V1_0/DataProfileId;",
+ "Landroid/hardware/radio/V1_0/DataProfileInfo;",
+ "Landroid/hardware/radio/V1_0/DataProfileInfoType;",
+ "Landroid/hardware/radio/V1_0/DataRegStateResult;",
+ "Landroid/hardware/radio/V1_0/DeviceStateType;",
+ "Landroid/hardware/radio/V1_0/Dial;",
+ "Landroid/hardware/radio/V1_0/EvdoSignalStrength;",
+ "Landroid/hardware/radio/V1_0/GsmBroadcastSmsConfigInfo;",
+ "Landroid/hardware/radio/V1_0/GsmSignalStrength;",
+ "Landroid/hardware/radio/V1_0/GsmSmsMessage;",
+ "Landroid/hardware/radio/V1_0/HardwareConfig;",
+ "Landroid/hardware/radio/V1_0/HardwareConfigModem;",
+ "Landroid/hardware/radio/V1_0/HardwareConfigSim;",
+ "Landroid/hardware/radio/V1_0/HardwareConfigState;",
+ "Landroid/hardware/radio/V1_0/HardwareConfigType;",
+ "Landroid/hardware/radio/V1_0/IccIo;",
+ "Landroid/hardware/radio/V1_0/IccIoResult;",
+ "Landroid/hardware/radio/V1_0/ImsSmsMessage;",
+ "Landroid/hardware/radio/V1_0/IndicationFilter;",
+ "Landroid/hardware/radio/V1_0/LastCallFailCause;",
+ "Landroid/hardware/radio/V1_0/LastCallFailCauseInfo;",
+ "Landroid/hardware/radio/V1_0/LceDataInfo;",
+ "Landroid/hardware/radio/V1_0/LceStatus;",
+ "Landroid/hardware/radio/V1_0/LceStatusInfo;",
+ "Landroid/hardware/radio/V1_0/LteSignalStrength;",
+ "Landroid/hardware/radio/V1_0/MvnoType;",
+ "Landroid/hardware/radio/V1_0/NeighboringCell;",
+ "Landroid/hardware/radio/V1_0/NvItem;",
+ "Landroid/hardware/radio/V1_0/NvWriteItem;",
+ "Landroid/hardware/radio/V1_0/OperatorInfo;",
+ "Landroid/hardware/radio/V1_0/OperatorStatus;",
+ "Landroid/hardware/radio/V1_0/P2Constant;",
+ "Landroid/hardware/radio/V1_0/PcoDataInfo;",
+ "Landroid/hardware/radio/V1_0/PersoSubstate;",
+ "Landroid/hardware/radio/V1_0/PhoneRestrictedState;",
+ "Landroid/hardware/radio/V1_0/PinState;",
+ "Landroid/hardware/radio/V1_0/PreferredNetworkType;",
+ "Landroid/hardware/radio/V1_0/RadioAccessFamily;",
+ "Landroid/hardware/radio/V1_0/RadioBandMode;",
+ "Landroid/hardware/radio/V1_0/RadioCapability;",
+ "Landroid/hardware/radio/V1_0/RadioCapabilityPhase;",
+ "Landroid/hardware/radio/V1_0/RadioCapabilityStatus;",
+ "Landroid/hardware/radio/V1_0/RadioCdmaSmsConst;",
+ "Landroid/hardware/radio/V1_0/RadioConst;",
+ "Landroid/hardware/radio/V1_0/RadioError;",
+ "Landroid/hardware/radio/V1_0/RadioIndicationType;",
+ "Landroid/hardware/radio/V1_0/RadioResponseInfo;",
+ "Landroid/hardware/radio/V1_0/RadioResponseType;",
+ "Landroid/hardware/radio/V1_0/RadioState;",
+ "Landroid/hardware/radio/V1_0/RadioTechnology;",
+ "Landroid/hardware/radio/V1_0/RadioTechnologyFamily;",
+ "Landroid/hardware/radio/V1_0/RegState;",
+ "Landroid/hardware/radio/V1_0/ResetNvType;",
+ "Landroid/hardware/radio/V1_0/RestrictedState;",
+ "Landroid/hardware/radio/V1_0/SapApduType;",
+ "Landroid/hardware/radio/V1_0/SapConnectRsp;",
+ "Landroid/hardware/radio/V1_0/SapDisconnectType;",
+ "Landroid/hardware/radio/V1_0/SapResultCode;",
+ "Landroid/hardware/radio/V1_0/SapStatus;",
+ "Landroid/hardware/radio/V1_0/SapTransferProtocol;",
+ "Landroid/hardware/radio/V1_0/SelectUiccSub;",
+ "Landroid/hardware/radio/V1_0/SendSmsResult;",
+ "Landroid/hardware/radio/V1_0/SetupDataCallResult;",
+ "Landroid/hardware/radio/V1_0/SignalStrength;",
+ "Landroid/hardware/radio/V1_0/SimApdu;",
+ "Landroid/hardware/radio/V1_0/SimRefreshResult;",
+ "Landroid/hardware/radio/V1_0/SimRefreshType;",
+ "Landroid/hardware/radio/V1_0/SmsAcknowledgeFailCause;",
+ "Landroid/hardware/radio/V1_0/SmsWriteArgs;",
+ "Landroid/hardware/radio/V1_0/SmsWriteArgsStatus;",
+ "Landroid/hardware/radio/V1_0/SrvccState;",
+ "Landroid/hardware/radio/V1_0/SsInfoData;",
+ "Landroid/hardware/radio/V1_0/SsRequestType;",
+ "Landroid/hardware/radio/V1_0/SsServiceType;",
+ "Landroid/hardware/radio/V1_0/SsTeleserviceType;",
+ "Landroid/hardware/radio/V1_0/StkCcUnsolSsResult;",
+ "Landroid/hardware/radio/V1_0/SubscriptionType;",
+ "Landroid/hardware/radio/V1_0/SuppServiceClass;",
+ "Landroid/hardware/radio/V1_0/SuppSvcNotification;",
+ "Landroid/hardware/radio/V1_0/TdScdmaSignalStrength;",
+ "Landroid/hardware/radio/V1_0/TimeStampType;",
+ "Landroid/hardware/radio/V1_0/TtyMode;",
+ "Landroid/hardware/radio/V1_0/UiccSubActStatus;",
+ "Landroid/hardware/radio/V1_0/UssdModeType;",
+ "Landroid/hardware/radio/V1_0/UusDcs;",
+ "Landroid/hardware/radio/V1_0/UusInfo;",
+ "Landroid/hardware/radio/V1_0/UusType;",
+ "Landroid/hardware/radio/V1_0/VoiceRegStateResult;",
+ "Landroid/hardware/radio/V1_0/WcdmaSignalStrength;",
+ "Landroid/hardware/radio/V1_0/IRadio;",
+ "Landroid/hardware/radio/V1_0/IRadioIndication;",
+ "Landroid/hardware/radio/V1_0/IRadioResponse;",
+ "Landroid/hardware/radio/V1_0/ISap;",
+ "Landroid/hardware/radio/V1_0/ISapCallback;",
+ "Lcom/android/internal/util/IState;",
+ "Lcom/android/internal/util/StateMachine;",
+ "Lcom/google/android/mms/ContentType;",
+ "Lcom/google/android/mms/MmsException;",
+ "Lcom/google/android/mms/pdu/Base64;",
+ "Lcom/google/android/mms/pdu/CharacterSets;",
+ "Lcom/google/android/mms/pdu/EncodedStringValue;",
+ "Lcom/google/android/mms/pdu/GenericPdu;",
+ "Lcom/google/android/mms/pdu/PduBody;",
+ "Lcom/google/android/mms/pdu/PduComposer;",
+ "Lcom/google/android/mms/pdu/PduContentTypes;",
+ "Lcom/google/android/mms/pdu/PduHeaders;",
+ "Lcom/google/android/mms/pdu/PduParser;",
+ "Lcom/google/android/mms/pdu/PduPart;",
+ "Lcom/google/android/mms/pdu/PduPersister;",
+ "Lcom/google/android/mms/pdu/QuotedPrintable;",
+ "Lcom/google/android/mms/util/AbstractCache;",
+ "Lcom/google/android/mms/util/DownloadDrmHelper;",
+ "Lcom/google/android/mms/util/DrmConvertSession;",
+ "Lcom/google/android/mms/util/PduCacheEntry;",
+ "Lcom/google/android/mms/util/SqliteWrapper;",
+ "Lcom/android/internal/util/State;",
+ "Lcom/google/android/mms/InvalidHeaderValueException;",
+ "Lcom/google/android/mms/pdu/AcknowledgeInd;",
+ "Lcom/google/android/mms/pdu/DeliveryInd;",
+ "Lcom/google/android/mms/pdu/MultimediaMessagePdu;",
+ "Lcom/google/android/mms/pdu/NotificationInd;",
+ "Lcom/google/android/mms/pdu/NotifyRespInd;",
+ "Lcom/google/android/mms/pdu/ReadOrigInd;",
+ "Lcom/google/android/mms/pdu/ReadRecInd;",
+ "Lcom/google/android/mms/pdu/SendConf;",
+ "Lcom/google/android/mms/util/PduCache;",
+ "Lcom/google/android/mms/pdu/RetrieveConf;",
+ "Lcom/google/android/mms/pdu/SendReq;"
+ );
+ private static final ImmutableSet<String> PERMISSION_CONTROLLER_APK_IN_APEX_BURNDOWN_LIST =
+ ImmutableSet.of(
+ "Lcom/android/modules/utils/build/SdkLevel;",
+ "Lcom/android/settingslib/RestrictedLockUtils;"
+ );
+ // TODO: b/223837599
+ private static final ImmutableSet<String> TETHERING_APK_IN_APEX_BURNDOWN_LIST =
+ ImmutableSet.of(
+ "Landroid/hidl/base/V1_0/DebugInfo;",
+ // /system/framework/services.jar
+ "Landroid/net/DataStallReportParcelable;",
+ "Landroid/net/DhcpResultsParcelable;",
+ "Landroid/net/INetd;",
+ "Landroid/net/INetdUnsolicitedEventListener;",
+ "Landroid/net/INetworkStackConnector;",
+ "Landroid/net/INetworkStackStatusCallback;",
+ "Landroid/net/InformationElementParcelable;",
+ "Landroid/net/InitialConfigurationParcelable;",
+ "Landroid/net/InterfaceConfigurationParcel;",
+ "Landroid/net/Layer2InformationParcelable;",
+ "Landroid/net/Layer2PacketParcelable;",
+ "Landroid/net/MarkMaskParcel;",
+ "Landroid/net/NativeNetworkConfig;",
+ "Landroid/net/NattKeepalivePacketDataParcelable;",
+ "Landroid/net/NetworkTestResultParcelable;",
+ "Landroid/net/PrivateDnsConfigParcel;",
+ "Landroid/net/ProvisioningConfigurationParcelable;",
+ "Landroid/net/RouteInfoParcel;",
+ "Landroid/net/ScanResultInfoParcelable;",
+ "Landroid/net/TcpKeepalivePacketDataParcelable;",
+ "Landroid/net/TetherConfigParcel;",
+ "Landroid/net/TetherOffloadRuleParcel;",
+ "Landroid/net/TetherStatsParcel;",
+ "Landroid/net/UidRangeParcel;",
+ "Landroid/net/dhcp/DhcpLeaseParcelable;",
+ "Landroid/net/dhcp/DhcpServingParamsParcel;",
+ "Landroid/net/dhcp/IDhcpEventCallbacks;",
+ "Landroid/net/dhcp/IDhcpServer;",
+ "Landroid/net/dhcp/IDhcpServerCallbacks;",
+ "Landroid/net/ipmemorystore/Blob;",
+ "Landroid/net/ipmemorystore/NetworkAttributesParcelable;",
+ "Landroid/net/ipmemorystore/SameL3NetworkResponseParcelable;",
+ "Landroid/net/ipmemorystore/StatusParcelable;",
+ "Landroid/net/netd/aidl/NativeUidRangeConfig;",
+ "Landroid/net/networkstack/aidl/NetworkMonitorParameters;",
+ "Landroid/net/networkstack/aidl/dhcp/DhcpOption;",
+ "Landroid/net/networkstack/aidl/ip/ReachabilityLossInfoParcelable;",
+ "Landroid/net/networkstack/aidl/quirks/IPv6ProvisioningLossQuirkParcelable;",
+ "Landroid/net/shared/NetdUtils;",
+ "Landroid/net/util/NetworkConstants;",
+ "Landroid/net/util/SharedLog;",
+ "Lcom/android/modules/utils/build/SdkLevel;",
+ ///system/framework/framework.jar
+ "Landroid/util/IndentingPrintWriter;",
+ "Lcom/android/internal/annotations/Keep;"
+ );
+ // TODO: b/223836161
+ private static final ImmutableSet<String> EXTSERVICES_APK_IN_APEX_BURNDOWN_LIST =
+ ImmutableSet.of(
+ ///system/framework/framework.jar
+ "Landroid/view/displayhash/DisplayHashResultCallback;",
+ "Landroid/view/displayhash/DisplayHash;",
+ "Landroid/view/displayhash/VerifiedDisplayHash;"
+ );
+ // TODO: b/223836163
+ private static final ImmutableSet<String> ODA_APK_IN_APEX_BURNDOWN_LIST =
+ ImmutableSet.of(
+ // /apex/com.android.ondevicepersonalization/javalib/framework-ondevicepersonalization.jar
+ "Landroid/ondevicepersonalization/aidl/IInitOnDevicePersonalizationCallback;",
+ "Landroid/ondevicepersonalization/aidl/IOnDevicePersonalizationManagerService;"
+ );
+ // TODO: b/223837017
+ private static final ImmutableSet<String> CELLBROADCAST_APK_IN_APEX_BURNDOWN_LIST =
+ ImmutableSet.of(
+ // /system/framework/telephony-common.jar
+ "Lcom/android/cellbroadcastservice/CellBroadcastStatsLog;",
+ // /system/framework/framework.jar
+ "Lcom/android/internal/util/IState;",
+ "Lcom/android/internal/util/StateMachine;",
+ "Lcom/android/internal/util/State;"
+ );
+ private static final ImmutableMap<String, ImmutableSet<String>> FULL_APK_IN_APEX_BURNDOWN =
+ new ImmutableMap.Builder<String, ImmutableSet<String>>()
+ .put("/apex/com.android.bluetooth/app/Bluetooth/Bluetooth.apk",
+ BLUETOOTH_APK_IN_APEX_BURNDOWN_LIST)
+ .put("/apex/com.android.permission/priv-app/PermissionController/PermissionController.apk",
+ PERMISSION_CONTROLLER_APK_IN_APEX_BURNDOWN_LIST)
+ .put("/apex/com.android.permission/priv-app/GooglePermissionController/GooglePermissionController.apk",
+ PERMISSION_CONTROLLER_APK_IN_APEX_BURNDOWN_LIST)
+ .put("/apex/com.android.tethering/priv-app/TetheringNextGoogle/TetheringNextGoogle.apk",
+ TETHERING_APK_IN_APEX_BURNDOWN_LIST)
+ .put("/apex/com.android.tethering/priv-app/TetheringGoogle/TetheringGoogle.apk",
+ TETHERING_APK_IN_APEX_BURNDOWN_LIST)
+ .put("/apex/com.android.tethering/priv-app/TetheringNext/TetheringNext.apk",
+ TETHERING_APK_IN_APEX_BURNDOWN_LIST)
+ .put("/apex/com.android.tethering/priv-app/Tethering/Tethering.apk",
+ TETHERING_APK_IN_APEX_BURNDOWN_LIST)
+ .put("/apex/com.android.extservices/priv-app/GoogleExtServices/GoogleExtServices.apk",
+ EXTSERVICES_APK_IN_APEX_BURNDOWN_LIST)
+ .put("/apex/com.android.extservices/priv-app/ExtServices/ExtServices.apk",
+ EXTSERVICES_APK_IN_APEX_BURNDOWN_LIST)
+ .put("/apex/com.android.ondevicepersonalization/app/OnDevicePersonalizationGoogle/OnDevicePersonalizationGoogle.apk",
+ ODA_APK_IN_APEX_BURNDOWN_LIST)
+ .put("/apex/com.android.ondevicepersonalization/app/OnDevicePersonalization/OnDevicePersonalization.apk",
+ ODA_APK_IN_APEX_BURNDOWN_LIST)
+ .put("/apex/com.android.cellbroadcast/priv-app/GoogleCellBroadcastServiceModule/GoogleCellBroadcastServiceModule.apk",
+ CELLBROADCAST_APK_IN_APEX_BURNDOWN_LIST)
+ .put("/apex/com.android.cellbroadcast/priv-app/CellBroadcastServiceModule/CellBroadcastServiceModule.apk",
+ CELLBROADCAST_APK_IN_APEX_BURNDOWN_LIST)
+ .build();
/**
* Fetch all jar files in BCP, SSCP and shared libs and extract all the classes.
*
@@ -335,6 +755,8 @@
.map(sharedLibraryInfo -> sharedLibraryInfo.paths)
.flatMap(ImmutableCollection::stream)
.filter(file -> doesFileExist(file, testInfo.getDevice()))
+ // GmsCore should not contribute to *classpath.
+ .filter(file -> !file.contains("GmsCore"))
.collect(ImmutableList.toImmutableList());
final ImmutableSetMultimap.Builder<String, String> jarsToClasses =
@@ -512,6 +934,71 @@
}
/**
+ * Ensure that no apk-in-apex bundles classes that could be eclipsed by jars in
+ * BOOTCLASSPATH, SYSTEMSERVERCLASSPATH.
+ */
+ @Test
+ public void testApkInApex_nonClasspathClasses() throws Exception {
+ HashMultimap<String, Multimap<String, String>> perApkClasspathDuplicates =
+ HashMultimap.create();
+ Arrays.stream(collectApkInApexPaths())
+ .parallel()
+ .forEach(apk -> {
+ try {
+ final ImmutableSet<String> apkClasses =
+ Classpaths.getClassDefsFromJar(getDevice(), apk).stream()
+ .map(ClassDef::getType)
+ .collect(ImmutableSet.toImmutableSet());
+ final ImmutableSet<String> burndownClasses =
+ FULL_APK_IN_APEX_BURNDOWN.getOrDefault(apk, ImmutableSet.of());
+ final Multimap<String, String> duplicates =
+ Multimaps.filterValues(sJarsToClasses, apkClasses::contains);
+ final Multimap<String, String> filteredDuplicates =
+ Multimaps.filterValues(duplicates,
+ className -> !burndownClasses.contains(className));
+ if (!filteredDuplicates.isEmpty()) {
+ synchronized (perApkClasspathDuplicates) {
+ perApkClasspathDuplicates.put(apk, filteredDuplicates);
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+ assertThat(perApkClasspathDuplicates).isEmpty();
+ }
+
+ private String[] collectApkInApexPaths() {
+ try {
+ final CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
+ final String installError = getDevice().installPackage(
+ buildHelper.getTestFile(TEST_HELPER_APK), false);
+ assertWithMessage("Failed to install %s due to: %s", TEST_HELPER_APK, installError)
+ .that(installError).isNull();
+ runDeviceTests(new DeviceTestRunOptions(TEST_HELPER_PACKAGE)
+ .setDevice(getDevice())
+ .setTestClassName(TEST_HELPER_PACKAGE + ".ApexDeviceTest")
+ .setTestMethodName("testCollectApkInApexPaths"));
+ final String remoteFile = "/sdcard/apk-in-apex-paths.txt";
+ String content;
+ try {
+ content = getDevice().pullFileContents(remoteFile);
+ } finally {
+ getDevice().deleteFile(remoteFile);
+ }
+ return content.split("\n");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ } finally {
+ try {
+ getDevice().uninstallPackage(TEST_HELPER_PACKAGE);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
* Gets the duplicate classes within a list of jar files.
*
* @param jars a list of jar files.
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ApexSignatureVerificationTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ApexSignatureVerificationTest.java
index e9ab634..b73c8d7 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ApexSignatureVerificationTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ApexSignatureVerificationTest.java
@@ -19,6 +19,8 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assume.assumeTrue;
+
import android.platform.test.annotations.RestrictedBuildTest;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -190,10 +192,13 @@
try {
apexes = mDevice.getActiveApexes();
for (ITestDevice.ApexInfo ap : apexes) {
- mPreloadedApexPathMap.put(ap.name, ap.sourceDir);
+ if (!ap.sourceDir.startsWith("/data/")) {
+ mPreloadedApexPathMap.put(ap.name, ap.sourceDir);
+ }
}
- assertThat(mPreloadedApexPathMap.size()).isAtLeast(0);
+ assumeTrue("No active APEX packages or all APEX packages have been already updated",
+ mPreloadedApexPathMap.size() > 0);
} catch (DeviceNotAvailableException e) {
throw new AssertionError("getApexPackageList DeviceNotAvailableException" + e);
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index f2ca529..1bf6889 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -101,6 +101,12 @@
"android.permission.ACCESS_MEDIA_LOCATION";
private static final String PERM_READ_EXTERNAL_STORAGE =
"android.permission.READ_EXTERNAL_STORAGE";
+ private static final String PERM_READ_MEDIA_IMAGES =
+ "android.permission.READ_MEDIA_IMAGES";
+ private static final String PERM_READ_MEDIA_AUDIO =
+ "android.permission.READ_MEDIA_AUDIO";
+ private static final String PERM_READ_MEDIA_VIDEO =
+ "android.permission.READ_MEDIA_VIDEO";
private static final String PERM_WRITE_EXTERNAL_STORAGE =
"android.permission.WRITE_EXTERNAL_STORAGE";
@@ -298,6 +304,9 @@
for (int user : mUsers) {
updateAppOp(WRITE_PKG_2, user, "android:request_install_packages", true);
updatePermissions(WRITE_PKG_2, user, new String[] {
+ PERM_READ_MEDIA_IMAGES,
+ PERM_READ_MEDIA_VIDEO,
+ PERM_READ_MEDIA_AUDIO,
PERM_READ_EXTERNAL_STORAGE,
PERM_WRITE_EXTERNAL_STORAGE,
}, true);
@@ -523,6 +532,9 @@
waitForBroadcastIdle();
for (int user : mUsers) {
updatePermissions(config.pkg, user, new String[] {
+ PERM_READ_MEDIA_IMAGES,
+ PERM_READ_MEDIA_VIDEO,
+ PERM_READ_MEDIA_AUDIO,
PERM_READ_EXTERNAL_STORAGE,
PERM_WRITE_EXTERNAL_STORAGE,
}, true);
@@ -551,6 +563,9 @@
// revoke permissions
updatePermissions(MEDIA.pkg, user, new String[] {
+ PERM_READ_MEDIA_IMAGES,
+ PERM_READ_MEDIA_VIDEO,
+ PERM_READ_MEDIA_AUDIO,
PERM_READ_EXTERNAL_STORAGE,
PERM_WRITE_EXTERNAL_STORAGE,
}, false);
@@ -576,6 +591,9 @@
// revoke permissions
updatePermissions(MEDIA.pkg, user, new String[] {
+ PERM_READ_MEDIA_IMAGES,
+ PERM_READ_MEDIA_VIDEO,
+ PERM_READ_MEDIA_AUDIO,
PERM_READ_EXTERNAL_STORAGE,
PERM_WRITE_EXTERNAL_STORAGE,
}, false);
@@ -592,9 +610,11 @@
public void testGrantUriPermission() throws Exception {
doGrantUriPermission(MEDIA, "testGrantUriPermission", new String[]{});
doGrantUriPermission(MEDIA, "testGrantUriPermission",
- new String[]{PERM_READ_EXTERNAL_STORAGE});
+ new String[]{PERM_READ_MEDIA_IMAGES, PERM_READ_MEDIA_VIDEO,
+ PERM_READ_MEDIA_AUDIO, PERM_READ_EXTERNAL_STORAGE});
doGrantUriPermission(MEDIA, "testGrantUriPermission",
- new String[]{PERM_READ_EXTERNAL_STORAGE, PERM_WRITE_EXTERNAL_STORAGE});
+ new String[]{PERM_READ_EXTERNAL_STORAGE, PERM_READ_MEDIA_IMAGES,
+ PERM_READ_MEDIA_VIDEO, PERM_READ_MEDIA_AUDIO, PERM_WRITE_EXTERNAL_STORAGE});
}
@Test
@@ -613,6 +633,9 @@
for (int user : mUsers) {
// Over revoke all permissions and grant necessary permissions later.
updatePermissions(config.pkg, user, new String[] {
+ PERM_READ_MEDIA_IMAGES,
+ PERM_READ_MEDIA_VIDEO,
+ PERM_READ_MEDIA_AUDIO,
PERM_READ_EXTERNAL_STORAGE,
PERM_WRITE_EXTERNAL_STORAGE,
}, false);
@@ -638,6 +661,9 @@
installPackage(config.apk);
for (int user : mUsers) {
updatePermissions(config.pkg, user, new String[] {
+ PERM_READ_MEDIA_IMAGES,
+ PERM_READ_MEDIA_VIDEO,
+ PERM_READ_MEDIA_AUDIO,
PERM_READ_EXTERNAL_STORAGE,
PERM_WRITE_EXTERNAL_STORAGE,
}, false);
@@ -663,6 +689,9 @@
installPackage(config.apk);
for (int user : mUsers) {
updatePermissions(config.pkg, user, new String[] {
+ PERM_READ_MEDIA_IMAGES,
+ PERM_READ_MEDIA_VIDEO,
+ PERM_READ_MEDIA_AUDIO,
PERM_READ_EXTERNAL_STORAGE,
}, true);
updatePermissions(config.pkg, user, new String[] {
@@ -690,6 +719,9 @@
installPackage(config.apk);
for (int user : mUsers) {
updatePermissions(config.pkg, user, new String[] {
+ PERM_READ_MEDIA_IMAGES,
+ PERM_READ_MEDIA_VIDEO,
+ PERM_READ_MEDIA_AUDIO,
PERM_READ_EXTERNAL_STORAGE,
PERM_WRITE_EXTERNAL_STORAGE,
}, true);
@@ -708,6 +740,9 @@
// revoke all permissions
updatePermissions(MEDIA.pkg, user, new String[] {
PERM_ACCESS_MEDIA_LOCATION,
+ PERM_READ_MEDIA_IMAGES,
+ PERM_READ_MEDIA_VIDEO,
+ PERM_READ_MEDIA_AUDIO,
PERM_READ_EXTERNAL_STORAGE,
PERM_WRITE_EXTERNAL_STORAGE,
}, false);
@@ -739,6 +774,9 @@
// TODO: extend test to exercise secondary users
int user = getDevice().getCurrentUser();
updatePermissions(config.pkg, user, new String[] {
+ PERM_READ_MEDIA_IMAGES,
+ PERM_READ_MEDIA_VIDEO,
+ PERM_READ_MEDIA_AUDIO,
PERM_READ_EXTERNAL_STORAGE,
}, true);
updatePermissions(config.pkg, user, new String[] {
@@ -849,6 +887,9 @@
}, true);
// revoke permissions
updatePermissions(MEDIA.pkg, user, new String[] {
+ PERM_READ_MEDIA_IMAGES,
+ PERM_READ_MEDIA_VIDEO,
+ PERM_READ_MEDIA_AUDIO,
PERM_READ_EXTERNAL_STORAGE,
PERM_WRITE_EXTERNAL_STORAGE,
}, false);
@@ -879,6 +920,9 @@
int user = getDevice().getCurrentUser();
// grant permissions
updatePermissions(MEDIA.pkg, user, new String[] {
+ PERM_READ_MEDIA_IMAGES,
+ PERM_READ_MEDIA_VIDEO,
+ PERM_READ_MEDIA_AUDIO,
PERM_READ_EXTERNAL_STORAGE,
PERM_ACCESS_MEDIA_LOCATION,
}, true);
@@ -912,6 +956,9 @@
int user = getDevice().getCurrentUser();
// grant permissions
updatePermissions(MEDIA.pkg, user, new String[] {
+ PERM_READ_MEDIA_IMAGES,
+ PERM_READ_MEDIA_VIDEO,
+ PERM_READ_MEDIA_AUDIO,
PERM_READ_EXTERNAL_STORAGE,
}, true);
// revoke permission
@@ -949,6 +996,9 @@
int user = getDevice().getCurrentUser();
// grant permissions
updatePermissions(MEDIA.pkg, user, new String[] {
+ PERM_READ_MEDIA_IMAGES,
+ PERM_READ_MEDIA_VIDEO,
+ PERM_READ_MEDIA_AUDIO,
PERM_READ_EXTERNAL_STORAGE,
PERM_ACCESS_MEDIA_LOCATION,
}, true);
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/MediaStorageApp/AndroidManifest.xml
index 64f7657..4065604 100644
--- a/hostsidetests/appsecurity/test-apps/MediaStorageApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/AndroidManifest.xml
@@ -39,6 +39,9 @@
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_MEDIA"/>
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
+ <uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
+ <uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
diff --git a/hostsidetests/car/src/android/car/cts/CarTelemetryHostTest.java b/hostsidetests/car/src/android/car/cts/CarTelemetryHostTest.java
index 779d405..af23b2b 100644
--- a/hostsidetests/car/src/android/car/cts/CarTelemetryHostTest.java
+++ b/hostsidetests/car/src/android/car/cts/CarTelemetryHostTest.java
@@ -20,7 +20,8 @@
import static org.junit.Assume.assumeTrue;
-import com.android.car.telemetry.TelemetryProto;
+import android.car.telemetry.TelemetryProto;
+
import com.android.compatibility.common.util.PollingCheck;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
diff --git a/hostsidetests/classloaders/OWNERS b/hostsidetests/classloaders/OWNERS
index e7c6bf7..18f4805 100644
--- a/hostsidetests/classloaders/OWNERS
+++ b/hostsidetests/classloaders/OWNERS
@@ -1,6 +1,8 @@
# Bug component: 86431
-calin@google.com
+jiakaiz@google.com
+mast@google.com
ngeoffray@google.com
oth@google.com
+rpl@google.com
skvadrik@google.com
-vmarko@google.com
\ No newline at end of file
+vmarko@google.com
diff --git a/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java b/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java
index edcfaa4..d4a1164 100644
--- a/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java
+++ b/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java
@@ -18,15 +18,22 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.google.common.io.ByteStreams;
-import junit.framework.Assert;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
import java.io.File;
import java.io.FileOutputStream;
@@ -40,13 +47,21 @@
/**
* Tests background dex optimization which runs as idle job.
*/
-public final class BackgroundDexOptimizationTest extends DeviceTestCase {
+@RunWith(DeviceJUnit4ClassRunner.class)
+// Tests for post boot optimization must run first because they reboot the device into a clean
+// state, which can benefit other tests so that they don't have to reboot again.
+// Tests for idle optimizations won't work without a reboot in some cases. See
+// `testIdleOptimization*` for more details. However, we can't do a reboot for every test case
+// because it will cause the test to time out.
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public final class BackgroundDexOptimizationTest extends BaseHostJUnit4Test {
private static final long REBOOT_TIMEOUT_MS = 600_000;
+ private static final long JOB_START_TIMEOUT_MS = 10_000;
private static final long DEXOPT_TIMEOUT_MS = 1_200_000;
// Cancel should be faster. It will be usually much shorter but we cannot make it too short
// as CTS cannot enforce unspecified performance.
private static final long DEXOPT_CANCEL_TIMEOUT_MS = 10_000;
- private static final long POLLING_TIME_SLICE = 2;
+ private static final long POLLING_TIME_SLICE = 200;
private static final String CMD_DUMP_PACKAGE_DEXOPT = "dumpsys -t 100 package dexopt";
@@ -70,31 +85,33 @@
private ITestDevice mDevice;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
+ @Before
+ public void setUp() throws Exception {
mDevice = getDevice();
- // Should reboot to put the device into known states (= post boot optimization not run yet).
- mDevice.reboot();
- assertThat(mDevice.waitForBootComplete(REBOOT_TIMEOUT_MS)).isTrue();
- // This requires PackageManager to be alive. So run after reboot as the previous failure
- // may have device in booting state.
- assumeTrue(checkDexOptEnabled());
}
- public void testPostBootOptimizationCompleted() throws Exception {
+ @Test
+ // Add an "A" in the name to make it run before other tests.
+ public void testAPostBootOptimizationCompleted() throws Exception {
+ // Should reboot to put the device into known states (= post boot optimization not run yet).
+ rebootAndCheckDexOptEnabled();
+
// Note that post boot job runs only once until it is completed.
completePostBootOptimization();
}
- public void testPostBootOptimizationCancelled() throws Exception {
+ @Test
+ // Add an "A" in the name to make it run before other tests.
+ public void testAPostBootOptimizationCancelled() throws Exception {
+ // Should reboot to put the device into known states (= post boot optimization not run yet).
+ rebootAndCheckDexOptEnabled();
+
reinstallAppPackage();
LastDeviceExecutionTime timeBefore = getLastExecutionTime();
postJobSchedulerJob(CMD_START_POST_BOOT);
// Wait until it is started.
- pollingCheck("Post boot start timeout", DEXOPT_TIMEOUT_MS,
+ pollingCheck("Post boot start timeout", JOB_START_TIMEOUT_MS,
() -> getLastExecutionTime().startTime >= timeBefore.deviceCurrentTime);
// Now cancel it.
@@ -116,23 +133,39 @@
}
}
+ @Test
public void testIdleOptimizationCompleted() throws Exception {
- completePostBootOptimization();
+ assumeTrue(checkDexOptEnabled());
+ // We check if post boot optimization is completed, and wait for it to be completed if not.
+ // Note that this won't work if the system server has been restarted (e.g., by a `stop &&
+ // start`) AND this test case is run individually, in which case,
+ // `checkFinishedPostBootUpdate` will return false because the system server will lose track
+ // of a completed post boot optimization run, but `completePostBootOptimization` will get
+ // stuck retrying to start the job since it has already completed.
+ ensurePostBootOptimizationCompleted();
completeIdleOptimization();
// idle job can run again.
completeIdleOptimization();
}
+ @Test
public void testIdleOptimizationCancelled() throws Exception {
- completePostBootOptimization();
+ assumeTrue(checkDexOptEnabled());
+ // We check if post boot optimization is completed, and wait for it to be completed if not.
+ // Note that this won't work if the system server has been restarted (e.g., by a `stop &&
+ // start`) AND this test case is run individually, in which case,
+ // `checkFinishedPostBootUpdate` will return false because the system server will lose track
+ // of a completed post boot optimization run, but `completePostBootOptimization` will get
+ // stuck retrying to start the job since it has already completed.
+ ensurePostBootOptimizationCompleted();
reinstallAppPackage();
LastDeviceExecutionTime timeBefore = getLastExecutionTime();
postJobSchedulerJob(CMD_START_IDLE);
// Wait until it is started.
- pollingCheck("Idle start timeout", DEXOPT_TIMEOUT_MS,
+ pollingCheck("Idle start timeout", JOB_START_TIMEOUT_MS,
() -> getLastExecutionTime().startTime >= timeBefore.deviceCurrentTime);
// Now cancel it.
@@ -189,13 +222,12 @@
assertThat(status).isEqualTo(STATUS_OK);
}
- @Override
- protected void tearDown() throws Exception {
+ @After
+ public void tearDown() throws Exception {
// Cancel all active dexopt jobs.
executeShellCommand(CMD_CANCEL_IDLE);
executeShellCommand(CMD_CANCEL_POST_BOOT);
mDevice.uninstallPackage(APPLICATION_PACKAGE);
- super.tearDown();
}
private void postJobSchedulerJob(String cmd) throws Exception {
@@ -315,7 +347,21 @@
Thread.sleep(POLLING_TIME_SLICE);
}
- Assert.fail(message.toString());
+ fail(message.toString());
+ }
+
+ private void rebootAndCheckDexOptEnabled() throws Exception {
+ mDevice.reboot();
+ assertThat(mDevice.waitForBootComplete(REBOOT_TIMEOUT_MS)).isTrue();
+ // This requires PackageManager to be alive. So run after reboot as the previous failure
+ // may have device in booting state.
+ assumeTrue(checkDexOptEnabled());
+ }
+
+ private void ensurePostBootOptimizationCompleted() throws Exception {
+ if (!checkFinishedPostBootUpdate()) {
+ completePostBootOptimization();
+ }
}
private static class LastDeviceExecutionTime {
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/BlockUninstallDelegateTest.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/BlockUninstallDelegateTest.java
deleted file mode 100644
index a4dffde..0000000
--- a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/BlockUninstallDelegateTest.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.delegate;
-
-import static android.app.admin.DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL;
-
-import static com.android.cts.delegate.DelegateTestUtils.assertExpectException;
-
-import android.app.admin.DevicePolicyManager;
-
-import java.util.List;
-
-/**
- * Test that an app given the {@link DevicePolicyManager#DELEGATION_BLOCK_UNINSTALL} scope via
- * {@link DevicePolicyManager#setDelegatedScopes} can choose packages that are block uninstalled.
- */
-public class BlockUninstallDelegateTest extends BaseJUnit3TestCase {
-
- private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
-
- public void testCannotAccessApis() {
- assertFalse("DelegateApp should not be a block uninstall delegate",
- amIBlockUninstallDelegate());
-
- assertExpectException(SecurityException.class,
- "Calling identity is not authorized", () -> {
- mDpm.setUninstallBlocked(null, TEST_APP_PKG, true);
- });
- }
-
- public void testCanAccessApis() {
- assertTrue("DelegateApp is not a block uninstall delegate",
- amIBlockUninstallDelegate());
- try {
- // Exercise setUninstallBlocked.
- mDpm.setUninstallBlocked(null, TEST_APP_PKG, true);
- assertTrue("App not uninstall blocked", mDpm.isUninstallBlocked(null, TEST_APP_PKG));
- } finally {
- mDpm.setUninstallBlocked(null, TEST_APP_PKG, false);
- assertFalse("App still uninstall blocked", mDpm.isUninstallBlocked(null, TEST_APP_PKG));
- }
- }
-
- private boolean amIBlockUninstallDelegate() {
- final String packageName = getInstrumentation().getContext().getPackageName();
- final List<String> scopes = mDpm.getDelegatedScopes(null, packageName);
- return scopes.contains(DELEGATION_BLOCK_UNINSTALL);
- }
-}
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/EnableSystemAppDelegateTest.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/EnableSystemAppDelegateTest.java
deleted file mode 100644
index f8c4225..0000000
--- a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/EnableSystemAppDelegateTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.delegate;
-
-import static android.app.admin.DevicePolicyManager.DELEGATION_ENABLE_SYSTEM_APP;
-
-import static com.android.cts.delegate.DelegateTestUtils.assertExpectException;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.Intent;
-
-import java.util.List;
-
-/**
- * Test that an app given the {@link DevicePolicyManager#DELEGATION_PERMISSION_GRANT} scope via
- * {@link DevicePolicyManager#setDelegatedScopes} can grant permissions and check permission grant
- * state.
- */
-public class EnableSystemAppDelegateTest extends BaseJUnit3TestCase {
-
- private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
-
- public void testCannotAccessApis() {
- assertFalse("DelegateApp should not be an enable system app delegate",
- amIEnableSystemAppDelegate());
-
- // Exercise enableSystemApp(String).
- assertExpectException(SecurityException.class,
- "Calling identity is not authorized", () -> {
- mDpm.enableSystemApp(null, TEST_APP_PKG);
- });
-
- // Exercise enableSystemApp(Intent).
- assertExpectException(SecurityException.class,
- "Calling identity is not authorized", () -> {
- mDpm.enableSystemApp(null, new Intent().setPackage(TEST_APP_PKG));
- });
- }
-
- public void testCanAccessApis() {
- assertTrue("DelegateApp is not an enable system app delegate",
- amIEnableSystemAppDelegate());
-
- // Exercise enableSystemApp(String).
- assertExpectException(IllegalArgumentException.class,
- "Only system apps can be enabled this way", () -> {
- mDpm.enableSystemApp(null, TEST_APP_PKG);
- });
-
- // Exercise enableSystemApp(Intent).
- mDpm.enableSystemApp(null, new Intent());
- }
-
- private boolean amIEnableSystemAppDelegate() {
- final String packageName = getInstrumentation().getContext().getPackageName();
- final List<String> scopes = mDpm.getDelegatedScopes(null, packageName);
- return scopes.contains(DELEGATION_ENABLE_SYSTEM_APP);
- }
-}
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/NetworkLoggingDelegateTest.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/NetworkLoggingDelegateTest.java
deleted file mode 100644
index 72dbd7c..0000000
--- a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/NetworkLoggingDelegateTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.delegate;
-
-import static android.app.admin.DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE;
-
-import static com.android.cts.delegate.DelegateTestUtils.assertExpectException;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.IntentFilter;
-import android.os.UserManager;
-import android.util.Log;
-
-import com.android.bedstead.dpmwrapper.TestAppHelper;
-import com.android.cts.delegate.DelegateTestUtils.DelegatedLogsReceiver;
-
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.concurrent.CountDownLatch;
-
-/**
- * Tests that a delegate app with DELEGATION_NETWORK_LOGGING is able to control and access
- * network logging.
- */
-public final class NetworkLoggingDelegateTest extends BaseJUnit3TestCase {
-
- private static final String TAG = "NetworkLoggingDelegateTest";
-
- private static final String[] URL_LIST = {
- "example.edu",
- "ipv6.google.com",
- "google.co.jp",
- "google.fr",
- "google.com.br",
- "google.com.tr",
- "google.co.uk",
- "google.de"
- };
-
- // TODO(b/176993670): receiver needed to forward intents from device owner user to current user
- // on headless system user mode. Might be removed once tests are refactor to use proper IPC.
- private DelegatedLogsReceiver mReceiver;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- if (UserManager.isHeadlessSystemUserMode()) {
- mReceiver = new DelegatedLogsReceiver();
- TestAppHelper.registerTestCaseReceiver(mContext, mReceiver,
- new IntentFilter(ACTION_NETWORK_LOGS_AVAILABLE));
- }
-
- DelegatedLogsReceiver.sBatchCountDown = new CountDownLatch(1);
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
-
- if (mReceiver != null) {
- TestAppHelper.unregisterTestCaseReceiver(mContext, mReceiver);
- }
- }
-
-
- public void testCanAccessApis() throws Throwable {
- assertThat(mDpm.getDelegatedScopes(null, mContext.getPackageName())).contains(
- DevicePolicyManager.DELEGATION_NETWORK_LOGGING);
- testNetworkLogging();
- }
-
- public void testCannotAccessApis()throws Exception {
- assertExpectException(SecurityException.class, null,
- () -> mDpm.isNetworkLoggingEnabled(null));
-
- assertExpectException(SecurityException.class, null,
- () -> mDpm.setNetworkLoggingEnabled(null, true));
-
- assertExpectException(SecurityException.class, null,
- () -> mDpm.retrieveNetworkLogs(null, 0));
- }
-
- public void testNetworkLogging() throws Throwable {
- mDpm.setNetworkLoggingEnabled(null, true);
- assertTrue(mDpm.isNetworkLoggingEnabled(null));
-
- try {
- for (final String url : URL_LIST) {
- connectToWebsite(url);
- }
- mDevice.executeShellCommand("dpm force-network-logs");
-
- DelegateTestUtils.DelegatedLogsReceiver.waitForBroadcast();
- } finally {
- mDpm.setNetworkLoggingEnabled(null, false);
- assertFalse(mDpm.isNetworkLoggingEnabled(null));
- }
- }
-
- private void connectToWebsite(String server) throws Exception {
- final URL url = new URL("http://" + server);
- HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
- try (AutoCloseable ac = () -> urlConnection.disconnect()){
- urlConnection.setConnectTimeout(2000);
- urlConnection.setReadTimeout(2000);
- urlConnection.getResponseCode();
- } catch (IOException e) {
- Log.w(TAG, "Failed to connect to " + server, e);
- }
- }
-}
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/PackageAccessDelegateTest.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/PackageAccessDelegateTest.java
deleted file mode 100644
index c996e5f..0000000
--- a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/PackageAccessDelegateTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.delegate;
-
-import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
-
-import static com.android.cts.delegate.DelegateTestUtils.assertExpectException;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-
-import java.util.List;
-
-/**
- * Test that an app given the {@link DevicePolicyManager#DELEGATION_PACKAGE_ACCESS} scope via
- * {@link DevicePolicyManager#setDelegatedScopes} can manage package hide and suspend status.
- */
-public class PackageAccessDelegateTest extends BaseJUnit3TestCase {
-
- private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
-
- public void testCannotAccessApis() throws NameNotFoundException {
- assertFalse("DelegateApp should not be a package access delegate",
- amIPackageAccessDelegate());
-
- // Exercise isApplicationHidden.
- assertExpectException(SecurityException.class,
- "Calling identity is not authorized", () -> {
- mDpm.isApplicationHidden(null, TEST_APP_PKG);
- });
-
- // Exercise setApplicationHidden.
- assertExpectException(SecurityException.class,
- "Calling identity is not authorized", () -> {
- mDpm.setApplicationHidden(null, TEST_APP_PKG, true /* hide */);
- });
-
- // Exercise isPackageSuspended.
- assertExpectException(SecurityException.class,
- "Calling identity is not authorized", () -> {
- mDpm.isPackageSuspended(null, TEST_APP_PKG);
- });
-
- // Exercise setPackagesSuspended.
- assertExpectException(SecurityException.class,
- "Calling identity is not authorized", () -> {
- mDpm.setPackagesSuspended(null, new String[] {TEST_APP_PKG}, true /* suspend */);
- });
- }
-
- public void testCanAccessApis() throws NameNotFoundException {
- assertTrue("DelegateApp is not a package access delegate", amIPackageAccessDelegate());
-
- // Exercise isApplicationHidden.
- assertFalse("Package should not be hidden", mDpm.isApplicationHidden(null, TEST_APP_PKG));
-
- // Exercise setApplicationHidden.
- assertTrue("Package not hidden successfully",
- mDpm.setApplicationHidden(null, TEST_APP_PKG, true /* hide */));
- assertTrue("Package should be hidden", mDpm.isApplicationHidden(null, TEST_APP_PKG));
-
- // Exercise isPackageSuspended.
- assertFalse("Package should not be suspended", mDpm.isPackageSuspended(null, TEST_APP_PKG));
-
- // Exercise setPackagesSuspended.
- String[] suspended = mDpm.setPackagesSuspended(null, new String[] {TEST_APP_PKG},
- true /* suspend */);
- assertTrue("Package not suspended successfully", suspended.length == 0);
- assertTrue("Package should be suspended", mDpm.isPackageSuspended(null, TEST_APP_PKG));
- }
-
- private boolean amIPackageAccessDelegate() {
- final String packageName = getInstrumentation().getContext().getPackageName();
- final List<String> scopes = mDpm.getDelegatedScopes(null, packageName);
- return scopes.contains(DELEGATION_PACKAGE_ACCESS);
- }
-}
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/PermissionGrantDelegateTest.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/PermissionGrantDelegateTest.java
deleted file mode 100644
index 9c6ac58..0000000
--- a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/PermissionGrantDelegateTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.delegate;
-
-import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
-import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED;
-import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED;
-import static android.app.admin.DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY;
-import static android.app.admin.DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT;
-
-import static com.android.cts.delegate.DelegateTestUtils.assertExpectException;
-
-import android.app.admin.DevicePolicyManager;
-
-import java.util.List;
-
-/**
- * Test that an app given the {@link DevicePolicyManager#DELEGATION_PERMISSION_GRANT} scope via
- * {@link DevicePolicyManager#setDelegatedScopes} can grant permissions and check permission grant
- * state.
- */
-public class PermissionGrantDelegateTest extends BaseJUnit3TestCase {
-
- private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
- private static final String TEST_PERMISSION = "android.permission.READ_CONTACTS";
-
- public void testCannotAccessApis() {
- assertFalse("DelegateApp should not be a permisssion grant delegate",
- amIPermissionGrantDelegate());
-
- // Exercise setPermissionPolicy.
- assertExpectException(SecurityException.class,
- "Calling identity is not authorized", () -> {
- mDpm.setPermissionPolicy(null, PERMISSION_POLICY_AUTO_GRANT);
- });
- assertFalse("Permission policy should not have been set",
- PERMISSION_POLICY_AUTO_GRANT == mDpm.getPermissionPolicy(null));
-
- // Exercise setPermissionGrantState.
- assertExpectException(SecurityException.class,
- "Calling identity is not authorized", () -> {
- mDpm.setPermissionGrantState(null, TEST_APP_PKG, TEST_PERMISSION,
- PERMISSION_GRANT_STATE_GRANTED);
- });
-
- // Exercise getPermissionGrantState.
- assertExpectException(SecurityException.class,
- "Calling identity is not authorized", () -> {
- mDpm.getPermissionGrantState(null, TEST_APP_PKG, TEST_PERMISSION);
- });
- }
-
- public void testCanAccessApis() {
- assertTrue("DelegateApp is not a permission grant delegate",
- amIPermissionGrantDelegate());
-
- // Exercise setPermissionPolicy.
- mDpm.setPermissionPolicy(null, PERMISSION_POLICY_AUTO_DENY);
- assertTrue("Permission policy was not set",
- PERMISSION_POLICY_AUTO_DENY == mDpm.getPermissionPolicy(null));
-
- // Exercise setPermissionGrantState.
- assertTrue("Permission grant state was not set successfully",
- mDpm.setPermissionGrantState(null, TEST_APP_PKG, TEST_PERMISSION,
- PERMISSION_GRANT_STATE_DENIED));
-
- // Exercise getPermissionGrantState.
- assertEquals("Permission grant state is not denied", PERMISSION_GRANT_STATE_DENIED,
- mDpm.getPermissionGrantState(null, TEST_APP_PKG, TEST_PERMISSION));
- }
-
- private boolean amIPermissionGrantDelegate() {
- final String packageName = getInstrumentation().getContext().getPackageName();
- final List<String> scopes = mDpm.getDelegatedScopes(null, packageName);
- return scopes.contains(DELEGATION_PERMISSION_GRANT);
- }
-}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java
index baaac8d3..88e4452 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java
@@ -177,11 +177,6 @@
mDevicePolicyManager.enableSystemApp(ADMIN_RECEIVER_COMPONENT, intent);
}
- public void testSetUninstallBlockedLogged() {
- mDevicePolicyManager.setUninstallBlocked(ADMIN_RECEIVER_COMPONENT, PACKAGE_NAME, true);
- mDevicePolicyManager.setUninstallBlocked(ADMIN_RECEIVER_COMPONENT, PACKAGE_NAME, false);
- }
-
public void testSetPreferentialNetworkServiceEnabledLogged() {
mDevicePolicyManager.setPreferentialNetworkServiceEnabled(true);
mDevicePolicyManager.setPreferentialNetworkServiceEnabled(false);
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
index 2707856..3c4f75b 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
@@ -104,6 +104,8 @@
.add("setPermittedInputMethods")
.add("getDrawable")
.add("getDrawableForDensity")
+ .add("getDevicePolicyManagementRoleHolderPackage")
+ .add("getDrawableAsIcon")
.build();
private static final String LOG_TAG = "ParentProfileTest";
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivity.java b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivity.java
index 918094c..5e1f248 100644
--- a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivity.java
+++ b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivity.java
@@ -20,10 +20,10 @@
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
+import android.view.WindowInsets;
+import android.view.WindowInsetsController;
import android.view.WindowManager;
-import java.lang.Override;
-
/**
* A simple activity to install for various users to test LauncherApps.
*/
@@ -46,6 +46,11 @@
Intent reply = new Intent();
reply.setAction(ACTIVITY_LAUNCHED_ACTION);
sendBroadcast(reply);
+
+ final WindowInsetsController insetsController = getWindow().getInsetsController();
+ if (insetsController != null) {
+ insetsController.hide(WindowInsets.Type.navigationBars());
+ }
}
@Override
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index a1cbf9f..7f3be30 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -30,7 +30,6 @@
import com.android.cts.devicepolicy.DeviceAdminFeaturesCheckerRule.TemporarilyIgnoreOnHeadlessSystemUserMode;
import com.android.cts.devicepolicy.annotations.LockSettingsTest;
-import com.android.cts.devicepolicy.metrics.DevicePolicyEventLogVerifier;
import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.log.LogUtil.CLog;
@@ -44,7 +43,6 @@
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -82,21 +80,12 @@
private static final String SIMPLE_PRE_M_APP_PKG = "com.android.cts.launcherapps.simplepremapp";
private static final String SIMPLE_PRE_M_APP_APK = "CtsSimplePreMApp.apk";
- private static final String APP_RESTRICTIONS_TARGET_APP_PKG
- = "com.android.cts.apprestrictions.targetapp";
- private static final String APP_RESTRICTIONS_TARGET_APP_APK = "CtsAppRestrictionsTargetApp.apk";
-
public static final String CERT_INSTALLER_PKG = "com.android.cts.certinstaller";
public static final String CERT_INSTALLER_APK = "CtsCertInstallerApp.apk";
protected static final String DELEGATE_APP_PKG = "com.android.cts.delegate";
protected static final String DELEGATE_APP_APK = "CtsDelegateApp.apk";
private static final String DELEGATION_CERT_INSTALL = "delegation-cert-install";
- private static final String DELEGATION_APP_RESTRICTIONS = "delegation-app-restrictions";
- private static final String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
- private static final String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant";
- private static final String DELEGATION_PACKAGE_ACCESS = "delegation-package-access";
- private static final String DELEGATION_ENABLE_SYSTEM_APP = "delegation-enable-system-app";
private static final String DELEGATION_CERT_SELECTION = "delegation-cert-selection";
protected static final String TEST_APP_APK = "CtsSimpleApp.apk";
@@ -106,23 +95,13 @@
protected static final String PACKAGE_INSTALLER_PKG = "com.android.cts.packageinstaller";
protected static final String PACKAGE_INSTALLER_APK = "CtsPackageInstallerApp.apk";
- private static final String ACCOUNT_MANAGEMENT_PKG
- = "com.android.cts.devicepolicy.accountmanagement";
- private static final String ACCOUNT_MANAGEMENT_APK = "CtsAccountManagementDevicePolicyApp.apk";
-
private static final String VPN_APP_PKG = "com.android.cts.vpnfirewall";
private static final String VPN_APP_APK = "CtsVpnFirewallApp.apk";
private static final String VPN_APP_API23_APK = "CtsVpnFirewallAppApi23.apk";
private static final String VPN_APP_API24_APK = "CtsVpnFirewallAppApi24.apk";
private static final String VPN_APP_NOT_ALWAYS_ON_APK = "CtsVpnFirewallAppNotAlwaysOn.apk";
- private static final String COMMAND_BLOCK_ACCOUNT_TYPE = "block-accounttype";
- private static final String COMMAND_UNBLOCK_ACCOUNT_TYPE = "unblock-accounttype";
-
- private static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
private static final String DISALLOW_REMOVE_USER = "no_remove_user";
- private static final String ACCOUNT_TYPE
- = "com.android.cts.devicepolicy.accountmanagement.account.type";
private static final String CUSTOMIZATION_APP_PKG = "com.android.cts.customizationapp";
private static final String CUSTOMIZATION_APP_APK = "CtsCustomizationApp.apk";
@@ -158,9 +137,6 @@
protected static final String ASSIST_INTERACTION_SERVICE =
ASSIST_APP_PKG + "/.MyInteractionService";
- private static final String ARG_ALLOW_FAILURE = "allowFailure";
- private static final String ARG_LOGGING_TEST = "loggingTest";
-
private static final String RESTRICT_BACKGROUND_GET_CMD =
"cmd netpolicy get restrict-background";
private static final String RESTRICT_BACKGROUND_ON_CMD =
@@ -199,10 +175,8 @@
getDevice().uninstallPackage(DEVICE_ADMIN_PKG);
getDevice().uninstallPackage(PERMISSIONS_APP_PKG);
getDevice().uninstallPackage(SIMPLE_PRE_M_APP_PKG);
- getDevice().uninstallPackage(APP_RESTRICTIONS_TARGET_APP_PKG);
getDevice().uninstallPackage(CERT_INSTALLER_PKG);
getDevice().uninstallPackage(DELEGATE_APP_PKG);
- getDevice().uninstallPackage(ACCOUNT_MANAGEMENT_PKG);
getDevice().uninstallPackage(VPN_APP_PKG);
getDevice().uninstallPackage(VPN_APP_API23_APK);
getDevice().uninstallPackage(VPN_APP_API24_APK);
@@ -234,93 +208,6 @@
"testAssertCallerIsApplicationRestrictionsManagingPackage", mUserId);
}
- /**
- * Returns a list of delegation tests that should run. Add delegations tests applicable to both
- * device owner and profile owners to this method directly. DO or PO specific tests should be
- * added to {@link #getAdditionalDelegationTests} in the subclass.
- */
- private Map<String, DevicePolicyEventWrapper[]> getDelegationTests() {
- final Map<String, DevicePolicyEventWrapper[]> result = new HashMap<>();
- result.put(".BlockUninstallDelegateTest", null);
- result.put(".PermissionGrantDelegateTest", null);
- result.put(".PackageAccessDelegateTest", null);
- result.put(".EnableSystemAppDelegateTest", null);
- result.putAll(getAdditionalDelegationTests());
- return result;
- }
-
- Map<String, DevicePolicyEventWrapper[]> getAdditionalDelegationTests() {
- return Collections.<String, DevicePolicyEventWrapper[]>emptyMap();
- }
-
- /**
- * Returns a list of delegation scopes that are needed to run delegation tests. Add scopes
- * which are applicable to both device owner and profile owners to this method directly.
- * DO or PO specific scopes should be added to {@link #getAdditionalDelegationScopes}
- * in the subclass.
- */
- private List<String> getDelegationScopes() {
- final List<String> result = new ArrayList<>(Arrays.asList(
- DELEGATION_APP_RESTRICTIONS,
- DELEGATION_CERT_INSTALL,
- DELEGATION_BLOCK_UNINSTALL,
- DELEGATION_PERMISSION_GRANT,
- DELEGATION_PACKAGE_ACCESS,
- DELEGATION_ENABLE_SYSTEM_APP
- ));
- result.addAll(getAdditionalDelegationScopes());
- return result;
- }
-
- List<String> getAdditionalDelegationScopes() {
- return Collections.<String>emptyList();
- }
-
- /**
- * General instructions to add a new delegation test:
- *
- * <p>Implement the delegate's positive/negate functionaility tests in a new test class
- * in CtsDelegateApp.apk. Main entry point are {@code testCanAccessApis} and
- * {@code testCannotAccessApis}. Once implemented, add the delegation scope and the test
- * class name to {@link #getDelegationScopes}, {@link #getDelegationTests} to make the test
- * run on DO/PO/PO on primary user. If the test should only run on a subset of these
- * combinations, add them to the subclass's {@link #getAdditionalDelegationScopes} and
- * {@link #getDelegationScopes} instead.
- * <p>Alternatively, create a separate hostside method to drive the test, similar to
- * {@link #testDelegationCertSelection}. This is preferred if the delegated functionalities
- * already exist in another app.
- */
- @Test
- public void testDelegation() throws Exception {
- // Install relevant apps.
- installDelegateApp();
- installAppAsUser(TEST_APP_APK, mUserId);
- installAppAsUser(APP_RESTRICTIONS_TARGET_APP_APK, mUserId);
- if (isHeadlessSystemUserMode()) {
- installAppAsUser(TEST_APP_APK, mDeviceOwnerUserId);
- installAppAsUser(APP_RESTRICTIONS_TARGET_APP_APK, mDeviceOwnerUserId);
- }
-
- try {
- final Map<String, DevicePolicyEventWrapper[]> delegationTests = getDelegationTests();
- // APIs are not accessible by default.
- executeDelegationTests(delegationTests, false /* negative result */);
-
- // Granting the appropriate delegation scopes makes APIs accessible.
- final List<String> scopes = getDelegationScopes();
- setDelegatedScopes(DELEGATE_APP_PKG, scopes);
- executeDelegationTests(delegationTests, true /* positive result */);
-
- // APIs are not accessible after revoking delegations.
- setDelegatedScopes(DELEGATE_APP_PKG, null);
- executeDelegationTests(delegationTests, false /* negative result */);
-
- } finally {
- // Remove any remaining delegations.
- setDelegatedScopes(DELEGATE_APP_PKG, null);
- }
- }
-
protected void installDelegateApp() throws Exception {
installAppAsUser(DELEGATE_APP_APK, mUserId);
}
@@ -1547,19 +1434,6 @@
}
@Test
- public void testSetUninstallBlockedLogged() throws Exception {
- installAppAsUser(PERMISSIONS_APP_APK, mUserId);
- assertMetricsLogged(getDevice(), () -> {
- executeDeviceTestMethod(".DevicePolicyLoggingTest",
- "testSetUninstallBlockedLogged");
- }, new DevicePolicyEventWrapper.Builder(EventId.SET_UNINSTALL_BLOCKED_VALUE)
- .setAdminPackageName(DEVICE_ADMIN_PKG)
- .setBoolean(false)
- .setStrings(PERMISSIONS_APP_PKG)
- .build());
- }
-
- @Test
public void testIsDeviceOrganizationOwnedWithManagedProfile() throws Exception {
executeDeviceTestMethod(".DeviceOwnershipTest",
"testCallingIsOrganizationOwnedWithManagedProfileExpectingFalse");
@@ -1684,57 +1558,11 @@
runDeviceTestsAsUser(INTENT_SENDER_PKG, ".SuspendPackageTest", testName, mUserId);
}
- private void executeAccountTest(String testName) throws DeviceNotAvailableException {
- runDeviceTestsAsUser(ACCOUNT_MANAGEMENT_PKG, ".AccountManagementTest",
- testName, mUserId);
- // Send a home intent to dismiss an error dialog.
- String command = "am start -a android.intent.action.MAIN"
- + " -c android.intent.category.HOME";
- CLog.i("Output for command " + command + ": " + getDevice().executeShellCommand(command));
- }
-
- private void executeAppRestrictionsManagingPackageTest(String testName) throws Exception {
- runDeviceTestsAsUser(DELEGATE_APP_PKG,
- ".AppRestrictionsDelegateTest", testName, mUserId);
- }
-
- private void executeDelegationTests(Map<String, DevicePolicyEventWrapper[]> delegationTests,
- boolean positive)
- throws Exception {
- for (Map.Entry<String, DevicePolicyEventWrapper[]> entry : delegationTests.entrySet()) {
- final String delegationTestClass = entry.getKey();
- CLog.i("executeDelegationTests(): executing %s (%s)", delegationTestClass,
- positive ? "positive" : "negative");
- final DevicePolicyEventWrapper[] expectedMetrics = entry.getValue();
- final DevicePolicyEventLogVerifier.Action testRun = () -> {
- runDeviceTestsAsUser(DELEGATE_APP_PKG, delegationTestClass,
- positive ? "testCanAccessApis" : "testCannotAccessApis", mUserId);
- };
- if (expectedMetrics != null && positive) {
- assertMetricsLogged(getDevice(), testRun, expectedMetrics);
- } else {
- testRun.apply();
- }
- }
- }
-
private void changeUserRestrictionOrFail(String key, boolean value, int userId)
throws DeviceNotAvailableException {
changeUserRestrictionOrFail(key, value, userId, DEVICE_ADMIN_PKG);
}
- private void changeAccountManagement(String command, String accountType, int userId)
- throws DeviceNotAvailableException {
- changePolicyOrFail(command, "--es extra-account-type " + accountType, userId);
- }
-
- private void changeApplicationRestrictionsManagingPackage(String packageName)
- throws DeviceNotAvailableException {
- String packageNameExtra = (packageName != null)
- ? "--es extra-package-name " + packageName : "";
- changePolicyOrFail("set-app-restrictions-manager", packageNameExtra, mUserId);
- }
-
protected void setDelegatedScopes(String packageName, List<String> scopes)
throws DeviceNotAvailableException {
final String packageNameExtra = "--es extra-package-name " + packageName;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 2087326..6080a3c 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -516,6 +516,10 @@
"addCrossProfileIntents", mProfileUserId);
runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileSharingTest",
"startSwitchToOtherProfileIntent", mProfileUserId);
+
+ // TODO(b/223178698): Investigate potential increase in latency
+ Thread.sleep(30000);
+
assertResolverActivityInForeground(mProfileUserId);
} finally {
pressHome();
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
index 1cde96f..7326b8b 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
@@ -36,10 +36,8 @@
import org.junit.Test;
import java.io.FileNotFoundException;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
/**
@@ -48,9 +46,6 @@
*/
public final class MixedDeviceOwnerTest extends DeviceAndProfileOwnerTest {
- private static final String DELEGATION_NETWORK_LOGGING = "delegation-network-logging";
- private static final String LOG_TAG_DEVICE_OWNER = "device-owner";
-
private static final String ARG_SECURITY_LOGGING_BATCH_NUMBER = "batchNumber";
private static final int SECURITY_EVENTS_BATCH_SIZE = 100;
@@ -122,14 +117,6 @@
@Test
@TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "218408549",
reason = "Will be migrated to new test infra")
- public void testDelegation() throws Exception {
- super.testDelegation();
- }
-
- @Override
- @Test
- @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "218408549",
- reason = "Will be migrated to new test infra")
public void testDelegationCertSelection() throws Exception {
super.testDelegationCertSelection();
}
@@ -198,38 +185,6 @@
executeDeviceTestMethod(".TimeManagementTest", "testSetTimeZone_failIfAutoTimeZoneEnabled");
}
- Map<String, DevicePolicyEventWrapper[]> getAdditionalDelegationTests() {
- final Map<String, DevicePolicyEventWrapper[]> result = new HashMap<>();
- DevicePolicyEventWrapper[] expectedMetrics = new DevicePolicyEventWrapper[] {
- new DevicePolicyEventWrapper.Builder(EventId.SET_NETWORK_LOGGING_ENABLED_VALUE)
- .setAdminPackageName(DELEGATE_APP_PKG)
- .setBoolean(true)
- .setInt(1)
- .setStrings(LOG_TAG_DEVICE_OWNER)
- .build(),
- new DevicePolicyEventWrapper.Builder(EventId.RETRIEVE_NETWORK_LOGS_VALUE)
- .setAdminPackageName(DELEGATE_APP_PKG)
- .setBoolean(true)
- .setStrings(LOG_TAG_DEVICE_OWNER)
- .build(),
- new DevicePolicyEventWrapper.Builder(EventId.SET_NETWORK_LOGGING_ENABLED_VALUE)
- .setAdminPackageName(DELEGATE_APP_PKG)
- .setBoolean(true)
- .setInt(0)
- .setStrings(LOG_TAG_DEVICE_OWNER)
- .build(),
- };
- result.put(".NetworkLoggingDelegateTest", expectedMetrics);
- return result;
- }
-
- @Override
- List<String> getAdditionalDelegationScopes() {
- final List<String> result = new ArrayList<>();
- result.add(DELEGATION_NETWORK_LOGGING);
- return result;
- }
-
@Test
public void testLockScreenInfo() throws Exception {
executeDeviceTestClass(".LockScreenInfoTest");
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
index a936df2..de04f84 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
@@ -31,9 +31,6 @@
import org.junit.Test;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* Set of tests for managed profile owner use cases that also apply to device owners.
* Tests that should be run identically in both cases are added in DeviceAndProfileOwnerTest.
@@ -398,11 +395,4 @@
"testSetNetworkLogsEnabled_false", mUserId);
}
}
-
- @Override
- List<String> getAdditionalDelegationScopes() {
- final List<String> result = new ArrayList<>();
- result.add(DELEGATION_NETWORK_LOGGING);
- return result;
- }
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
index 4311426..f7c8e14 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
@@ -151,6 +151,11 @@
public static final File CEC_MAP_FOLDER =
new File(System.getProperty("java.io.tmpdir"), "cec-cts-temp");
+ // CEC Settings
+ public static final String SETTING_VOLUME_CONTROL_ENABLED = "volume_control_enabled";
+
+ // CEC Settings Values
+ public static final String VOLUME_CONTROL_ENABLED = "1";
// Power Control Modes for source devices
public static final String POWER_CONTROL_MODE_BROADCAST = "broadcast";
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java
index 18fe41f..baaccc8 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java
@@ -30,7 +30,6 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
@@ -205,13 +204,18 @@
* not turned on.
*/
@Test
- @Ignore("b/218266432")
public void cect_sendVolumeKeyPressToTv() throws Exception {
ITestDevice device = getDevice();
String ucpMessage;
String command = "cmd hdmi_control setsam ";
simulateCecSinkConnected(device, getTargetLogicalAddress());
+ String volumeControlEnabled =
+ getSettingsValue(device, HdmiCecConstants.SETTING_VOLUME_CONTROL_ENABLED);
+ setSettingsValue(
+ device,
+ HdmiCecConstants.SETTING_VOLUME_CONTROL_ENABLED,
+ HdmiCecConstants.VOLUME_CONTROL_ENABLED);
boolean wasSystemAudioModeOn = isSystemAudioModeOn(device);
if (wasSystemAudioModeOn) {
@@ -243,6 +247,8 @@
if (wasSystemAudioModeOn) {
device.executeShellCommand(command + "on");
}
+ setSettingsValue(
+ device, HdmiCecConstants.SETTING_VOLUME_CONTROL_ENABLED, volumeControlEnabled);
}
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemAudioControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemAudioControlTest.java
index 718ae56..e8c0a3c 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemAudioControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemAudioControlTest.java
@@ -28,7 +28,6 @@
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Rule;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
@@ -57,21 +56,34 @@
* the audio rendering.
*/
@Test
- @Ignore("b/218266432")
public void cect_hf4_10_5_RemoteControlCommandsWithSystemAudioControlProperty()
throws Exception {
setCec20();
ITestDevice device = getDevice();
- // Broadcast <Set System Audio Mode> ["off"].
- broadcastSystemAudioModeMessage(false);
- // All remote control commands should forward to the TV.
- sendVolumeUpCommandAndCheckForUcp(LogicalAddress.TV);
+ String volumeControlEnabled =
+ getSettingsValue(device, HdmiCecConstants.SETTING_VOLUME_CONTROL_ENABLED);
- // Broadcast <Set System Audio Mode> ["on"].
- broadcastSystemAudioModeMessage(true);
- // All remote control commands should forward to the audio rendering device.
- sendVolumeUpCommandAndCheckForUcp(LogicalAddress.AUDIO_SYSTEM);
+ try {
+ simulateCecSinkConnected(device, getTargetLogicalAddress());
+ setSettingsValue(
+ device,
+ HdmiCecConstants.SETTING_VOLUME_CONTROL_ENABLED,
+ HdmiCecConstants.VOLUME_CONTROL_ENABLED);
+
+ // Broadcast <Set System Audio Mode> ["off"].
+ broadcastSystemAudioModeMessage(false);
+ // All remote control commands should forward to the TV.
+ sendVolumeUpCommandAndCheckForUcp(LogicalAddress.TV);
+
+ // Broadcast <Set System Audio Mode> ["on"].
+ broadcastSystemAudioModeMessage(true);
+ // All remote control commands should forward to the audio rendering device.
+ sendVolumeUpCommandAndCheckForUcp(LogicalAddress.AUDIO_SYSTEM);
+ } finally {
+ setSettingsValue(
+ device, HdmiCecConstants.SETTING_VOLUME_CONTROL_ENABLED, volumeControlEnabled);
+ }
}
private void broadcastSystemAudioModeMessage(boolean val) throws Exception {
diff --git a/hostsidetests/media/app/MediaRouterTest/src/android/media/router/cts/MediaRouter2Test.java b/hostsidetests/media/app/MediaRouterTest/src/android/media/router/cts/MediaRouter2Test.java
index fb37109..76bdaf7 100644
--- a/hostsidetests/media/app/MediaRouterTest/src/android/media/router/cts/MediaRouter2Test.java
+++ b/hostsidetests/media/app/MediaRouterTest/src/android/media/router/cts/MediaRouter2Test.java
@@ -30,6 +30,7 @@
import static android.media.cts.MediaRouterTestConstants.ROUTE_ID_3_2;
import static android.media.cts.MediaRouterTestConstants.ROUTE_ID_3_3;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -46,6 +47,7 @@
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -53,6 +55,7 @@
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
@LargeTest
public class MediaRouter2Test {
@@ -77,14 +80,14 @@
List<String> features = new ArrayList<>();
features.add("A test feature");
RouteDiscoveryPreference preference =
- new RouteDiscoveryPreference.Builder(features, /*activeScan=*/false).build();
+ new RouteDiscoveryPreference.Builder(features, /*activeScan=*/ false).build();
mRouter2.registerRouteCallback(mExecutor, mRouterDummyCallback, preference);
}
@Test
public void dontDedupeByDefault() throws Exception {
RouteDiscoveryPreference preference =
- new RouteDiscoveryPreference.Builder(FEATURES_ALL, /*activeScan=*/ true).build();
+ new RouteDiscoveryPreference.Builder(FEATURES_ALL, /*activeScan=*/ true).build();
Map<String, MediaRoute2Info> routes =
waitAndGetRoutes(preference, Set.of(ROUTE_ID_1_1, ROUTE_ID_2_1, ROUTE_ID_3_1));
@@ -102,7 +105,7 @@
@Test
public void setDeduplicationPackageOrder1() throws Exception {
RouteDiscoveryPreference preference =
- new RouteDiscoveryPreference.Builder(FEATURES_ALL, /*activeScan=*/true)
+ new RouteDiscoveryPreference.Builder(FEATURES_ALL, /*activeScan=*/ true)
.setDeduplicationPackageOrder(
List.of(
MEDIA_ROUTER_PROVIDER_1_PACKAGE,
@@ -126,7 +129,7 @@
@Test
public void setDeduplicationPackageOrder2() throws Exception {
RouteDiscoveryPreference preference =
- new RouteDiscoveryPreference.Builder(FEATURES_ALL, /*activeScan=*/true)
+ new RouteDiscoveryPreference.Builder(FEATURES_ALL, /*activeScan=*/ true)
.setDeduplicationPackageOrder(
List.of(
MEDIA_ROUTER_PROVIDER_3_PACKAGE,
@@ -150,7 +153,7 @@
@Test
public void setDeduplicationPackageOrder3() throws Exception {
RouteDiscoveryPreference preference =
- new RouteDiscoveryPreference.Builder(FEATURES_ALL, /*activeScan=*/true)
+ new RouteDiscoveryPreference.Builder(FEATURES_ALL, /*activeScan=*/ true)
.setDeduplicationPackageOrder(
List.of(
MEDIA_ROUTER_PROVIDER_2_PACKAGE,
@@ -171,6 +174,89 @@
assertFalse(routes.containsKey(ROUTE_ID_3_3));
}
+ @Test
+ public void testRouteCallbacks() throws Exception {
+ Set<String> addedRouteIds = new HashSet<>();
+ Set<String> removedRouteIds = new HashSet<>();
+
+ AtomicReference<CountDownLatch> addLatchRef = new AtomicReference<>();
+ AtomicReference<CountDownLatch> removeLatchRef = new AtomicReference<>();
+
+ addLatchRef.set(new CountDownLatch(1));
+ removeLatchRef.set(new CountDownLatch(1));
+
+ RouteDiscoveryPreference preference =
+ new RouteDiscoveryPreference.Builder(FEATURES_ALL, /*activeScan=*/ true)
+ .setAllowedPackages(List.of(MEDIA_ROUTER_PROVIDER_1_PACKAGE))
+ .setDeduplicationPackageOrder(
+ List.of(
+ MEDIA_ROUTER_PROVIDER_2_PACKAGE,
+ MEDIA_ROUTER_PROVIDER_3_PACKAGE,
+ MEDIA_ROUTER_PROVIDER_1_PACKAGE))
+ .build();
+ MediaRouter2.RouteCallback routeCallback =
+ new MediaRouter2.RouteCallback() {
+ @Override
+ public void onRoutesAdded(List<MediaRoute2Info> routes) {
+ for (MediaRoute2Info route : routes) {
+ if (!route.isSystemRoute()) {
+ addedRouteIds.add(route.getOriginalId());
+ }
+ }
+ addLatchRef.get().countDown();
+ }
+
+ @Override
+ public void onRoutesRemoved(List<MediaRoute2Info> routes) {
+ for (MediaRoute2Info route : routes) {
+ removedRouteIds.add(route.getOriginalId());
+ }
+ removeLatchRef.get().countDown();
+ }
+ };
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, preference);
+ assertTrue(addLatchRef.get().await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertFalse(removeLatchRef.get().await(WAIT_MS, TimeUnit.MILLISECONDS));
+ assertEquals(Set.of(ROUTE_ID_1_1, ROUTE_ID_1_2, ROUTE_ID_1_3), addedRouteIds);
+
+ addLatchRef.set(new CountDownLatch(1));
+ removeLatchRef.set(new CountDownLatch(1));
+ RouteDiscoveryPreference preference2 =
+ new RouteDiscoveryPreference.Builder(preference)
+ .setAllowedPackages(
+ List.of(
+ MEDIA_ROUTER_PROVIDER_1_PACKAGE,
+ MEDIA_ROUTER_PROVIDER_2_PACKAGE))
+ .build();
+
+ addedRouteIds.clear();
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, preference2);
+ assertTrue(addLatchRef.get().await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertTrue(removeLatchRef.get().await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals(Set.of(ROUTE_ID_2_1, ROUTE_ID_2_2, ROUTE_ID_2_3), addedRouteIds);
+ assertEquals(Set.of(ROUTE_ID_1_2), removedRouteIds);
+
+ addLatchRef.set(new CountDownLatch(1));
+ removeLatchRef.set(new CountDownLatch(1));
+ RouteDiscoveryPreference preference3 =
+ new RouteDiscoveryPreference.Builder(preference)
+ .setAllowedPackages(
+ List.of(
+ MEDIA_ROUTER_PROVIDER_1_PACKAGE,
+ MEDIA_ROUTER_PROVIDER_2_PACKAGE,
+ MEDIA_ROUTER_PROVIDER_3_PACKAGE))
+ .build();
+
+ addedRouteIds.clear();
+ removedRouteIds.clear();
+
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, preference3);
+ assertTrue(addLatchRef.get().await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertTrue(removeLatchRef.get().await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals(Set.of(ROUTE_ID_3_1, ROUTE_ID_3_2), addedRouteIds);
+ assertEquals(Set.of(ROUTE_ID_1_3), removedRouteIds);
+ }
+
// It returns original route id -> route for convenience
private static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
Map<String, MediaRoute2Info> routeMap = new HashMap<>();
diff --git a/hostsidetests/media/src/android/media/router/cts/MediaRouter2HostTest.java b/hostsidetests/media/src/android/media/router/cts/MediaRouter2HostTest.java
index df6ebeb..32adb1e 100644
--- a/hostsidetests/media/src/android/media/router/cts/MediaRouter2HostTest.java
+++ b/hostsidetests/media/src/android/media/router/cts/MediaRouter2HostTest.java
@@ -66,4 +66,10 @@
runDeviceTests(
MEDIA_ROUTER_TEST_PACKAGE, DEVICE_SIDE_TEST_CLASS, "setDeduplicationPackageOrder3");
}
+
+ @AppModeFull
+ @RequiresDevice
+ public void testCallback() throws Exception {
+ runDeviceTests(MEDIA_ROUTER_TEST_PACKAGE, DEVICE_SIDE_TEST_CLASS, "testRouteCallbacks");
+ }
}
diff --git a/hostsidetests/scopedstorage/Android.bp b/hostsidetests/scopedstorage/Android.bp
index 57abfec..d50ff73 100644
--- a/hostsidetests/scopedstorage/Android.bp
+++ b/hostsidetests/scopedstorage/Android.bp
@@ -33,6 +33,22 @@
}
android_test_helper_app {
+ name: "CtsScopedStorageTestAppA31",
+ manifest: "ScopedStorageTestHelper/TestAppA31.xml",
+ static_libs: ["cts-scopedstorage-lib"],
+ sdk_version: "test_current",
+ target_sdk_version: "31",
+ min_sdk_version: "30",
+ srcs: ["ScopedStorageTestHelper/src/**/*.java"],
+ // Tag as a CTS artifact
+ test_suites: [
+ "general-tests",
+ "mts-mediaprovider",
+ "cts",
+ ],
+}
+
+android_test_helper_app {
name: "CtsScopedStorageTestAppB",
manifest: "ScopedStorageTestHelper/TestAppB.xml",
static_libs: ["cts-scopedstorage-lib"],
@@ -213,6 +229,7 @@
min_sdk_version: "30",
java_resources: [
":CtsScopedStorageTestAppA",
+ ":CtsScopedStorageTestAppA31",
":CtsScopedStorageTestAppB",
":CtsScopedStorageTestAppC",
":CtsScopedStorageTestAppCLegacy",
diff --git a/hostsidetests/scopedstorage/AndroidManifest.xml b/hostsidetests/scopedstorage/AndroidManifest.xml
index 9d45439..39dc12e 100644
--- a/hostsidetests/scopedstorage/AndroidManifest.xml
+++ b/hostsidetests/scopedstorage/AndroidManifest.xml
@@ -19,6 +19,10 @@
<uses-sdk android:minSdkVersion="30" />
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
+ <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
+ <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
diff --git a/hostsidetests/scopedstorage/CoreTest.xml b/hostsidetests/scopedstorage/CoreTest.xml
index f9eaa20..1aac1dd 100644
--- a/hostsidetests/scopedstorage/CoreTest.xml
+++ b/hostsidetests/scopedstorage/CoreTest.xml
@@ -24,6 +24,7 @@
<option name="test-file-name" value="ScopedStorageTest.apk" />
<option name="test-file-name" value="LegacyStorageTest.apk" />
<option name="test-file-name" value="CtsScopedStorageTestAppA.apk" />
+ <option name="test-file-name" value="CtsScopedStorageTestAppA31.apk" />
<option name="test-file-name" value="CtsScopedStorageTestAppB.apk" />
<option name="test-file-name" value="CtsScopedStorageTestAppDLegacy.apk" />
</target_preparer>
diff --git a/hostsidetests/scopedstorage/PublicVolumeTest.xml b/hostsidetests/scopedstorage/PublicVolumeTest.xml
index 1dc4017..c52a067 100644
--- a/hostsidetests/scopedstorage/PublicVolumeTest.xml
+++ b/hostsidetests/scopedstorage/PublicVolumeTest.xml
@@ -20,6 +20,7 @@
<option name="test-file-name" value="ScopedStorageTest.apk" />
<option name="test-file-name" value="LegacyStorageTest.apk" />
<option name="test-file-name" value="CtsScopedStorageTestAppA.apk" />
+ <option name="test-file-name" value="CtsScopedStorageTestAppA31.apk" />
<option name="test-file-name" value="CtsScopedStorageTestAppB.apk" />
<option name="test-file-name" value="CtsScopedStorageTestAppDLegacy.apk" />
</target_preparer>
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppA.xml b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppA.xml
index b9b3f0c..885497b 100644
--- a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppA.xml
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppA.xml
@@ -22,6 +22,9 @@
<uses-sdk android:minSdkVersion="30" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
+ <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
+ <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<application android:label="TestAppA">
<activity android:name="android.scopedstorage.cts.ScopedStorageTestHelper" android:exported="true" >
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppA31.xml b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppA31.xml
new file mode 100644
index 0000000..68e6a15
--- /dev/null
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppA31.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.scopedstorage.cts.testapp.A31.withres"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="31"/>
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <application android:label="TestAppA">
+ <activity android:name="android.scopedstorage.cts.ScopedStorageTestHelper" android:exported="true" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <provider
+ android:name="androidx.core.content.FileProvider"
+ android:authorities="android.scopedstorage.cts.testapp.A31.withres"
+ android:exported="false"
+ android:grantUriPermissions="true">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/file_paths" />
+ </provider>
+ </application>
+</manifest>
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppC.xml b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppC.xml
index cf9c7fe..a6d1cb8 100644
--- a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppC.xml
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppC.xml
@@ -21,6 +21,9 @@
<uses-sdk android:minSdkVersion="30" />
+ <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
+ <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppC30.xml b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppC30.xml
index 17f63d1..4010295 100644
--- a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppC30.xml
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppC30.xml
@@ -21,6 +21,9 @@
<uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
+ <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
+ <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppFileManager.xml b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppFileManager.xml
index dd01db9..e49af51 100644
--- a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppFileManager.xml
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppFileManager.xml
@@ -21,6 +21,9 @@
<uses-sdk android:minSdkVersion="30" />
+ <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
+ <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppFileManagerBypassDB.xml b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppFileManagerBypassDB.xml
index 29b7151..5b9c657 100644
--- a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppFileManagerBypassDB.xml
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppFileManagerBypassDB.xml
@@ -21,6 +21,9 @@
<uses-sdk android:minSdkVersion="30" />
+ <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
+ <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppSystemGalleryBypassDB.xml b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppSystemGalleryBypassDB.xml
index ae0ec51..2813a03 100644
--- a/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppSystemGalleryBypassDB.xml
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/TestAppSystemGalleryBypassDB.xml
@@ -22,6 +22,9 @@
<uses-sdk android:minSdkVersion="30" />
+ <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
+ <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java b/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java
index ee63a8a..2f37855 100644
--- a/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java
@@ -52,6 +52,7 @@
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import androidx.annotation.Nullable;
@@ -158,10 +159,11 @@
try {
final String mode = queryType.equals(IS_URI_REDACTED_VIA_FILE_DESCRIPTOR_FOR_WRITE)
? "w" : "r";
- FileDescriptor fd = getContentResolver().openFileDescriptor(uri,
- mode).getFileDescriptor();
- ExifInterface exifInterface = new ExifInterface(fd);
- intent.putExtra(queryType, exifInterface.getGpsDateTime() == -1);
+ try (ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(uri, mode)) {
+ FileDescriptor fd = pfd.getFileDescriptor();
+ ExifInterface exifInterface = new ExifInterface(fd);
+ intent.putExtra(queryType, exifInterface.getGpsDateTime() == -1);
+ }
} catch (Exception e) {
intent.putExtra(INTENT_EXCEPTION, e);
}
diff --git a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/RedactUriDeviceTest.java b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/RedactUriDeviceTest.java
index 2e8ccdae5..b23f945 100644
--- a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/RedactUriDeviceTest.java
+++ b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/RedactUriDeviceTest.java
@@ -50,6 +50,7 @@
import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import androidx.test.filters.SdkSuppress;
@@ -447,9 +448,10 @@
try {
assertUriIsUnredacted(img);
- InputStream is = getContentResolver().openInputStream(redactedUri);
- ExifInterface redactedExifInf = new ExifInterface(is);
- assertUriIsRedacted(redactedExifInf);
+ try (InputStream is = getContentResolver().openInputStream(redactedUri)) {
+ ExifInterface redactedExifInf = new ExifInterface(is);
+ assertUriIsRedacted(redactedExifInf);
+ }
} finally {
img.delete();
}
@@ -462,10 +464,12 @@
try {
assertUriIsUnredacted(img);
- FileDescriptor fd = getContentResolver().openFileDescriptor(redactedUri,
- "r").getFileDescriptor();
- ExifInterface redactedExifInf = new ExifInterface(fd);
- assertUriIsRedacted(redactedExifInf);
+ try (ParcelFileDescriptor pfd =
+ getContentResolver().openFileDescriptor(redactedUri, "r")) {
+ FileDescriptor fd = pfd.getFileDescriptor();
+ ExifInterface redactedExifInf = new ExifInterface(fd);
+ assertUriIsRedacted(redactedExifInf);
+ }
} finally {
img.delete();
}
diff --git a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
index 756e425..1a3bff9 100644
--- a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
+++ b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
@@ -198,10 +198,14 @@
// The following apps are installed before the tests are run via a target_preparer.
// See test config for details.
- // An app with READ_EXTERNAL_STORAGE permission
- private static final TestApp APP_A_HAS_RES = new TestApp("TestAppA",
- "android.scopedstorage.cts.testapp.A.withres", 1, false,
- "CtsScopedStorageTestAppA.apk");
+ // An app with READ_EXTERNAL_STORAGE and READ_MEDIA_* permissions
+ private static final TestApp APP_A_HAS_RES =
+ new TestApp(
+ "TestAppA",
+ "android.scopedstorage.cts.testapp.A.withres",
+ 1,
+ false,
+ "CtsScopedStorageTestAppA.apk");
// An app with no permissions
private static final TestApp APP_B_NO_PERMS = new TestApp("TestAppB",
"android.scopedstorage.cts.testapp.B.noperms", 1, false,
@@ -895,11 +899,11 @@
try {
assertThat(file.createNewFile()).isTrue();
- ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
- ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
-
- assertRWR(readPfd, writePfd);
- assertUpperFsFd(writePfd); // With cache
+ try (ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
+ ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw")) {
+ assertRWR(readPfd, writePfd);
+ assertUpperFsFd(writePfd); // With cache
+ }
} finally {
file.delete();
}
@@ -913,11 +917,11 @@
try {
assertThat(file.createNewFile()).isTrue();
- ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
- ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
-
- assertRWR(readPfd, writePfd);
- assertLowerFsFdWithPassthrough(writePfd);
+ try (ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
+ ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE)) {
+ assertRWR(readPfd, writePfd);
+ assertLowerFsFdWithPassthrough(writePfd);
+ }
} finally {
file.delete();
}
@@ -931,11 +935,11 @@
try {
assertThat(file.createNewFile()).isTrue();
- ParcelFileDescriptor writePfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
- ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
-
- assertRWR(readPfd, writePfd);
- assertUpperFsFd(readPfd); // With cache
+ try (ParcelFileDescriptor writePfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
+ ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw")) {
+ assertRWR(readPfd, writePfd);
+ assertUpperFsFd(readPfd); // With cache
+ }
} finally {
file.delete();
}
@@ -949,11 +953,11 @@
try {
assertThat(file.createNewFile()).isTrue();
- ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
- ParcelFileDescriptor writePfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
-
- assertRWR(readPfd, writePfd);
- assertLowerFsFdWithPassthrough(readPfd);
+ try (ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
+ ParcelFileDescriptor writePfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE)) {
+ assertRWR(readPfd, writePfd);
+ assertLowerFsFdWithPassthrough(readPfd);
+ }
} finally {
file.delete();
}
@@ -968,13 +972,13 @@
assertThat(file.createNewFile()).isTrue();
// We upgrade 'w' only to 'rw'
- ParcelFileDescriptor writePfd = openWithMediaProvider(file, "w");
- ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
-
- assertRWR(readPfd, writePfd);
- assertRWR(writePfd, readPfd); // Can read on 'w' only pfd
- assertLowerFsFdWithPassthrough(writePfd);
- assertLowerFsFdWithPassthrough(readPfd);
+ try (ParcelFileDescriptor writePfd = openWithMediaProvider(file, "w");
+ ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw")) {
+ assertRWR(readPfd, writePfd);
+ assertRWR(writePfd, readPfd); // Can read on 'w' only pfd
+ assertLowerFsFdWithPassthrough(writePfd);
+ assertLowerFsFdWithPassthrough(readPfd);
+ }
} finally {
file.delete();
}
@@ -991,15 +995,13 @@
// Even if we close the original fd, since we have a dup open
// the FUSE IO should still bypass the cache
- try (ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw")) {
- try (ParcelFileDescriptor writePfdDup = writePfd.dup();
- ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(
- file, MODE_READ_WRITE)) {
- writePfd.close();
+ try (ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
+ ParcelFileDescriptor writePfdDup = writePfd.dup();
+ ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE)) {
+ writePfd.close();
- assertRWR(readPfd, writePfdDup);
- assertLowerFsFdWithPassthrough(writePfdDup);
- }
+ assertRWR(readPfd, writePfdDup);
+ assertLowerFsFdWithPassthrough(writePfdDup);
}
} finally {
file.delete();
@@ -1026,12 +1028,13 @@
writePfd.close();
// Upper fs open and read without direct_io
- ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
- Os.pread(readPfd.getFileDescriptor(), readBuffer, 0, 10, 0);
+ try (ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE)) {
+ Os.pread(readPfd.getFileDescriptor(), readBuffer, 0, 10, 0);
- // Last write on lower fs is visible via upper fs
- assertThat(readBuffer).isEqualTo(writeBuffer);
- assertThat(readPfd.getStatSize()).isEqualTo(writeBuffer.length);
+ // Last write on lower fs is visible via upper fs
+ assertThat(readBuffer).isEqualTo(writeBuffer);
+ assertThat(readPfd.getStatSize()).isEqualTo(writeBuffer.length);
+ }
} finally {
file.delete();
}
@@ -1260,9 +1263,12 @@
@Test
public void testReadStorageInvalidation() throws Exception {
- testAppOpInvalidation(APP_C, new File(getDcimDir(), "read_storage.jpg"),
- Manifest.permission.READ_EXTERNAL_STORAGE,
- AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE, /* forWrite */ false);
+ testAppOpInvalidation(
+ APP_C,
+ new File(getDcimDir(), "read_storage.jpg"),
+ Manifest.permission.READ_MEDIA_IMAGES,
+ AppOpsManager.OPSTR_READ_MEDIA_IMAGES,
+ /* forWrite */ false);
}
@Test
@@ -1435,7 +1441,6 @@
Thread.sleep(200);
}
assertThat(canOpenFileAs(app, file, forWrite)).isTrue();
-
// Deny
if (permission != null) {
revokePermission(packageName, permission);
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageCoreHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageCoreHostTest.java
index 7d8a6e7..c2414dd 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageCoreHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageCoreHostTest.java
@@ -61,8 +61,12 @@
@Before
public void revokeStoragePermissions() throws Exception {
- revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE",
- "android.permission.READ_EXTERNAL_STORAGE");
+ revokePermissions(
+ "android.permission.WRITE_EXTERNAL_STORAGE",
+ "android.permission.READ_EXTERNAL_STORAGE",
+ "android.permission.READ_MEDIA_AUDIO",
+ "android.permission.READ_MEDIA_VIDEO",
+ "android.permission.READ_MEDIA_IMAGES");
}
@After
@@ -93,10 +97,71 @@
@Test
public void testAccess_file() throws Exception {
grantPermissions("android.permission.READ_EXTERNAL_STORAGE");
+ grantPermissions("android.permission.READ_MEDIA_IMAGES");
try {
runDeviceTest("testAccess_file");
} finally {
revokePermissions("android.permission.READ_EXTERNAL_STORAGE");
+ revokePermissions("android.permission.READ_MEDIA_IMAGES");
+ }
+ }
+
+ @Test
+ public void testAccess_MediaFile() throws Exception {
+ grantPermissions("android.permission.READ_MEDIA_IMAGES");
+ grantPermissions("android.permission.READ_MEDIA_AUDIO");
+ grantPermissions("android.permission.READ_MEDIA_VIDEO");
+ try {
+ runDeviceTest("testAccess_MediaFile");
+ } finally {
+ revokePermissions("android.permission.READ_MEDIA_IMAGES");
+ revokePermissions("android.permission.READ_MEDIA_AUDIO");
+ revokePermissions("android.permission.READ_MEDIA_VIDEO");
+ }
+ }
+
+ @Test
+ public void testAccess_OnlyAudioFile() throws Exception {
+ grantPermissions("android.permission.READ_MEDIA_AUDIO");
+ try {
+ runDeviceTest("testAccess_OnlyAudioFile");
+ } finally {
+ revokePermissions("android.permission.READ_MEDIA_AUDIO");
+ }
+ }
+
+ @Test
+ public void testAccess_OnlyVideoFile() throws Exception {
+ grantPermissions("android.permission.READ_MEDIA_VIDEO");
+ try {
+ runDeviceTest("testAccess_OnlyVideoFile");
+ } finally {
+ revokePermissions("android.permission.READ_MEDIA_VIDEO");
+ }
+ }
+
+ @Test
+ public void testAccess_OnlyImageFile() throws Exception {
+ grantPermissions("android.permission.READ_MEDIA_IMAGES");
+ try {
+ runDeviceTest("testAccess_OnlyImageFile");
+ } finally {
+ revokePermissions("android.permission.READ_MEDIA_IMAGES");
+ }
+ }
+
+ @Test
+ public void testAccess_MediaFileLegacy() throws Exception {
+ runDeviceTest("testAccess_MediaFileLegacy");
+ }
+
+ @Test
+ public void testAccess_MediaFileWithRES() throws Exception {
+ grantPermissions("android.permission.READ_EXTERNAL_STORAGE");
+ try {
+ runDeviceTest("testAccess_MediaFileWithRES");
+ } finally {
+ revokePermissions("android.permission.READ_EXTERNAL_STORAGE");
}
}
diff --git a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
index 314dbb4..7c27ee7 100644
--- a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
+++ b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
@@ -586,6 +586,9 @@
assertThat(InstallUtils.getInstalledVersion(packageName)).isEqualTo(1);
if (grantStoragePermission) {
grantPermission(packageName, Manifest.permission.READ_EXTERNAL_STORAGE);
+ grantPermission(packageName, Manifest.permission.READ_MEDIA_IMAGES);
+ grantPermission(packageName, Manifest.permission.READ_MEDIA_AUDIO);
+ grantPermission(packageName, Manifest.permission.READ_MEDIA_VIDEO);
}
} finally {
uiAutomation.dropShellPermissionIdentity();
@@ -856,8 +859,7 @@
* Returns whether we can open the file.
*/
public static boolean canOpen(File file, boolean forWrite) {
- try {
- openWithFilePath(file, forWrite);
+ try (ParcelFileDescriptor ignore = openWithFilePath(file, forWrite)) {
return true;
} catch (IOException expected) {
return false;
@@ -1702,7 +1704,7 @@
private static boolean isVolumeMounted(String type) {
try {
final String volume = executeShellCommand("sm list-volumes " + type).trim();
- return volume != null && volume.contains("mounted");
+ return volume != null && volume.contains(" mounted");
} catch (Exception e) {
return false;
}
@@ -1716,6 +1718,18 @@
return isVolumeMounted("emulated");
}
+ private static boolean isFuseReady() {
+ for (String volumeName : MediaStore.getExternalVolumeNames(getContext())) {
+ final Uri uri = MediaStore.Files.getContentUri(volumeName);
+ try (Cursor c = getContentResolver().query(uri, null, null, null)) {
+ assertThat(c).isNotNull();
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Prepare or create a public volume for testing
*/
@@ -1734,6 +1748,8 @@
"Timed out while waiting for public volume");
pollForCondition(TestUtils::isEmulatedVolumeMounted,
"Timed out while waiting for emulated volume");
+ pollForCondition(TestUtils::isFuseReady,
+ "Timed out while waiting for fuse");
}
}
diff --git a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
index ebc8f10..14bbcb0 100644
--- a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
+++ b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
@@ -28,6 +28,7 @@
import static android.scopedstorage.cts.lib.TestUtils.assertMountMode;
import static android.scopedstorage.cts.lib.TestUtils.assertThrows;
import static android.scopedstorage.cts.lib.TestUtils.canOpen;
+import static android.scopedstorage.cts.lib.TestUtils.canOpenFileAs;
import static android.scopedstorage.cts.lib.TestUtils.canReadAndWriteAs;
import static android.scopedstorage.cts.lib.TestUtils.createFileAs;
import static android.scopedstorage.cts.lib.TestUtils.deleteFileAs;
@@ -135,10 +136,25 @@
// The following apps are installed before the tests are run via a target_preparer.
// See test config for details.
- // An app with READ_EXTERNAL_STORAGE permission
- private static final TestApp APP_A_HAS_RES = new TestApp("TestAppA",
- "android.scopedstorage.cts.testapp.A.withres", 1, false,
- "CtsScopedStorageTestAppA.apk");
+
+ // An app with READ_EXTERNAL_STORAGE and READ_MEDIA_* permissions.
+ // R_E_S permission isn't actually used since the app targets T+,
+ // the R_M_* permissions will be checked instead.
+ private static final TestApp APP_A_HAS_READ_MEDIA_ALL =
+ new TestApp(
+ "TestAppA",
+ "android.scopedstorage.cts.testapp.A.withres",
+ 1,
+ false,
+ "CtsScopedStorageTestAppA.apk");
+ // An app with READ_EXTERNAL_STORAGE permission with targetSdk 31
+ private static final TestApp APP_A_HAS_RES_31 =
+ new TestApp(
+ "TestAppA31",
+ "android.scopedstorage.cts.testapp.A31.withres",
+ 1,
+ false,
+ "CtsScopedStorageTestAppA31.apk");
// An app with no permissions
private static final TestApp APP_B_NO_PERMS = new TestApp("TestAppB",
"android.scopedstorage.cts.testapp.B.noperms", 1, false,
@@ -212,10 +228,10 @@
// Let app A create a file in its data dir
final File otherAppExternalDataDir = new File(getExternalFilesDir().getPath().replace(
- THIS_PACKAGE_NAME, APP_A_HAS_RES.getPackageName()));
+ THIS_PACKAGE_NAME, APP_A_HAS_READ_MEDIA_ALL.getPackageName()));
final File otherAppExternalDataFile = new File(otherAppExternalDataDir,
NONMEDIA_FILE_NAME);
- assertCreateFilesAs(APP_A_HAS_RES, otherAppExternalDataFile);
+ assertCreateFilesAs(APP_A_HAS_READ_MEDIA_ALL, otherAppExternalDataFile);
// File Manager app gets global access with MANAGE_EXTERNAL_STORAGE permission, however,
// file manager app doesn't have access to other app's external files directory
@@ -223,7 +239,8 @@
assertThat(canOpen(otherAppExternalDataFile, /* forWrite */ true)).isFalse();
assertThat(otherAppExternalDataFile.delete()).isFalse();
- assertThat(deleteFileAs(APP_A_HAS_RES, otherAppExternalDataFile.getPath())).isTrue();
+ assertThat(deleteFileAs(APP_A_HAS_READ_MEDIA_ALL,
+ otherAppExternalDataFile.getPath())).isTrue();
assertThrows(IOException.class,
() -> {
@@ -282,8 +299,167 @@
}
@Test
+ public void testAccess_OnlyImageFile() throws Exception {
+ pollForPermission(Manifest.permission.READ_MEDIA_IMAGES, /*granted*/ true);
+
+ final File otherAppImage = new File(getDcimDir(), "other-" + IMAGE_FILE_NAME);
+ final File otherAppVideo = new File(getDcimDir(), "other-" + VIDEO_FILE_NAME);
+ final File otherAppAudio = new File(getMusicDir(), "other-" + AUDIO_FILE_NAME);
+
+ try {
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppImage.getPath())).isTrue();
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppVideo.getPath())).isTrue();
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppAudio.getPath())).isTrue();
+
+ // We can read the other app's image file only because we hold R_M_I.
+ assertCannotReadOrWrite(otherAppAudio);
+ assertFileAccess_readOnly(otherAppImage);
+ assertCannotReadOrWrite(otherAppVideo);
+
+ } finally {
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppImage.getAbsolutePath());
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppVideo.getAbsolutePath());
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppAudio.getAbsolutePath());
+ }
+ }
+
+ @Test
+ public void testAccess_OnlyVideoFile() throws Exception {
+ pollForPermission(Manifest.permission.READ_MEDIA_VIDEO, /*granted*/ true);
+
+ final File otherAppImage = new File(getDcimDir(), "other-" + IMAGE_FILE_NAME);
+ final File otherAppVideo = new File(getDcimDir(), "other-" + VIDEO_FILE_NAME);
+ final File otherAppAudio = new File(getMusicDir(), "other-" + AUDIO_FILE_NAME);
+
+ try {
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppImage.getPath())).isTrue();
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppVideo.getPath())).isTrue();
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppAudio.getPath())).isTrue();
+
+ // We can read the other app's video file only because we hold R_M_V.
+ assertCannotReadOrWrite(otherAppImage);
+ assertFileAccess_readOnly(otherAppVideo);
+ assertCannotReadOrWrite(otherAppAudio);
+
+ } finally {
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppImage.getAbsolutePath());
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppVideo.getAbsolutePath());
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppAudio.getAbsolutePath());
+ }
+ }
+
+ @Test
+ public void testAccess_OnlyAudioFile() throws Exception {
+ pollForPermission(Manifest.permission.READ_MEDIA_AUDIO, /*granted*/ true);
+
+ final File otherAppImage = new File(getDcimDir(), "other-" + IMAGE_FILE_NAME);
+ final File otherAppVideo = new File(getDcimDir(), "other-" + VIDEO_FILE_NAME);
+ final File otherAppAudio = new File(getMusicDir(), "other-" + AUDIO_FILE_NAME);
+
+ try {
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppImage.getPath())).isTrue();
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppVideo.getPath())).isTrue();
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppAudio.getPath())).isTrue();
+
+ // We can read the other app's audio file only because we hold R_M_A.
+ assertCannotReadOrWrite(otherAppImage);
+ assertFileAccess_readOnly(otherAppAudio);
+ assertCannotReadOrWrite(otherAppVideo);
+
+ } finally {
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppImage.getAbsolutePath());
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppVideo.getAbsolutePath());
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppAudio.getAbsolutePath());
+ }
+ }
+
+ @Test
+ public void testAccess_MediaFile() throws Exception {
+ pollForPermission(Manifest.permission.READ_MEDIA_IMAGES, /*granted*/ true);
+ pollForPermission(Manifest.permission.READ_MEDIA_AUDIO, /*granted*/ true);
+ pollForPermission(Manifest.permission.READ_MEDIA_VIDEO, /*granted*/ true);
+
+ final File downloadDir = getDownloadDir();
+ final File otherAppImage = new File(getDcimDir(), "other-" + IMAGE_FILE_NAME);
+ final File otherAppVideo = new File(getDcimDir(), "other-" + VIDEO_FILE_NAME);
+ final File otherAppAudio = new File(getMusicDir(), "other-" + AUDIO_FILE_NAME);
+ final File myAppPdf = new File(downloadDir, "my-" + NONMEDIA_FILE_NAME);
+
+ try {
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppImage.getPath())).isTrue();
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppVideo.getPath())).isTrue();
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppAudio.getPath())).isTrue();
+
+ // We can read our image and pdf files.
+ assertThat(myAppPdf.createNewFile()).isTrue();
+ assertFileAccess_readWrite(myAppPdf);
+
+ // We can read the other app media files because we hold R_M_*.
+ assertFileAccess_readOnly(otherAppImage);
+ assertFileAccess_readOnly(otherAppVideo);
+ assertFileAccess_readOnly(otherAppAudio);
+ } finally {
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppImage.getAbsolutePath());
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppVideo.getAbsolutePath());
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppAudio.getAbsolutePath());
+ myAppPdf.delete();
+ }
+ }
+
+ /** R_E_S can't give access to media files anymore. */
+ @Test
+ public void testAccess_MediaFileWithRES() throws Exception {
+ pollForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, /*granted*/ true);
+
+ final File otherAppImage = new File(getDcimDir(), "other-" + IMAGE_FILE_NAME);
+ final File otherAppVideo = new File(getDcimDir(), "other-" + VIDEO_FILE_NAME);
+ final File otherAppAudio = new File(getMusicDir(), "other-" + AUDIO_FILE_NAME);
+
+ try {
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppImage.getPath())).isTrue();
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppVideo.getPath())).isTrue();
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppAudio.getPath())).isTrue();
+
+ // Can't read the other app media even with R_E_S.
+ assertCannotReadOrWrite(otherAppImage);
+ assertCannotReadOrWrite(otherAppVideo);
+ assertCannotReadOrWrite(otherAppAudio);
+ } finally {
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppImage.getAbsolutePath());
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppVideo.getAbsolutePath());
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppAudio.getAbsolutePath());
+ }
+ }
+
+ // R_E_S with targetsdk 31 can still access media files.
+ @Test
+ public void testAccess_MediaFileLegacy() throws Exception {
+ final File otherAppImage = new File(getDcimDir(), "other-" + IMAGE_FILE_NAME);
+ final File otherAppVideo = new File(getDcimDir(), "other-" + VIDEO_FILE_NAME);
+ final File otherAppAudio = new File(getMusicDir(), "other-" + AUDIO_FILE_NAME);
+ try {
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppImage.getPath())).isTrue();
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppVideo.getPath())).isTrue();
+ assertThat(createFileAs(APP_B_NO_PERMS, otherAppAudio.getPath())).isTrue();
+
+ // Can read the other app media files because of holding R_E_S with targetsdk31.
+ assertThat(canOpenFileAs(APP_A_HAS_RES_31, otherAppImage, false /* forWrite */))
+ .isTrue();
+ assertThat(canOpenFileAs(APP_A_HAS_RES_31, otherAppVideo, false /* forWrite */))
+ .isTrue();
+ assertThat(canOpenFileAs(APP_A_HAS_RES_31, otherAppAudio, false /* forWrite */))
+ .isTrue();
+ } finally {
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppImage.getAbsolutePath());
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppVideo.getAbsolutePath());
+ deleteFileAsNoThrow(APP_B_NO_PERMS, otherAppAudio.getAbsolutePath());
+ }
+ }
+
+ @Test
public void testAccess_file() throws Exception {
pollForPermission(Manifest.permission.READ_EXTERNAL_STORAGE, /*granted*/ true);
+ pollForPermission(Manifest.permission.READ_MEDIA_IMAGES, /*granted*/ true);
final File downloadDir = getDownloadDir();
final File otherAppPdf = new File(downloadDir, "other-" + NONMEDIA_FILE_NAME);
@@ -301,7 +477,7 @@
assertThat(myAppPdf.createNewFile()).isTrue();
assertFileAccess_readWrite(myAppPdf);
- // We can read the other app's image file because we hold R_E_S, but we can
+ // We can read the other app's image file because we hold R_M_I, but we can
// check only exists for the pdf files.
assertFileAccess_readOnly(otherAppImage);
assertFileAccess_existsOnly(otherAppPdf);
@@ -768,7 +944,9 @@
assertCanQueryAndOpenFile(otherPendingFile, "r");
// We can also read other app's pending file via MediaStore API
- assertNotNull(openWithMediaProvider(otherPendingFile, "r"));
+ try (ParcelFileDescriptor pfd = openWithMediaProvider(otherPendingFile, "r")) {
+ assertNotNull(pfd);
+ }
} finally {
deleteFileAsNoThrow(APP_B_NO_PERMS, otherPendingFile.getAbsolutePath());
}
@@ -798,10 +976,10 @@
}
// Let app A create a file in its data dir
final File otherAppExternalDataDir = new File(getExternalFilesDir().getPath().replace(
- THIS_PACKAGE_NAME, APP_A_HAS_RES.getPackageName()));
+ THIS_PACKAGE_NAME, APP_A_HAS_READ_MEDIA_ALL.getPackageName()));
final File otherAppExternalDataFile = new File(otherAppExternalDataDir,
NONMEDIA_FILE_NAME);
- assertCreateFilesAs(APP_A_HAS_RES, otherAppExternalDataFile);
+ assertCreateFilesAs(APP_A_HAS_READ_MEDIA_ALL, otherAppExternalDataFile);
// File Manager app gets global access with MANAGE_EXTERNAL_STORAGE permission, however,
// file manager app doesn't have access to other app's external files directory
@@ -809,7 +987,8 @@
assertThat(canOpen(otherAppExternalDataFile, /* forWrite */ true)).isFalse();
assertThat(otherAppExternalDataFile.delete()).isFalse();
- assertThat(deleteFileAs(APP_A_HAS_RES, otherAppExternalDataFile.getPath())).isTrue();
+ assertThat(deleteFileAs(APP_A_HAS_READ_MEDIA_ALL,
+ otherAppExternalDataFile.getPath())).isTrue();
assertThrows(IOException.class,
() -> {
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9537/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9537/Android.bp
index 9b5a6ca..5e9597d 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9537/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9537/Android.bp
@@ -30,8 +30,11 @@
"external/aac/libSYS/include",
"external/aac/libAACdec/include",
],
+ static_libs: [
+ "libFraunhoferAAC",
+ ],
shared_libs: [
- "libbluetooth",
+ "liblog",
],
cflags: [
"-DCHECK_OVERFLOW",
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9549/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9549/Android.bp
index 5b9e6dd..651c36f 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9549/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9549/Android.bp
@@ -25,8 +25,11 @@
srcs : [
"poc.cpp",
],
- shared_libs : [
- "libbluetooth",
+ static_libs: [
+ "libFraunhoferAAC",
+ ],
+ shared_libs: [
+ "liblog",
],
include_dirs : [
"external/aac/libSBRdec/src",
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp
index e750829..8494e2c 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9558/poc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,9 @@
#include <nfc_api.h>
#include <rw_int.h>
+#define INITIAL_VALUE 0xBE
+#define NUM_BYTES 1
+
bool isTestInProgress = false;
struct sigaction new_action, old_action;
void sigabrt_handler(int signum, siginfo_t *info, void *context) {
@@ -30,9 +33,6 @@
exit(EXIT_FAILURE);
}
-#define INITIAL_VALUE 0xBE
-#define NUM_BYTES 1
-
extern tRW_CB rw_cb;
void rw_init(void);
void rw_t2t_handle_rsp(uint8_t *p_data);
@@ -63,6 +63,7 @@
p_t2t->found_tlv = TAG_LOCK_CTRL_TLV;
p_t2t->bytes_count = NUM_BYTES;
p_t2t->tlv_value[1] = UINT8_MAX;
+ p_t2t->p_cur_cmd_buf = (NFC_HDR *)GKI_getpoolbuf(NFC_RW_POOL_ID);
uint8_t *base_ptr = (uint8_t *)(p_t2t->lockbyte + RW_T1T_MAX_LOCK_BYTES);
memset((void *)base_ptr, INITIAL_VALUE, sizeof(tRW_T1T_LOCK));
uint8_t data[T2T_READ_DATA_LEN];
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9247/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9247/Android.bp
index b85abba..31572ca 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9247/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9247/Android.bp
@@ -32,7 +32,10 @@
"external/aac/libFDK/include/",
"cts/hostsidetests/securitybulletin/securityPatch/includes/",
],
+ static_libs: [
+ "libFraunhoferAAC",
+ ],
shared_libs: [
- "libbluetooth",
+ "liblog",
],
}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9308/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9308/Android.bp
index 250b45b..8834e75 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9308/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9308/Android.bp
@@ -29,7 +29,10 @@
"external/aac/libSYS/include",
"external/aac/libAACdec/include",
],
+ static_libs: [
+ "libFraunhoferAAC",
+ ],
shared_libs: [
- "libbluetooth",
+ "liblog",
],
}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9357/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9357/Android.bp
index 9a7a370..56804eb 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9357/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9357/Android.bp
@@ -30,7 +30,10 @@
"external/aac/libAACdec/src",
"external/aac/libSYS/include",
],
+ static_libs: [
+ "libFraunhoferAAC",
+ ],
shared_libs: [
- "libbluetooth",
+ "liblog",
],
}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9362/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9362/Android.bp
index 1cb71e3..30507a9 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2019-9362/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-9362/Android.bp
@@ -25,8 +25,11 @@
srcs: [
"poc.cpp",
],
+ static_libs: [
+ "libFraunhoferAAC",
+ ],
shared_libs: [
- "libbluetooth",
+ "liblog",
],
include_dirs: [
"external/aac/libSACdec/src",
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0451/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0451/Android.bp
index 69ce4b1..cd1a59f 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0451/Android.bp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0451/Android.bp
@@ -37,7 +37,10 @@
"external/aac/libDRCdec/include",
"external/aac/libSBRdec/src",
],
+ static_libs: [
+ "libFraunhoferAAC",
+ ],
shared_libs: [
- "libbluetooth",
+ "liblog",
],
}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/Android.bp
new file mode 100644
index 0000000..0c8ffff
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+ name: "CVE-2021-39665",
+ defaults: [
+ "cts_hostsidetests_securitybulletin_defaults",
+ ],
+ srcs: [
+ "poc.cpp",
+ ],
+ shared_libs: [
+ "libutils",
+ "libmediaplayerservice",
+ "libstagefright_foundation",
+ ],
+ include_dirs: [
+ "frameworks/av/media/libstagefright/rtsp/include/media/stagefright/rtsp",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/poc.cpp
new file mode 100644
index 0000000..4571a6d
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39665/poc.cpp
@@ -0,0 +1,85 @@
+/**
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dlfcn.h>
+
+#include "../includes/common.h"
+
+#define private public
+#include "AAVCAssembler.h"
+
+using namespace android;
+
+bool isOverloadingEnabled = false;
+
+bool isTestInProgress = false;
+
+struct sigaction newAction, oldAction;
+
+static void *(*realMalloc)(size_t) = nullptr;
+
+void *malloc(size_t size) {
+ if (!realMalloc) {
+ realMalloc = (void *(*)(size_t))dlsym(RTLD_NEXT, "malloc");
+ if (!realMalloc) {
+ return nullptr;
+ }
+ }
+ if (isOverloadingEnabled && (size == 0)) {
+ size_t pageSize = sysconf(_SC_PAGE_SIZE);
+ void *ptr = memalign(pageSize, pageSize);
+ mprotect(ptr, pageSize, PROT_NONE);
+ return ptr;
+ }
+ return realMalloc(size);
+}
+
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+ if (isTestInProgress && info->si_signo == SIGSEGV) {
+ (*oldAction.sa_sigaction)(signum, info, context);
+ return;
+ }
+ _exit(EXIT_FAILURE);
+}
+
+int main() {
+ sigemptyset(&newAction.sa_mask);
+ newAction.sa_flags = SA_SIGINFO;
+ newAction.sa_sigaction = sigsegv_handler;
+ sigaction(SIGSEGV, &newAction, &oldAction);
+
+ sp<ABuffer> buffer(new ABuffer(16));
+ FAIL_CHECK(buffer != nullptr);
+
+ sp<AMessage> meta = buffer->meta();
+ FAIL_CHECK(meta != nullptr);
+
+ uint32_t rtpTime = 16;
+ meta->setInt32("rtp-time", rtpTime);
+
+ AAVCAssembler *assembler = new AAVCAssembler(meta);
+ FAIL_CHECK(assembler != nullptr);
+
+ isOverloadingEnabled = true;
+ sp<ABuffer> zeroSizedBuffer(new ABuffer(0));
+ isOverloadingEnabled = false;
+
+ isTestInProgress = true;
+ assembler->checkSpsUpdated(zeroSizedBuffer);
+ isTestInProgress = false;
+
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
index c9c1d61..a4d088d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,22 +14,28 @@
* limitations under the License.
*/
+
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.regex.Pattern;
+
@RunWith(DeviceJUnit4ClassRunner.class)
public class CVE_2018_9558 extends SecurityTestCase {
/**
* b/112161557
* Vulnerability Behaviour: SIGABRT in self
+ * Vulnerable Library: libnfc-nci (As per AOSP code)
+ * Vulnerable Function: rw_t2t_handle_tlv_detect_rsp (As per AOSP code)
*/
@Test
@AsbSecurityTest(cveBugId = 112161557)
@@ -37,11 +43,15 @@
AdbUtils.assumeHasNfc(getDevice());
assumeIsSupportedNfcDevice(getDevice());
pocPusher.only64();
- String binaryName = "CVE-2018-9558";
String[] signals = {CrashUtils.SIGABRT};
+ String binaryName = "CVE-2018-9558";
AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
- testConfig.config.setSignals(CrashUtils.SIGABRT);
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
+ "rw_t2t_handle_tlv_detect_rsp"));
+ testConfig.config
+ .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
+ testConfig.config.setSignals(signals);
AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java
new file mode 100644
index 0000000..311b5ce
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.regex.Pattern;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39665 extends SecurityTestCase {
+
+ /**
+ * b/204077881
+ * Vulnerability Behavior: SIGSEGV in self
+ * Vulnerable Library: libmediaplayerservice (As per AOSP code)
+ * Vulnerable Function: android::AAVCAssembler::checkSpsUpdated (As per AOSP code)
+ */
+ @AsbSecurityTest(cveBugId = 204077881)
+ @Test
+ public void testPocCVE_2021_39665() throws Exception {
+ String[] signals = {CrashUtils.SIGSEGV};
+ String binaryName = "CVE-2021-39665";
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ .setBacktraceIncludes(new BacktraceFilterPattern("libmediaplayerservice",
+ "android::AAVCAssembler::checkSpsUpdated"));
+ testConfig.config.setSignals(signals);
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+}
diff --git a/hostsidetests/systemui/Android.bp b/hostsidetests/systemui/Android.bp
index 6fd9c8c..a5918f4 100644
--- a/hostsidetests/systemui/Android.bp
+++ b/hostsidetests/systemui/Android.bp
@@ -30,6 +30,7 @@
static_libs: [
"cts-statsd-atom-host-test-utils",
"platformprotos",
+ "CompatChangeGatingTestBase",
],
// Tag this module as a cts test artifact
test_suites: [
diff --git a/hostsidetests/systemui/app/src/android/systemui/cts/TestActiveTileService.java b/hostsidetests/systemui/app/src/android/systemui/cts/TestActiveTileService.java
index f8fe6c0..02b403a 100644
--- a/hostsidetests/systemui/app/src/android/systemui/cts/TestActiveTileService.java
+++ b/hostsidetests/systemui/app/src/android/systemui/cts/TestActiveTileService.java
@@ -22,6 +22,9 @@
public class TestActiveTileService extends TestTileService {
+ private static final String EXTRA_BAD_PACKAGE = "android.systemui.cts.EXTRA_BAD_PACKAGE";
+ private static final String TAG = "TestActiveTileService";
+
@Override
public void onTileAdded() {
Log.i(TAG, TEST_PREFIX + "onTileAdded");
@@ -32,7 +35,18 @@
public void onReceive(Context context, Intent intent) {
Log.i(TestActiveTileService.class.getSimpleName(),
TEST_PREFIX + "requestListeningState");
- requestListeningState(context, new ComponentName(context, TestActiveTileService.class));
+ ComponentName componentName;
+ boolean useBadPackage = intent.getBooleanExtra(EXTRA_BAD_PACKAGE, false);
+ if (useBadPackage) {
+ componentName = ComponentName.unflattenFromString("pkg/.cls");
+ } else {
+ componentName = new ComponentName(context, TestActiveTileService.class);
+ }
+ try {
+ requestListeningState(context, componentName);
+ } catch (SecurityException e) {
+ Log.i(TAG, TEST_PREFIX + "SecurityException");
+ }
}
}
}
diff --git a/hostsidetests/systemui/src/android/host/systemui/ActiveTileServiceCompatChangeTest.java b/hostsidetests/systemui/src/android/host/systemui/ActiveTileServiceCompatChangeTest.java
new file mode 100644
index 0000000..d861e40
--- /dev/null
+++ b/hostsidetests/systemui/src/android/host/systemui/ActiveTileServiceCompatChangeTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.host.systemui;
+
+import android.compat.cts.CompatChangeGatingTestCase;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+
+import java.util.Set;
+
+public class ActiveTileServiceCompatChangeTest extends CompatChangeGatingTestCase {
+
+ // Constants for generating commands below.
+ private static final String PACKAGE = "android.systemui.cts";
+
+ // Commands used on the device.
+ private static final String ADD_TILE = "cmd statusbar add-tile ";
+ private static final String REM_TILE = "cmd statusbar remove-tile ";
+
+ public static final String REQUEST_SUPPORTED = "cmd statusbar check-support";
+ public static final String TEST_PREFIX = "TileTest_";
+
+ // Time between checks for logs we expect.
+ private static final long CHECK_DELAY = 500;
+ // Number of times to check before failing.
+ private static final long CHECK_RETRIES = 30;
+
+ private final String mService = "TestActiveTileService";
+ private final String mComponent = PACKAGE + "/." + mService;
+
+ private static final long REQUEST_LISTENING_MUST_MATCH_PACKAGE = 172251878L;
+
+ private static final String EXTRA_BAD_PACKAGE = "android.systemui.cts.EXTRA_BAD_PACKAGE";
+ private static final String ACTION_REQUEST_LISTENING =
+ "android.sysui.testtile.REQUEST_LISTENING";
+
+ private static final String REQUEST_LISTENING = "am broadcast -a " + ACTION_REQUEST_LISTENING
+ + " " + PACKAGE;
+
+ private static final String REQUEST_LISTENING_BAD =
+ REQUEST_LISTENING + " -ez " + EXTRA_BAD_PACKAGE + " true";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ clearLogcat();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ if (!supported()) return;
+ remTile();
+ // Try to wait for a onTileRemoved.
+ waitFor("onTileRemoved");
+ }
+
+ public void testRequestListening_changeEnabled() throws Exception {
+ runTest(true);
+ }
+
+ public void testRequestListening_changeDisabled() throws Exception {
+ runTest(false);
+ }
+
+ public void testRequestListeningBadPackage_changeEnabled_SecurityException() throws Exception {
+ if (!supported()) return;
+ Set<Long> enabledSet = Set.of(REQUEST_LISTENING_MUST_MATCH_PACKAGE);
+ Set<Long> disabledSet = Set.of();
+
+ setCompatConfig(enabledSet, disabledSet, PACKAGE);
+
+ addTile();
+ assertTrue(waitFor("onDestroy"));
+
+ // Request the listening state but use a bad component name (not in the same package)
+ getDevice().executeShellCommand(REQUEST_LISTENING_BAD);
+ assertTrue(waitFor("SecurityException"));
+ }
+
+ private void runTest(boolean enabled) throws Exception {
+ if (!supported()) return;
+ Set<Long> enabledSet = enabled ? Set.of(REQUEST_LISTENING_MUST_MATCH_PACKAGE) : Set.of();
+ Set<Long> disabledSet = enabled ? Set.of() : Set.of(REQUEST_LISTENING_MUST_MATCH_PACKAGE);
+
+ setCompatConfig(enabledSet, disabledSet, PACKAGE);
+
+ final long configId = getClass().getCanonicalName().hashCode();
+ createAndUploadStatsdConfig(configId, PACKAGE);
+
+ try {
+ executeRequestListeningTest();
+ } finally {
+ resetCompatChanges(Set.of(REQUEST_LISTENING_MUST_MATCH_PACKAGE), PACKAGE);
+ validatePostRunStatsdReport(configId, PACKAGE, enabledSet, disabledSet);
+ }
+ }
+
+ private void executeRequestListeningTest() throws Exception {
+ addTile();
+ assertTrue(waitFor("onDestroy"));
+
+ // Request the listening state and verify that it gets an onStartListening.
+ getDevice().executeShellCommand(REQUEST_LISTENING);
+ assertTrue(waitFor("requestListeningState"));
+ assertTrue(waitFor("onStartListening"));
+ }
+
+ private void addTile() throws Exception {
+ execute(ADD_TILE + mComponent);
+ }
+
+ private void remTile() throws Exception {
+ execute(REM_TILE + mComponent);
+ }
+
+ private void execute(String cmd) throws Exception {
+ getDevice().executeShellCommand(cmd);
+ // All of the status bar commands tend to have animations associated
+ // everything seems to be happier if you give them time to finish.
+ Thread.sleep(100);
+ }
+
+ protected boolean waitFor(String str) throws DeviceNotAvailableException, InterruptedException {
+ final String searchStr = TEST_PREFIX + str;
+ int ct = 0;
+ while (!hasLog(searchStr) && (ct++ < CHECK_RETRIES)) {
+ Thread.sleep(CHECK_DELAY);
+ }
+ return hasLog(searchStr);
+ }
+
+ protected boolean hasLog(String str) throws DeviceNotAvailableException {
+ String logs = getDevice().executeAdbCommand("logcat", "-v", "brief", "-d", mService + ":I",
+ "*:S");
+ return logs.contains(str);
+ }
+
+ private void clearLogcat() throws DeviceNotAvailableException {
+ getDevice().executeAdbCommand("logcat", "-c");
+ }
+
+ protected boolean supported() throws DeviceNotAvailableException {
+ return supportedHardware() && supportedSoftware();
+ }
+
+ private boolean supportedSoftware() throws DeviceNotAvailableException {
+ String supported = getDevice().executeShellCommand(REQUEST_SUPPORTED);
+ return Boolean.parseBoolean(supported);
+ }
+
+ private boolean supportedHardware() throws DeviceNotAvailableException {
+ String features = getDevice().executeShellCommand("pm list features");
+ return !features.contains("android.hardware.type.television")
+ && !features.contains("android.hardware.type.watch");
+ }
+}
diff --git a/tests/PhotoPicker/AndroidTest.xml b/tests/PhotoPicker/AndroidTest.xml
index d0bf797..c52543e 100644
--- a/tests/PhotoPicker/AndroidTest.xml
+++ b/tests/PhotoPicker/AndroidTest.xml
@@ -20,7 +20,7 @@
<option name="test-file-name" value="CtsPhotoPickerTest.apk" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
- <option name="force-root" value="true" />
+ <option name="force-root" value="false" />
</target_preparer>
<option
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/CloudPhotoPickerTest.java b/tests/PhotoPicker/src/android/photopicker/cts/CloudPhotoPickerTest.java
index a8f9132..aa0c954 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/CloudPhotoPickerTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/CloudPhotoPickerTest.java
@@ -52,7 +52,6 @@
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -66,7 +65,6 @@
* Photo Picker Device only tests for common flows.
*/
@RunWith(AndroidJUnit4.class)
-@SdkSuppress(minSdkVersion = 31, codeName = "S")
public class CloudPhotoPickerTest extends PhotoPickerBaseTest {
private final List<Uri> mUriList = new ArrayList<>();
private MediaGenerator mCloudPrimaryMediaGenerator;
@@ -242,7 +240,7 @@
}
@Test
- public void testUriAccess() throws Exception {
+ public void testUriAccessWithValidProjection() throws Exception {
initPrimaryCloudProviderWithImage(Pair.create(null, CLOUD_ID1));
final ClipData clipData = fetchPickerMedia(1);
@@ -276,9 +274,29 @@
assertRedactedReadOnlyAccess(clipData.getItemAt(0).getUri());
}
- @Ignore("b/215187981: For some reason, it hits a timeout and crashes the other tests on cf")
+ @Test
+ public void testUriAccessWithInvalidProjection() throws Exception {
+ initPrimaryCloudProviderWithImage(Pair.create(null, CLOUD_ID1));
+
+ final ClipData clipData = fetchPickerMedia(1);
+ final List<String> mediaIds = extractMediaIds(clipData, 1);
+
+ assertThat(mediaIds).containsExactly(CLOUD_ID1);
+
+ final ContentResolver resolver = mContext.getContentResolver();
+
+ assertThrows(IllegalArgumentException.class, () -> resolver.query(
+ clipData.getItemAt(0).getUri(),
+ new String[] {MediaStore.MediaColumns.RELATIVE_PATH}, null, null));
+ }
+
@Test
public void testCloudEventNotification() throws Exception {
+ // Create a placeholder local image to ensure that the picker UI is never empty.
+ // The PhotoPickerUiUtils#findItemList needs to select an item and it times out if the
+ // Picker UI is empty.
+ createImages(1, mContext.getUserId(), mUriList);
+
// Cloud provider isn't set
assertThat(MediaStore.isCurrentCloudMediaProviderAuthority(mContext.getContentResolver(),
CloudProviderPrimary.AUTHORITY)).isFalse();
@@ -349,8 +367,7 @@
private ClipData fetchPickerMedia(int maxCount) throws Exception {
final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
- // TODO(b/205291616): Replace 100 with MediaStore.getPickImagesMaxLimit()
- intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, 100);
+ intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit());
mActivity.startActivityForResult(intent, REQUEST_CODE);
final List<UiObject> itemList = findItemList(maxCount);
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java
index 67623ac..12bd8ae 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java
@@ -16,17 +16,13 @@
package android.photopicker.cts;
-import android.Manifest;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
-import android.provider.DeviceConfig;
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.UiDevice;
-import com.android.modules.utils.build.SdkLevel;
-
import org.junit.Before;
/**
@@ -45,8 +41,6 @@
final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
mDevice = UiDevice.getInstance(inst);
- enablePhotoPickerFlag(inst);
-
final String setSyncDelayCommand =
"setprop persist.sys.photopicker.pickerdb.default_sync_delay_ms 0";
mDevice.executeShellCommand(setSyncDelayCommand);
@@ -65,18 +59,4 @@
mActivity.clearResult();
mDevice.waitForIdle();
}
-
- private void enablePhotoPickerFlag(Instrumentation inst) throws Exception {
- if (SdkLevel.isAtLeastS()) {
- inst.getUiAutomation().adoptShellPermissionIdentity(
- Manifest.permission.WRITE_DEVICE_CONFIG);
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
- "picker_intent_enabled" /* name */,
- "true" /* value */,
- false /* makeDefault */);
- } else {
- mDevice.executeShellCommand("setprop persist.sys.storage_picker_enabled true");
- }
- }
}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java
index fcef908..1092406 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java
@@ -136,8 +136,7 @@
private void assertBlockedByAdmin(boolean isInvokedFromWorkProfile) throws Exception {
Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
- // TODO(b/205291616): Replace 100 with MediaStore.getPickImagesMaxLimit()
- intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, 100);
+ intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit());
mActivity.startActivityForResult(intent, REQUEST_CODE);
// Click the profile button to change to work profile
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
index b9f8f33..7ad44e1 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
@@ -17,6 +17,7 @@
package android.photopicker.cts;
import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertMimeType;
+import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertPersistedGrant;
import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertPickerUriFormat;
import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertRedactedReadOnlyAccess;
import static android.photopicker.cts.util.PhotoPickerFilesUtils.createDNGVideos;
@@ -44,7 +45,6 @@
import androidx.test.uiautomator.UiSelector;
import org.junit.After;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -83,10 +83,66 @@
final Uri uri = mActivity.getResult().data.getData();
assertPickerUriFormat(uri, mContext.getUserId());
+ assertPersistedGrant(uri, mContext.getContentResolver());
assertRedactedReadOnlyAccess(uri);
}
@Test
+ public void testSingleSelectForFavoritesAlbum() throws Exception {
+ final int itemCount = 1;
+ createImages(itemCount, mContext.getUserId(), mUriList, true);
+
+ final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
+ mActivity.startActivityForResult(intent, REQUEST_CODE);
+
+ UiObject albumsTab = mDevice.findObject(new UiSelector().text(
+ "Albums"));
+ clickAndWait(albumsTab);
+ final UiObject album = findItemList(1).get(0);
+ clickAndWait(album);
+
+ final UiObject item = findItemList(itemCount).get(0);
+ clickAndWait(item);
+
+ final Uri uri = mActivity.getResult().data.getData();
+ assertPickerUriFormat(uri, mContext.getUserId());
+ assertRedactedReadOnlyAccess(uri);
+ }
+
+ @Test
+ public void testLaunchPreviewMultipleForVideoAlbum() throws Exception {
+ final int videoCount = 2;
+ createVideos(videoCount, mContext.getUserId(), mUriList);
+
+ final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
+ intent.setType("video/*");
+ intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit());
+ mActivity.startActivityForResult(intent, REQUEST_CODE);
+
+ UiObject albumsTab = mDevice.findObject(new UiSelector().text(
+ "Albums"));
+ clickAndWait(albumsTab);
+ final UiObject album = findItemList(1).get(0);
+ clickAndWait(album);
+
+ final List<UiObject> itemList = findItemList(videoCount);
+ final int itemCount = itemList.size();
+
+ assertThat(itemCount).isEqualTo(videoCount);
+
+ for (int i = 0; i < itemCount; i++) {
+ clickAndWait(itemList.get(i));
+ }
+
+ clickAndWait(findViewSelectedButton());
+
+ // Wait for playback to start. This is needed in some devices where playback
+ // buffering -> ready state takes around 10s.
+ final long playbackStartTimeout = 10000;
+ (findPreviewVideoImageView()).waitUntilGone(playbackStartTimeout);
+ }
+
+ @Test
public void testSingleSelectWithPreview() throws Exception {
final int itemCount = 1;
createImages(itemCount, mContext.getUserId(), mUriList);
@@ -110,8 +166,7 @@
@Test
public void testMultiSelect_invalidParam() throws Exception {
final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
- // TODO(b/205291616): Replace 101 with MediaStore.getPickImagesMaxLimit() + 1
- intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, 101);
+ intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit() + 1);
mActivity.startActivityForResult(intent, REQUEST_CODE);
final GetResultActivity.Result res = mActivity.getResult();
assertThat(res.resultCode).isEqualTo(Activity.RESULT_CANCELED);
@@ -174,6 +229,7 @@
final Uri uri = mActivity.getResult().data.getData();
assertPickerUriFormat(uri, mContext.getUserId());
+ assertPersistedGrant(uri, mContext.getContentResolver());
assertRedactedReadOnlyAccess(uri);
}
@@ -182,8 +238,7 @@
final int imageCount = 4;
createImages(imageCount, mContext.getUserId(), mUriList);
final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
- // TODO(b/205291616): Replace 100 with MediaStore.getPickImagesMaxLimit()
- intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, 100);
+ intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit());
mActivity.startActivityForResult(intent, REQUEST_CODE);
final List<UiObject> itemList = findItemList(imageCount);
@@ -201,6 +256,7 @@
for (int i = 0; i < count; i++) {
final Uri uri = clipData.getItemAt(i).getUri();
assertPickerUriFormat(uri, mContext.getUserId());
+ assertPersistedGrant(uri, mContext.getContentResolver());
assertRedactedReadOnlyAccess(uri);
}
}
@@ -210,8 +266,7 @@
final int videoCount = 3;
createDNGVideos(videoCount, mContext.getUserId(), mUriList);
final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
- // TODO(b/205291616): Replace 100 with MediaStore.getPickImagesMaxLimit()
- intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, 100);
+ intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit());
intent.setType("video/*");
mActivity.startActivityForResult(intent, REQUEST_CODE);
@@ -248,6 +303,7 @@
for (int i = 0; i < count; i++) {
final Uri uri = clipData.getItemAt(i).getUri();
assertPickerUriFormat(uri, mContext.getUserId());
+ assertPersistedGrant(uri, mContext.getContentResolver());
assertRedactedReadOnlyAccess(uri);
}
}
@@ -257,8 +313,7 @@
final int imageCount = 4;
createImages(imageCount, mContext.getUserId(), mUriList);
final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
- // TODO(b/205291616): Replace 100 with MediaStore.getPickImagesMaxLimit()
- intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, 100);
+ intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit());
mActivity.startActivityForResult(intent, REQUEST_CODE);
final List<UiObject> itemList = findItemList(imageCount);
@@ -287,39 +342,31 @@
for (int i = 0; i < count; i++) {
final Uri uri = clipData.getItemAt(i).getUri();
assertPickerUriFormat(uri, mContext.getUserId());
+ assertPersistedGrant(uri, mContext.getContentResolver());
assertRedactedReadOnlyAccess(uri);
}
}
@Test
- @Ignore("Re-enable once b/218794887 is fixed")
- public void testMultiSelect_PreviewVideoPlayPause() throws Exception {
- launchPreviewMultipleWithVideos(/* videoCount */ 4);
+ public void testMultiSelect_previewVideoPlayPause() throws Exception {
+ launchPreviewMultipleWithVideos(/* videoCount */ 3);
// Check Play/Pause in first video
testVideoPreviewPlayPause();
- // Move to second video
+ // Move to third video
swipeLeftAndWait();
- // Check Play/Pause in second video
+ swipeLeftAndWait();
+ // Check Play/Pause in third video
testVideoPreviewPlayPause();
- // Move to fourth video
- swipeLeftAndWait();
- swipeLeftAndWait();
- // Check Play/Pause in fourth video
- testVideoPreviewPlayPause();
-
- final UiObject addButton = findPreviewAddButton();
- addButton.click();
// We don't test the result of the picker here because the intention of the test is only to
// test the video controls
}
@Test
- @Ignore("Re-enable once b/218794887 is fixed")
- public void testMultiSelect_PreviewVideoMuteButton() throws Exception {
- launchPreviewMultipleWithVideos(/* videoCount */ 4);
+ public void testMultiSelect_previewVideoMuteButtonInitial() throws Exception {
+ launchPreviewMultipleWithVideos(/* videoCount */ 1);
final UiObject playPauseButton = findPlayPauseButton();
final UiObject muteButton = findMuteButton();
@@ -340,8 +387,42 @@
// Click on the muteButton and check that mute button status is now `selected`
clickAndWait(muteButton);
assertThat(muteButton.isSelected()).isTrue();
+ // Click on the muteButton and check that mute button status is now `not selected`
+ clickAndWait(muteButton);
+ assertThat(muteButton.isSelected()).isFalse();
- // Test 3: Swipe resumes mute state, with state of mute button = `not selected`
+ // Test 3: Next preview resumes mute state
+ // Go back and launch preview again
+ mDevice.pressBack();
+ clickAndWait(findViewSelectedButton());
+ // set-up and wait for player controls to be sticky
+ setUpAndAssertStickyPlayerControls(playerView, playPauseButton, muteButton);
+ assertThat(muteButton.isSelected()).isFalse();
+
+ // We don't test the result of the picker here because the intention of the test is only to
+ // test the video controls
+ }
+
+ @Test
+ public void testMultiSelect_previewVideoMuteButtonOnSwipe() throws Exception {
+ launchPreviewMultipleWithVideos(/* videoCount */ 3);
+
+ final UiObject playPauseButton = findPlayPauseButton();
+ final UiObject muteButton = findMuteButton();
+ final UiObject playerView = findPlayerView();
+
+ // set-up and wait for player controls to be sticky
+ setUpAndAssertStickyPlayerControls(playerView, playPauseButton, muteButton);
+
+ // Test 1: Swipe resumes mute state, with state of the button = `selected`
+ assertThat(muteButton.isSelected()).isTrue();
+ // Swipe to next page and check that muteButton is selected
+ swipeLeftAndWait();
+ // set-up and wait for player controls to be sticky
+ setUpAndAssertStickyPlayerControls(playerView, playPauseButton, muteButton);
+ assertThat(muteButton.isSelected()).isTrue();
+
+ // Test 2: Swipe resumes mute state, with state of mute button = `not selected`
// Click muteButton again to check the next video resumes the previous video's mute state
clickAndWait(muteButton);
assertThat(muteButton.isSelected()).isFalse();
@@ -351,44 +432,18 @@
setUpAndAssertStickyPlayerControls(playerView, playPauseButton, muteButton);
assertThat(muteButton.isSelected()).isFalse();
- // Test 4: Swipe resumes mute state, with state of the button = `selected`
- // Click muteButton again to check the next video resumes the previous video's mute state
- clickAndWait(muteButton);
- assertThat(muteButton.isSelected()).isTrue();
- // Swipe to next page and check that muteButton is selected
- swipeLeftAndWait();
- // set-up and wait for player controls to be sticky
- setUpAndAssertStickyPlayerControls(playerView, playPauseButton, muteButton);
- assertThat(muteButton.isSelected()).isTrue();
-
- // Test 5: Next preview resumes mute state
- // Click muteButton again to check if next Preview launch resumes the muteButton state
- clickAndWait(muteButton);
- assertThat(muteButton.isSelected()).isFalse();
- // Go back and launch preview again
- mDevice.pressBack();
- // set-up and wait for player controls to be sticky
- clickAndWait(findViewSelectedButton());
- setUpAndAssertStickyPlayerControls(playerView, playPauseButton, muteButton);
- assertThat(muteButton.isSelected()).isFalse();
-
- clickAndWait(findPreviewAddButton());
// We don't test the result of the picker here because the intention of the test is only to
// test the video controls
}
@Test
- @Ignore("Re-enable once b/218794887 is fixed")
- public void testMultiSelect_PreviewVideoControlsVisibility() throws Exception {
+ public void testMultiSelect_previewVideoControlsVisibility() throws Exception {
launchPreviewMultipleWithVideos(/* videoCount */ 3);
mDevice.waitForIdle();
final UiObject playPauseButton = findPlayPauseButton();
final UiObject muteButton = findMuteButton();
- // Check that the player controls are visible
- assertPlayerControlsVisible(playPauseButton, muteButton);
-
// Check that buttons auto hide.
assertPlayerControlsAutoHide(playPauseButton, muteButton);
@@ -421,8 +476,6 @@
// Check that the player controls are auto hidden in 1s
assertPlayerControlsAutoHide(playPauseButton, muteButton);
- final UiObject addButton = findPreviewAddButton();
- addButton.click();
// We don't test the result of the picker here because the intention of the test is only to
// test the video controls
}
@@ -437,8 +490,7 @@
final String mimeType = "video/dng";
final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
- // TODO(b/205291616): Replace 100 with MediaStore.getPickImagesMaxLimit()
- intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, 100);
+ intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit());
intent.setType(mimeType);
mActivity.startActivityForResult(intent, REQUEST_CODE);
@@ -458,6 +510,7 @@
for (int i = 0; i < count; i++) {
final Uri uri = clipData.getItemAt(i).getUri();
assertPickerUriFormat(uri, mContext.getUserId());
+ assertPersistedGrant(uri, mContext.getContentResolver());
assertRedactedReadOnlyAccess(uri);
assertMimeType(uri, mimeType);
}
@@ -488,8 +541,7 @@
private void launchPreviewMultipleWithVideos(int videoCount) throws Exception {
createVideos(videoCount, mContext.getUserId(), mUriList);
final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
- // TODO(b/205291616): Replace 100 with MediaStore.getPickImagesMaxLimit()
- intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, 100);
+ intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit());
intent.setType("video/*");
mActivity.startActivityForResult(intent, REQUEST_CODE);
@@ -512,8 +564,8 @@
private void setUpAndAssertStickyPlayerControls(UiObject playerView, UiObject playPauseButton,
UiObject muteButton) throws Exception {
- // Check that buttons auto hide.
- assertPlayerControlsAutoHide(playPauseButton, muteButton);
+ // Wait for 1s or Play/Pause button to hide
+ playPauseButton.waitUntilGone(1000);
// Click on StyledPlayerView to make the video controls visible
clickAndWait(playerView);
assertPlayerControlsVisible(playPauseButton, muteButton);
@@ -590,7 +642,7 @@
private void swipeLeftAndWait() {
final int width = mDevice.getDisplayWidth();
final int height = mDevice.getDisplayHeight();
- mDevice.swipe(15 * width / 20, height / 2, width / 20, height / 2, 20);
+ mDevice.swipe(15 * width / 20, height / 2, width / 20, height / 2, 10);
mDevice.waitForIdle();
}
}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/RemoteVideoPreviewTest.java b/tests/PhotoPicker/src/android/photopicker/cts/RemoteVideoPreviewTest.java
index a4ec998..22d6a9d 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/RemoteVideoPreviewTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/RemoteVideoPreviewTest.java
@@ -48,6 +48,7 @@
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
@@ -112,6 +113,7 @@
}
@Test
+ @Ignore("Re-enable once b/223224727 is fixed")
public void testBasicVideoPreview() throws Exception {
initCloudProviderWithVideo(Arrays.asList(Pair.create(null, CLOUD_ID1)));
@@ -144,6 +146,7 @@
}
@Test
+ @Ignore("Re-enable once b/223224727 is fixed")
public void testSwipeAdjacentVideoPreview() throws Exception {
initCloudProviderWithVideo(
Arrays.asList(Pair.create(null, CLOUD_ID1), Pair.create(null, CLOUD_ID2)));
@@ -179,6 +182,7 @@
}
@Test
+ @Ignore("Re-enable once b/223224727 is fixed")
public void testSwipeImageVideoPreview() throws Exception {
initCloudProviderWithImage(Arrays.asList(Pair.create(null, CLOUD_ID1)));
initCloudProviderWithVideo(Arrays.asList(Pair.create(null, CLOUD_ID2)));
@@ -299,8 +303,7 @@
private void launchPreviewMultiple(int count) throws Exception {
final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
- // TODO(b/205291616): Replace 100 with MediaStore.getPickImagesMaxLimit()
- intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, 100);
+ intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit());
mActivity.startActivityForResult(intent, REQUEST_CODE);
final List<UiObject> itemList = findItemList(count);
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java
index a9894a9..9eb7d59 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java
@@ -16,8 +16,6 @@
package android.photopicker.cts.util;
-import static android.os.SystemProperties.getBoolean;
-import static android.provider.MediaStore.Files.FileColumns;
import static android.provider.MediaStore.PickerMediaColumns;
import static com.google.common.truth.Truth.assertThat;
@@ -27,6 +25,8 @@
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
+import android.content.UriPermission;
import android.database.Cursor;
import android.media.ExifInterface;
import android.net.Uri;
@@ -41,7 +41,9 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/**
* Photo Picker Utility methods for test assertions.
@@ -58,6 +60,20 @@
assertThat(auth).isEqualTo("picker");
}
+ public static void assertPersistedGrant(Uri uri, ContentResolver resolver) {
+ resolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ final List<UriPermission> uriPermissions = resolver.getPersistedUriPermissions();
+ final List<Uri> uris = new ArrayList<>();
+ for (UriPermission perm : uriPermissions) {
+ if (perm.isReadPermission()) {
+ uris.add(perm.getUri());
+ }
+ }
+
+ assertThat(uris).contains(uri);
+ }
+
public static void assertMimeType(Uri uri, String expectedMimeType) throws Exception {
final Context context = InstrumentationRegistry.getTargetContext();
final String resultMimeType = context.getContentResolver().getType(uri);
@@ -73,12 +89,7 @@
assertThat(c).isNotNull();
assertThat(c.moveToFirst()).isTrue();
- final String mimeType;
- if (getBoolean("sys.photopicker.pickerdb.enabled", true)) {
- mimeType = c.getString(c.getColumnIndex(PickerMediaColumns.MIME_TYPE));
- } else {
- mimeType = c.getString(c.getColumnIndex(FileColumns.MIME_TYPE));
- }
+ final String mimeType = c.getString(c.getColumnIndex(PickerMediaColumns.MIME_TYPE));
if (mimeType.startsWith("image")) {
assertImageRedactedReadOnlyAccess(uri, resolver);
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerFilesUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerFilesUtils.java
index 87be764..3705ddd 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerFilesUtils.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerFilesUtils.java
@@ -44,8 +44,13 @@
public static void createImages(int count, int userId, List<Uri> uriList)
throws Exception {
+ createImages(count, userId, uriList, false);
+ }
+
+ public static void createImages(int count, int userId, List<Uri> uriList, boolean isFavorite)
+ throws Exception {
for (int i = 0; i < count; i++) {
- final Uri uri = createImage(userId);
+ final Uri uri = createImage(userId, isFavorite);
uriList.add(uri);
clearMediaOwner(uri, userId);
}
@@ -101,13 +106,14 @@
return uri;
}
- private static Uri createImage(int userId) throws Exception {
+ private static Uri createImage(int userId, boolean isFavorite) throws Exception {
final Uri uri = stageMedia(R.raw.lg_g4_iso_800_jpg,
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/jpeg", userId);
+ MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/jpeg", userId, isFavorite);
return uri;
}
- private static Uri stageMedia(int resId, Uri collectionUri, String mimeType, int userId) throws
+ private static Uri stageMedia(int resId, Uri collectionUri, String mimeType, int userId,
+ boolean isFavorite) throws
Exception {
UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
uiAutomation.adoptShellPermissionIdentity(
@@ -118,17 +124,24 @@
final Context userContext = userId == context.getUserId() ? context :
context.createPackageContextAsUser("android", /* flags= */ 0,
UserHandle.of(userId));
- return stageMedia(resId, collectionUri, mimeType, userContext);
+ return stageMedia(resId, collectionUri, mimeType, userContext, isFavorite);
} finally {
uiAutomation.dropShellPermissionIdentity();
}
}
- private static Uri stageMedia(int resId, Uri collectionUri, String mimeType, Context context)
+ private static Uri stageMedia(int resId, Uri collectionUri, String mimeType, int userId) throws
+ Exception {
+ return stageMedia(resId, collectionUri, mimeType, userId, false);
+ }
+
+ private static Uri stageMedia(int resId, Uri collectionUri, String mimeType, Context context,
+ boolean isFavorite)
throws IOException {
final String displayName = DISPLAY_NAME_PREFIX + System.nanoTime();
final MediaStoreUtils.PendingParams params = new MediaStoreUtils.PendingParams(
collectionUri, displayName, mimeType);
+ params.setIsFavorite(isFavorite);
final Uri pendingUri = MediaStoreUtils.createPending(context, params);
try (MediaStoreUtils.PendingSession session = MediaStoreUtils.openPending(context,
pendingUri)) {
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index 1a359dd..0f5afd1 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -109,12 +109,14 @@
@Rule
public final RuleChain mRuleChain = RuleChain
- .outerRule(mSpeakingAndVibratingAccessibilityServiceRule)
+ // SettingsStateChangerRule will suppress accessibility services, so it should be
+ // executed before enabling a11y services and after disabling a11y services.
+ .outerRule(mAudioDescriptionSetterRule)
+ .around(mSpeakingAndVibratingAccessibilityServiceRule)
.around(mVibratingAccessibilityServiceRule)
.around(mSpeakingAccessibilityServiceRule)
// Inner rule capture failure and dump data before finishing activity and a11y service
- .around(mDumpOnFailureRule)
- .around(mAudioDescriptionSetterRule);
+ .around(mDumpOnFailureRule);
private AccessibilityManager mAccessibilityManager;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityMagnificationTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityMagnificationTest.java
index 715c040..1ef0724 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityMagnificationTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityMagnificationTest.java
@@ -420,14 +420,22 @@
.setMode(MAGNIFICATION_MODE_WINDOW)
.setScale(2.0f)
.build();
- mService.runOnServiceSync(
- () -> controller.setMagnificationConfig(config, /* animate= */ false));
- sUiAutomation.executeAndWaitForEvent(
- () -> mService.runOnServiceSync(() -> mService.disableSelfAndRemove()),
- event -> sUiAutomation.getWindows().stream().noneMatch(
- accessibilityWindowInfo -> accessibilityWindowInfo.getType()
- == AccessibilityWindowInfo.TYPE_MAGNIFICATION_OVERLAY), 5000);
+ try {
+ sUiAutomation.executeAndWaitForEvent(
+ () -> controller.setMagnificationConfig(config, false),
+ event -> sUiAutomation.getWindows().stream().anyMatch(
+ accessibilityWindowInfo -> accessibilityWindowInfo.getType()
+ == AccessibilityWindowInfo.TYPE_MAGNIFICATION_OVERLAY), 5000);
+
+ sUiAutomation.executeAndWaitForEvent(
+ () -> mService.runOnServiceSync(() -> mService.disableSelfAndRemove()),
+ event -> sUiAutomation.getWindows().stream().noneMatch(
+ accessibilityWindowInfo -> accessibilityWindowInfo.getType()
+ == AccessibilityWindowInfo.TYPE_MAGNIFICATION_OVERLAY), 5000);
+ } finally {
+ controller.resetCurrentMagnification(false);
+ }
}
@Test
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 3530c6a..f34bcd6 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -31,7 +31,6 @@
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Process;
@@ -697,32 +696,6 @@
}
}
- public void testSetUninstallBlocked_failIfNotProfileOwner() {
- if (!mDeviceAdmin) {
- Log.w(TAG, "Skipping testSetUninstallBlocked_failIfNotProfileOwner");
- return;
- }
- try {
- mDevicePolicyManager.setUninstallBlocked(mComponent,
- "android.admin.cts", true);
- fail("did not throw expected SecurityException");
- } catch (SecurityException e) {
- assertProfileOwnerMessage(e.getMessage());
- }
- }
-
- public void testSetUninstallBlocked_succeedForNotInstalledApps() {
- if (!mDeviceAdmin) {
- Log.w(TAG, "Skipping testSetUninstallBlocked_succeedForNotInstalledApps");
- return;
- }
- ComponentName profileOwner = DeviceAdminInfoTest.getProfileOwnerComponent();
- mDevicePolicyManager.setUninstallBlocked(profileOwner,
- "android.admin.not.installed", true);
- assertFalse(mDevicePolicyManager.isUninstallBlocked(profileOwner,
- "android.admin.not.installed"));
- }
-
public void testSetPermittedAccessibilityServices_failIfNotProfileOwner() {
if (!mDeviceAdmin) {
Log.w(TAG, "Skipping testSetPermittedAccessibilityServices_failIfNotProfileOwner");
diff --git a/tests/app/app/src/android/app/stubs/SendBubbleActivity.java b/tests/app/app/src/android/app/stubs/SendBubbleActivity.java
index 9c29acc..0281671 100644
--- a/tests/app/app/src/android/app/stubs/SendBubbleActivity.java
+++ b/tests/app/app/src/android/app/stubs/SendBubbleActivity.java
@@ -16,8 +16,6 @@
package android.app.stubs;
-import static android.app.stubs.BubbledActivity.EXTRA_LOCUS_ID;
-
import android.app.Activity;
import android.app.Notification;
import android.app.Notification.BubbleMetadata;
@@ -56,23 +54,6 @@
sendBroadcast(i);
}
- public void startBubbleActivity(int id) {
- startBubbleActivity(id, true /* addLocusId */);
- }
-
- /**
- * Starts the same activity that is in the bubble produced by this activity.
- */
- public void startBubbleActivity(int id, boolean addLocusId) {
- final Intent intent = new Intent(getApplicationContext(), BubbledActivity.class);
- // Clear any previous instance of this activity
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
- if (addLocusId) {
- intent.putExtra(EXTRA_LOCUS_ID, String.valueOf(id));
- }
- startActivity(intent);
- }
-
/**
* Sends a notification that has bubble metadata but the rest of the notification isn't
* configured correctly so the system won't allow it to bubble.
diff --git a/tests/app/app/src/android/app/stubs/TestNotificationListener.java b/tests/app/app/src/android/app/stubs/TestNotificationListener.java
index eabde5c..65ba550 100644
--- a/tests/app/app/src/android/app/stubs/TestNotificationListener.java
+++ b/tests/app/app/src/android/app/stubs/TestNotificationListener.java
@@ -34,6 +34,7 @@
public ArrayList<StatusBarNotification> mPosted = new ArrayList<>();
public Map<String, Integer> mRemoved = new HashMap<>();
public RankingMap mRankingMap;
+ public Map<String, Boolean> mIntercepted = new HashMap<>();
/**
* This controls whether there is a listener connected or not. Depending on the method, if the
@@ -89,6 +90,7 @@
public void resetData() {
mPosted.clear();
mRemoved.clear();
+ mIntercepted.clear();
}
public void addTestPackage(String packageName) {
@@ -103,6 +105,7 @@
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
if (sbn == null || !mTestPackages.contains(sbn.getPackageName())) { return; }
mRankingMap = rankingMap;
+ updateInterceptedRecords(rankingMap);
mPosted.add(sbn);
}
@@ -111,11 +114,26 @@
int reason) {
if (sbn == null || !mTestPackages.contains(sbn.getPackageName())) { return; }
mRankingMap = rankingMap;
+ updateInterceptedRecords(rankingMap);
mRemoved.put(sbn.getKey(), reason);
}
@Override
public void onNotificationRankingUpdate(RankingMap rankingMap) {
mRankingMap = rankingMap;
+ updateInterceptedRecords(rankingMap);
+ }
+
+ // update the local cache of intercepted records based on the given ranking map; should be run
+ // every time the listener gets updated ranking map info
+ private void updateInterceptedRecords(RankingMap rankingMap) {
+ for (String key : rankingMap.getOrderedKeys()) {
+ Ranking rank = new Ranking();
+ if (rankingMap.getRanking(key, rank)) {
+ // matchesInterruptionFilter is true if the notifiation can bypass and false if
+ // blocked so the "is intercepted" boolean is the opposite of that.
+ mIntercepted.put(key, !rank.matchesInterruptionFilter());
+ }
+ }
}
}
diff --git a/tests/app/src/android/app/cts/NotificationManagerBubbleTest.java b/tests/app/src/android/app/cts/NotificationManagerBubbleTest.java
index 82000a4..f4fda53 100644
--- a/tests/app/src/android/app/cts/NotificationManagerBubbleTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerBubbleTest.java
@@ -20,6 +20,7 @@
import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
+import static android.app.stubs.BubbledActivity.EXTRA_LOCUS_ID;
import static android.app.stubs.BubblesTestService.EXTRA_TEST_CASE;
import static android.app.stubs.BubblesTestService.TEST_CALL;
import static android.app.stubs.BubblesTestService.TEST_MESSAGING;
@@ -30,6 +31,7 @@
import static org.junit.Assert.assertThrows;
+import android.app.Activity;
import android.app.ActivityOptions;
import android.app.Instrumentation;
import android.app.KeyguardManager;
@@ -213,7 +215,7 @@
* @return the SendBubbleActivity that was opened.
*/
private SendBubbleActivity startSendBubbleActivity() {
- final CountDownLatch latch = new CountDownLatch(2);
+ final CountDownLatch latch = new CountDownLatch(1);
mBubbleBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -240,14 +242,7 @@
SendBubbleActivity sendBubbleActivity = (SendBubbleActivity) monitor.waitForActivity();
// Make sure device is unlocked
- KeyguardManager keyguardManager = mContext.getSystemService(KeyguardManager.class);
- keyguardManager.requestDismissKeyguard(sendBubbleActivity,
- new KeyguardManager.KeyguardDismissCallback() {
- @Override
- public void onDismissSucceeded() {
- latch.countDown();
- }
- });
+ ensureDeviceUnlocked(sendBubbleActivity);
try {
latch.await(500, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
@@ -266,6 +261,53 @@
return monitor;
}
+ private BubbledActivity startBubbleActivity(int id) {
+ return startBubbleActivity(id, true /* addLocusId */);
+ }
+
+ /**
+ * Starts the same activity that is in the bubble produced by this activity.
+ */
+ private BubbledActivity startBubbleActivity(int id, boolean addLocusId) {
+ Instrumentation.ActivityMonitor monitor = startBubbledActivityMonitor();
+
+ final Intent intent = new Intent(mContext, BubbledActivity.class);
+ // Clear any previous instance of this activity
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+ if (addLocusId) {
+ intent.putExtra(EXTRA_LOCUS_ID, String.valueOf(id));
+ }
+
+ InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ BubbledActivity bubbledActivity = (BubbledActivity) monitor.waitForActivity();
+ ensureDeviceUnlocked(bubbledActivity);
+ return bubbledActivity;
+ }
+
+ /**
+ * Make sure device is unlocked so the activity can become visible
+ */
+ private void ensureDeviceUnlocked(Activity activity) {
+ // Make sure device is unlocked
+ KeyguardManager keyguardManager = mContext.getSystemService(KeyguardManager.class);
+ if (keyguardManager.isKeyguardLocked()) {
+ CountDownLatch latch = new CountDownLatch(1);
+ keyguardManager.requestDismissKeyguard(activity,
+ new KeyguardManager.KeyguardDismissCallback() {
+ @Override
+ public void onDismissSucceeded() {
+ latch.countDown();
+ }
+ });
+ try {
+ latch.await(500, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException ignored) {
+ }
+ }
+ }
+
private void cleanupSendBubbleActivity() {
mContext.unregisterReceiver(mBubbleBroadcastReceiver);
}
@@ -852,13 +894,8 @@
verifyNotificationBubbleState(notifId, true /* shouldBeBubble */);
mListener.resetData();
- // Prep to find bubbled activity
- Instrumentation.ActivityMonitor monitor = startBubbledActivityMonitor();
-
// Launch same activity as whats in the bubble
- a.startBubbleActivity(notifId);
- BubbledActivity activity = (BubbledActivity) monitor.waitForActivity();
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ BubbledActivity activity = startBubbleActivity(notifId);
// It should have the locusId
assertEquals(new LocusId(String.valueOf(notifId)),
@@ -900,13 +937,8 @@
verifyNotificationBubbleState(BUBBLE_NOTIF_ID, true /* shouldBeBubble */);
mListener.resetData();
- // Prep to find bubbled activity
- Instrumentation.ActivityMonitor monitor = startBubbledActivityMonitor();
-
// Launch same activity as whats in the bubble
- a.startBubbleActivity(BUBBLE_NOTIF_ID);
- BubbledActivity activity = (BubbledActivity) monitor.waitForActivity();
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ BubbledActivity activity = startBubbleActivity(BUBBLE_NOTIF_ID);
// It should have the locusId
assertEquals(new LocusId(String.valueOf(BUBBLE_NOTIF_ID)),
@@ -948,13 +980,8 @@
verifyNotificationBubbleState(BUBBLE_NOTIF_ID, true /* shouldBeBubble */);
mListener.resetData();
- // Prep to find bubbled activity
- Instrumentation.ActivityMonitor monitor = startBubbledActivityMonitor();
-
// Launch same activity as whats in the bubble
- a.startBubbleActivity(BUBBLE_NOTIF_ID, false /* addLocusId */);
- BubbledActivity activity = (BubbledActivity) monitor.waitForActivity();
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ BubbledActivity activity = startBubbleActivity(BUBBLE_NOTIF_ID, false /* addLocusId */);
// It shouldn't have the locusId
assertNull(activity.getLocusId());
@@ -997,13 +1024,8 @@
verifyNotificationBubbleState(BUBBLE_NOTIF_ID, true /* shouldBeBubble */);
mListener.resetData();
- // Prep to find bubbled activity
- Instrumentation.ActivityMonitor monitor = startBubbledActivityMonitor();
-
// Launch same activity as whats in the bubble
- a.startBubbleActivity(BUBBLE_NOTIF_ID, true /* addLocusId */);
- BubbledActivity activity = (BubbledActivity) monitor.waitForActivity();
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ BubbledActivity activity = startBubbleActivity(BUBBLE_NOTIF_ID, true /* addLocusId */);
// Activity has the locus
assertNotNull(activity.getLocusId());
@@ -1051,13 +1073,8 @@
assertTrue(sbn.getNotification().getBubbleMetadata().isBubbleSuppressable());
assertFalse(sbn.getNotification().getBubbleMetadata().isBubbleSuppressed());
- // Prep to find bubbled activity
- Instrumentation.ActivityMonitor monitor = startBubbledActivityMonitor();
-
// Launch same activity as whats in the bubble
- a.startBubbleActivity(notifId);
- BubbledActivity activity = (BubbledActivity) monitor.waitForActivity();
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ BubbledActivity activity = startBubbleActivity(notifId);
// It should have the locusId
assertEquals(new LocusId(String.valueOf(notifId)),
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index e3a86ef..cedaae9 100755
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -2625,6 +2625,76 @@
}
}
+ public void testRepeatCallers_repeatCallNotIntercepted_contactAfterPhone() throws Exception {
+ toggleListenerAccess(true);
+ Thread.sleep(500); // wait for listener to be allowed
+ mListener = TestNotificationListener.getInstance();
+ assertNotNull(mListener);
+
+ // if a call is recorded with just phone number info (not a contact's uri), which may
+ // happen when the same contact calls across multiple apps (or if the contact uri provided
+ // is otherwise inconsistent), check for the contact's phone number
+ toggleNotificationPolicyAccess(mContext.getPackageName(),
+ InstrumentationRegistry.getInstrumentation(), true);
+ int origFilter = mNotificationManager.getCurrentInterruptionFilter();
+ Policy origPolicy = mNotificationManager.getNotificationPolicy();
+ Uri aliceUri = null;
+ long startTime = System.currentTimeMillis();
+ try {
+ mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
+ PRIORITY_CATEGORY_REPEAT_CALLERS, 0, 0));
+ // turn on manual DND
+ mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
+ assertExpectedDndState(INTERRUPTION_FILTER_PRIORITY);
+
+ insertSingleContact(ALICE, ALICE_PHONE, ALICE_EMAIL, false);
+ aliceUri = lookupContact(ALICE_PHONE);
+ Uri alicePhoneUri = makePhoneUri(ALICE_PHONE);
+
+ // no one has called; matchesCallFilter should return false for both URIs
+ assertFalse(mNotificationManager.matchesCallFilter(aliceUri));
+ assertFalse(mNotificationManager.matchesCallFilter(alicePhoneUri));
+
+ // register a call from Alice via just the phone number
+ sendNotification(1, null, R.drawable.blue, true, alicePhoneUri);
+ Thread.sleep(1000); // give the listener some time to receive info
+
+ // check that the first notification is intercepted
+ StatusBarNotification sbn = findPostedNotification(1, false);
+ assertNotNull(sbn);
+ assertTrue(mListener.mIntercepted.containsKey(sbn.getKey()));
+ assertTrue(mListener.mIntercepted.get(sbn.getKey())); // should be intercepted
+
+ // cancel first notification
+ cancelAndPoll(1);
+
+ // now send a call with only Alice's contact Uri as the info
+ // Note that this is a test of the repeat caller check, not matchesCallFilter itself
+ sendNotification(2, null, R.drawable.blue, true, aliceUri);
+ // wait for contact lookup, which may take a while
+ Thread.sleep(3000);
+
+ // now check that the second notification is not intercepted
+ StatusBarNotification sbn2 = findPostedNotification(2, true);
+ assertTrue(mListener.mIntercepted.containsKey(sbn2.getKey()));
+ assertFalse(mListener.mIntercepted.get(sbn2.getKey())); // should not be intercepted
+
+ // cancel second notification
+ cancelAndPoll(2);
+ } finally {
+ mNotificationManager.setInterruptionFilter(origFilter);
+ mNotificationManager.setNotificationPolicy(origPolicy);
+ if (aliceUri != null) {
+ // delete the contact
+ deleteSingleContact(aliceUri);
+ }
+
+ // clean up the recorded calls
+ SystemUtil.runWithShellPermissionIdentity(() ->
+ mNotificationManager.cleanUpCallersAfter(startTime));
+ }
+ }
+
public void testMatchesCallFilter_allCallers() throws Exception {
// allow all callers
toggleNotificationPolicyAccess(mContext.getPackageName(),
diff --git a/tests/appsearch/helper-app/src/com/android/cts/appsearch/helper/AppSearchTestService.java b/tests/appsearch/helper-app/src/com/android/cts/appsearch/helper/AppSearchTestService.java
index 0b25b55..306d8d5 100644
--- a/tests/appsearch/helper-app/src/com/android/cts/appsearch/helper/AppSearchTestService.java
+++ b/tests/appsearch/helper-app/src/com/android/cts/appsearch/helper/AppSearchTestService.java
@@ -99,7 +99,7 @@
String packageName, String databaseName, String namespace, String id) {
try {
AppSearchBatchResult<String, GenericDocument> getResult =
- mGlobalSearchSessionShim.getByDocumentId(
+ mGlobalSearchSessionShim.getByDocumentIdAsync(
packageName,
databaseName,
new GetByDocumentIdRequest.Builder(namespace)
diff --git a/tests/appsearch/src/com/android/cts/appsearch/app/GlobalSearchSessionPlatformCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/app/GlobalSearchSessionPlatformCtsTest.java
index cd96c50..1f74690 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/app/GlobalSearchSessionPlatformCtsTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/app/GlobalSearchSessionPlatformCtsTest.java
@@ -329,7 +329,7 @@
// Can get the document
AppSearchBatchResult<String, GenericDocument> result = mGlobalSearchSession
- .getByDocumentId(PKG_A, "database",
+ .getByDocumentIdAsync(PKG_A, "database",
new GetByDocumentIdRequest.Builder("namespace")
.addIds("id1")
.build()).get();
@@ -360,7 +360,7 @@
// Can get the document
AppSearchBatchResult<String, GenericDocument> result = mGlobalSearchSession
- .getByDocumentId(PKG_A, "database",
+ .getByDocumentIdAsync(PKG_A, "database",
new GetByDocumentIdRequest.Builder("namespace")
.addIds("id1")
.build()).get();
@@ -376,7 +376,7 @@
// Can get the document
AppSearchBatchResult<String, GenericDocument> result = mGlobalSearchSession
- .getByDocumentId(PKG_A, "database",
+ .getByDocumentIdAsync(PKG_A, "database",
new GetByDocumentIdRequest.Builder("namespace")
.addIds("id1")
.build()).get();
@@ -392,7 +392,7 @@
// Can get the document
AppSearchBatchResult<String, GenericDocument> result = mGlobalSearchSession
- .getByDocumentId(PKG_A, "database",
+ .getByDocumentIdAsync(PKG_A, "database",
new GetByDocumentIdRequest.Builder("namespace")
.addIds("id1")
.build()).get();
@@ -408,7 +408,7 @@
// Can get the document
AppSearchBatchResult<String, GenericDocument> result = mGlobalSearchSession
- .getByDocumentId(PKG_A, "database",
+ .getByDocumentIdAsync(PKG_A, "database",
new GetByDocumentIdRequest.Builder("namespace")
.addIds("id1")
.build()).get();
@@ -423,7 +423,7 @@
mGlobalSearchSession =
GlobalSearchSessionShimImpl.createGlobalSearchSession(mContext).get();
AppSearchBatchResult<String, GenericDocument> nonExistentResult = mGlobalSearchSession
- .getByDocumentId(PKG_A, "database",
+ .getByDocumentIdAsync(PKG_A, "database",
new GetByDocumentIdRequest.Builder("namespace")
.addIds("id1")
.build()).get();
@@ -439,7 +439,7 @@
mGlobalSearchSession =
GlobalSearchSessionShimImpl.createGlobalSearchSession(mContext).get();
AppSearchBatchResult<String, GenericDocument> unAuthResult = mGlobalSearchSession
- .getByDocumentId(PKG_A, "database",
+ .getByDocumentIdAsync(PKG_A, "database",
new GetByDocumentIdRequest.Builder("namespace")
.addIds("id1")
.build()).get();
@@ -463,7 +463,7 @@
// Can get the document
AppSearchBatchResult<String, GenericDocument> result = mGlobalSearchSession
- .getByDocumentId(PKG_A, DB_NAME,
+ .getByDocumentIdAsync(PKG_A, DB_NAME,
new GetByDocumentIdRequest.Builder(NAMESPACE_NAME)
.addIds("id1")
.build()).get();
@@ -472,7 +472,7 @@
// Can't get non existent document
AppSearchBatchResult<String, GenericDocument> nonExistent = mGlobalSearchSession
- .getByDocumentId(PKG_A, DB_NAME,
+ .getByDocumentIdAsync(PKG_A, DB_NAME,
new GetByDocumentIdRequest.Builder(NAMESPACE_NAME)
.addIds("id2")
.build()).get();
@@ -494,7 +494,7 @@
// Can't get the document
AppSearchBatchResult<String, GenericDocument> result = mGlobalSearchSession
- .getByDocumentId(PKG_A, DB_NAME,
+ .getByDocumentIdAsync(PKG_A, DB_NAME,
new GetByDocumentIdRequest.Builder(NAMESPACE_NAME)
.addIds("id1")
.build()).get();
@@ -517,7 +517,7 @@
GlobalSearchSessionShimImpl.createGlobalSearchSession(mContext).get();
AppSearchBatchResult<String, GenericDocument> nonExistentResult =
- mGlobalSearchSession.getByDocumentId(PKG_A, DB_NAME,
+ mGlobalSearchSession.getByDocumentIdAsync(PKG_A, DB_NAME,
new GetByDocumentIdRequest.Builder(NAMESPACE_NAME)
.addIds("id1")
.build()).get();
@@ -538,7 +538,7 @@
GlobalSearchSessionShimImpl.createGlobalSearchSession(mContext).get();
AppSearchBatchResult<String, GenericDocument> unAuthResult =
- mGlobalSearchSession.getByDocumentId(PKG_A, DB_NAME,
+ mGlobalSearchSession.getByDocumentIdAsync(PKG_A, DB_NAME,
new GetByDocumentIdRequest.Builder(NAMESPACE_NAME)
.addIds("id1")
.build()).get();
@@ -560,7 +560,7 @@
GlobalSearchSessionShimImpl.createGlobalSearchSession(mContext).get();
AppSearchBatchResult<String, GenericDocument> noGlobalResult = mGlobalSearchSession
- .getByDocumentId(PKG_A, DB_NAME,
+ .getByDocumentIdAsync(PKG_A, DB_NAME,
new GetByDocumentIdRequest.Builder(NAMESPACE_NAME)
.addIds("id1")
.build()).get();
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchResultCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchResultCtsTest.java
index 2691ecf..6adcfce 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchResultCtsTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/AppSearchResultCtsTest.java
@@ -23,6 +23,14 @@
import org.junit.Test;
public class AppSearchResultCtsTest {
+ @Test
+ public void testNewSuccessfulResult() {
+ AppSearchResult<String> result = AppSearchResult.newSuccessfulResult("String");
+ assertThat(result.getResultCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ assertThat(result.getResultValue()).isEqualTo("String");
+ assertThat(result.isSuccess()).isTrue();
+ assertThat(result.getErrorMessage()).isNull();
+ }
@Test
public void testResultEquals_identical() {
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java
index 5efc5a8..4e186a3 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/GlobalSearchSessionCtsTestBase.java
@@ -26,12 +26,14 @@
import static org.junit.Assume.assumeTrue;
import android.annotation.NonNull;
+import android.app.appsearch.AppSearchBatchResult;
import android.app.appsearch.AppSearchResult;
import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.AppSearchSchema.PropertyConfig;
import android.app.appsearch.AppSearchSessionShim;
import android.app.appsearch.Features;
import android.app.appsearch.GenericDocument;
+import android.app.appsearch.GetByDocumentIdRequest;
import android.app.appsearch.GetSchemaResponse;
import android.app.appsearch.GlobalSearchSessionShim;
import android.app.appsearch.PutDocumentsRequest;
@@ -130,6 +132,59 @@
}
@Test
+ public void testGlobalGetById() throws Exception {
+ assumeTrue(
+ mGlobalSearchSession
+ .getFeatures()
+ .isFeatureSupported(Features.GLOBAL_SEARCH_SESSION_GET_BY_ID));
+ SearchSpec exactSearchSpec =
+ new SearchSpec.Builder().setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY).build();
+
+ // Schema registration
+ mDb1.setSchema(new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build())
+ .get();
+
+ AppSearchBatchResult<String, GenericDocument> nonExistent =
+ mGlobalSearchSession
+ .getByDocumentIdAsync(
+ mContext.getPackageName(),
+ DB_NAME_1,
+ new GetByDocumentIdRequest.Builder("namespace")
+ .addIds("id1")
+ .build())
+ .get();
+
+ assertThat(nonExistent.isSuccess()).isFalse();
+ assertThat(nonExistent.getSuccesses()).isEmpty();
+ assertThat(nonExistent.getFailures()).containsKey("id1");
+ assertThat(nonExistent.getFailures().get("id1").getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+
+ // Index a document
+ AppSearchEmail inEmail =
+ new AppSearchEmail.Builder("namespace", "id1")
+ .setFrom("from@example.com")
+ .setTo("to1@example.com", "to2@example.com")
+ .setSubject("testPut example")
+ .setBody("This is the body of the testPut email")
+ .build();
+ checkIsBatchResultSuccess(
+ mDb1.put(new PutDocumentsRequest.Builder().addGenericDocuments(inEmail).build()));
+
+ // Query for the document
+ AppSearchBatchResult<String, GenericDocument> afterPutDocuments =
+ mGlobalSearchSession
+ .getByDocumentIdAsync(
+ mContext.getPackageName(),
+ DB_NAME_1,
+ new GetByDocumentIdRequest.Builder("namespace")
+ .addIds("id1")
+ .build())
+ .get();
+ assertThat(afterPutDocuments.getSuccesses()).containsExactly("id1", inEmail);
+ }
+
+ @Test
public void testGlobalQuery_oneInstance() throws Exception {
// Snapshot what documents may already exist on the device.
SearchSpec exactSearchSpec =
@@ -1474,6 +1529,33 @@
}
@Test
+ public void testGlobalGetByDocumentId_notSupported() throws Exception {
+ assumeFalse(
+ mGlobalSearchSession
+ .getFeatures()
+ .isFeatureSupported(Features.GLOBAL_SEARCH_SESSION_GET_BY_ID));
+
+ Context context = ApplicationProvider.getApplicationContext();
+
+ UnsupportedOperationException e =
+ assertThrows(
+ UnsupportedOperationException.class,
+ () ->
+ mGlobalSearchSession.getByDocumentIdAsync(
+ context.getPackageName(),
+ DB_NAME_1,
+ new GetByDocumentIdRequest.Builder("namespace")
+ .addIds("id")
+ .build()));
+
+ assertThat(e)
+ .hasMessageThat()
+ .isEqualTo(
+ Features.GLOBAL_SEARCH_SESSION_GET_BY_ID
+ + " is not supported on this AppSearch implementation.");
+ }
+
+ @Test
public void testAddObserver_schemaChange_added() throws Exception {
// Register an observer
TestObserverCallback observer = new TestObserverCallback();
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/app/SetSchemaRequestCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/app/SetSchemaRequestCtsTest.java
index 8171168..d72b482 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/app/SetSchemaRequestCtsTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/app/SetSchemaRequestCtsTest.java
@@ -274,6 +274,62 @@
}
@Test
+ public void testClearSchemaTypeVisibleForPermissions() {
+ SetSchemaRequest.Builder setSchemaRequestBuilder =
+ new SetSchemaRequest.Builder()
+ .addSchemas(
+ new AppSearchSchema.Builder("Schema1").build(),
+ new AppSearchSchema.Builder("Schema2").build())
+ .addRequiredPermissionsForSchemaTypeVisibility(
+ "Schema1",
+ ImmutableSet.of(
+ SetSchemaRequest.READ_SMS, SetSchemaRequest.READ_CALENDAR))
+ .addRequiredPermissionsForSchemaTypeVisibility(
+ "Schema1",
+ ImmutableSet.of(SetSchemaRequest.READ_HOME_APP_SEARCH_DATA))
+ .addRequiredPermissionsForSchemaTypeVisibility(
+ "Schema2", ImmutableSet.of(SetSchemaRequest.READ_EXTERNAL_STORAGE));
+
+ SetSchemaRequest request = setSchemaRequestBuilder.build();
+
+ assertThat(request.getRequiredPermissionsForSchemaTypeVisibility())
+ .containsExactly(
+ "Schema1",
+ ImmutableSet.of(
+ ImmutableSet.of(
+ SetSchemaRequest.READ_SMS,
+ SetSchemaRequest.READ_CALENDAR),
+ ImmutableSet.of(
+ SetSchemaRequest.READ_HOME_APP_SEARCH_DATA)),
+ "Schema2",
+ ImmutableSet.of(
+ ImmutableSet.of(SetSchemaRequest.READ_EXTERNAL_STORAGE)));
+
+ // Clear the permissions in the builder
+ setSchemaRequestBuilder.clearRequiredPermissionsForSchemaTypeVisibility("Schema1");
+
+ // New object should be updated
+ assertThat(setSchemaRequestBuilder.build().getRequiredPermissionsForSchemaTypeVisibility())
+ .containsExactly(
+ "Schema2",
+ ImmutableSet.of(ImmutableSet.of(SetSchemaRequest.READ_EXTERNAL_STORAGE)));
+
+ // Old object should remain unchanged
+ assertThat(request.getRequiredPermissionsForSchemaTypeVisibility())
+ .containsExactly(
+ "Schema1",
+ ImmutableSet.of(
+ ImmutableSet.of(
+ SetSchemaRequest.READ_SMS,
+ SetSchemaRequest.READ_CALENDAR),
+ ImmutableSet.of(
+ SetSchemaRequest.READ_HOME_APP_SEARCH_DATA)),
+ "Schema2",
+ ImmutableSet.of(
+ ImmutableSet.of(SetSchemaRequest.READ_EXTERNAL_STORAGE)));
+ }
+
+ @Test
public void testSchemaTypeVisibilityForPackage_visible() {
AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/observer/DocumentChangeInfoCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/observer/DocumentChangeInfoCtsTest.java
new file mode 100644
index 0000000..2459214
--- /dev/null
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/observer/DocumentChangeInfoCtsTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.cts.observer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.observer.DocumentChangeInfo;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.Test;
+
+public class DocumentChangeInfoCtsTest {
+ @Test
+ public void testConstructor() {
+ DocumentChangeInfo DocumentChangeInfo =
+ new DocumentChangeInfo(
+ "packageName",
+ "databaseName",
+ "namespace",
+ "SchemaName",
+ ImmutableSet.of("documentId1", "documentId2"));
+ assertThat(DocumentChangeInfo.getPackageName()).isEqualTo("packageName");
+ assertThat(DocumentChangeInfo.getDatabaseName()).isEqualTo("databaseName");
+ assertThat(DocumentChangeInfo.getNamespace()).isEqualTo("namespace");
+ assertThat(DocumentChangeInfo.getSchemaName()).isEqualTo("SchemaName");
+ assertThat(DocumentChangeInfo.getChangedDocumentIds())
+ .containsExactly("documentId1", "documentId2");
+ }
+
+ @Test
+ public void testEqualsAndHasCode() {
+ DocumentChangeInfo info1Copy1 =
+ new DocumentChangeInfo(
+ "packageName",
+ "databaseName",
+ "namespace",
+ "SchemaName",
+ ImmutableSet.of("documentId1", "documentId2"));
+ DocumentChangeInfo info1Copy2 =
+ new DocumentChangeInfo(
+ "packageName",
+ "databaseName",
+ "namespace",
+ "SchemaName",
+ ImmutableSet.of("documentId1", "documentId2"));
+ DocumentChangeInfo info2 =
+ new DocumentChangeInfo(
+ "packageName",
+ "databaseName",
+ "namespace",
+ "SchemaName",
+ ImmutableSet.of("documentId3", "documentId2"));
+
+ assertThat(info1Copy1).isEqualTo(info1Copy2);
+ assertThat(info1Copy1.hashCode()).isEqualTo(info1Copy2.hashCode());
+ assertThat(info1Copy1).isNotEqualTo(info2);
+ assertThat(info1Copy1.hashCode()).isNotEqualTo(info2.hashCode());
+ }
+}
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/observer/ObserverSpecCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/observer/ObserverSpecCtsTest.java
new file mode 100644
index 0000000..bdce40c
--- /dev/null
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/observer/ObserverSpecCtsTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.cts.observer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.observer.ObserverSpec;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.Test;
+
+public class ObserverSpecCtsTest {
+ @Test
+ public void testFilterSchemas() {
+ ObserverSpec observerSpec =
+ new ObserverSpec.Builder()
+ .addFilterSchemas("Schema1", "Schema2")
+ .addFilterSchemas(ImmutableSet.of("Schema3", "Schema4"))
+ .build();
+ assertThat(observerSpec.getFilterSchemas())
+ .containsExactly("Schema1", "Schema2", "Schema3", "Schema4");
+ }
+}
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/observer/SchemaChangeInfoCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/observer/SchemaChangeInfoCtsTest.java
new file mode 100644
index 0000000..a2f1004
--- /dev/null
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/observer/SchemaChangeInfoCtsTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.cts.observer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.observer.SchemaChangeInfo;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.Test;
+
+public class SchemaChangeInfoCtsTest {
+ @Test
+ public void testConstructor() {
+ SchemaChangeInfo schemaChangeInfo =
+ new SchemaChangeInfo(
+ "packageName",
+ "databaseName",
+ ImmutableSet.of("schemaName1", "schemaName2"));
+ assertThat(schemaChangeInfo.getPackageName()).isEqualTo("packageName");
+ assertThat(schemaChangeInfo.getDatabaseName()).isEqualTo("databaseName");
+ assertThat(schemaChangeInfo.getChangedSchemaNames())
+ .containsExactly("schemaName1", "schemaName2");
+ }
+
+ @Test
+ public void testEqualsAndHasCode() {
+ SchemaChangeInfo info1Copy1 =
+ new SchemaChangeInfo(
+ "packageName",
+ "databaseName",
+ ImmutableSet.of("schemaName1", "schemaName2"));
+ SchemaChangeInfo info1Copy2 =
+ new SchemaChangeInfo(
+ "packageName",
+ "databaseName",
+ ImmutableSet.of("schemaName1", "schemaName2"));
+ SchemaChangeInfo info2 =
+ new SchemaChangeInfo(
+ "packageName",
+ "databaseName",
+ ImmutableSet.of("schemaName3", "schemaName2"));
+
+ assertThat(info1Copy1).isEqualTo(info1Copy2);
+ assertThat(info1Copy1.hashCode()).isEqualTo(info1Copy2.hashCode());
+ assertThat(info1Copy1).isNotEqualTo(info2);
+ assertThat(info1Copy1.hashCode()).isNotEqualTo(info2.hashCode());
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/commontests/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/commontests/AutoFillServiceTestCase.java
index 55f94ef..ae7a665 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/commontests/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/commontests/AutoFillServiceTestCase.java
@@ -109,7 +109,7 @@
}
protected static InlineUiBot getInlineUiBot() {
- return sDefaultUiBot2;
+ return new InlineUiBot(getContext());
}
protected static UiBot getDropdownUiBot() {
@@ -485,7 +485,6 @@
}
protected static final UiBot sDefaultUiBot = new UiBot();
- protected static final InlineUiBot sDefaultUiBot2 = new InlineUiBot();
private AutoFillServiceTestCase() {
throw new UnsupportedOperationException("Contain static stuff only");
diff --git a/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java
index 6149ec9..6c2afe0 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java
@@ -771,6 +771,7 @@
/**
* Gets the total number of nodes in an structure.
+ * A node that has a non-null IdPackage which does not match the test package is not counted.
*/
public static int getNumberNodes(AssistStructure structure,
CharSequence windowTitle) {
@@ -798,14 +799,18 @@
/**
* Gets the total number of nodes in an node, including all descendants and the node itself.
+ * A node that has a non-null IdPackage which does not match the test package is not counted.
*/
public static int getNumberNodes(ViewNode node) {
+ if (node.getIdPackage() != null && !node.getIdPackage().equals(MY_PACKAGE)) {
+ Log.w(TAG, "ViewNode ignored in getNumberNodes because of mismatched package: "
+ + node.getIdPackage());
+ return 0;
+ }
int count = 1;
final int childrenSize = node.getChildCount();
- if (childrenSize > 0) {
- for (int i = 0; i < childrenSize; i++) {
- count += getNumberNodes(node.getChildAt(i));
- }
+ for (int i = 0; i < childrenSize; i++) {
+ count += getNumberNodes(node.getChildAt(i));
}
return count;
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/testcore/InlineUiBot.java b/tests/autofillservice/src/android/autofillservice/cts/testcore/InlineUiBot.java
index 50892fc..f488f09 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/testcore/InlineUiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/testcore/InlineUiBot.java
@@ -20,14 +20,16 @@
import static android.autofillservice.cts.testcore.Timeouts.LONG_PRESS_MS;
import static android.autofillservice.cts.testcore.Timeouts.UI_TIMEOUT;
+import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiObject2;
+import android.util.Log;
import com.android.compatibility.common.util.RequiredFeatureRule;
-import com.android.compatibility.common.util.Timeout;
import com.android.cts.mockime.MockIme;
import org.junit.rules.RuleChain;
@@ -46,12 +48,11 @@
private static final RequiredFeatureRule REQUIRES_IME_RULE = new RequiredFeatureRule(
PackageManager.FEATURE_INPUT_METHODS);
- public InlineUiBot() {
- this(UI_TIMEOUT);
- }
+ private final Context mContext;
- public InlineUiBot(Timeout defaultTimeout) {
- super(defaultTimeout);
+ public InlineUiBot(Context context) {
+ super(UI_TIMEOUT);
+ mContext = context;
}
public static RuleChain annotateRule(TestRule rule) {
@@ -73,7 +74,7 @@
* Selects the suggestion in the {@link MockIme}'s suggestion strip by the given text.
*/
public void selectSuggestion(String name) throws Exception {
- final UiObject2 strip = findSuggestionStrip(UI_TIMEOUT);
+ final UiObject2 strip = findSuggestionStrip();
final UiObject2 dataset = strip.findObject(By.text(name));
if (dataset == null) {
throw new AssertionError("no dataset " + name + " in " + getChildrenAsText(strip));
@@ -88,7 +89,7 @@
@Override
public void longPressSuggestion(String name) throws Exception {
- final UiObject2 strip = findSuggestionStrip(UI_TIMEOUT);
+ final UiObject2 strip = findSuggestionStrip();
final UiObject2 dataset = strip.findObject(By.text(name));
if (dataset == null) {
throw new AssertionError("no dataset " + name + " in " + getChildrenAsText(strip));
@@ -97,14 +98,14 @@
}
@Override
- public UiObject2 assertDatasets(String...names) throws Exception {
- final UiObject2 picker = findSuggestionStrip(UI_TIMEOUT);
+ public UiObject2 assertDatasets(String... names) throws Exception {
+ final UiObject2 picker = findSuggestionStrip();
return assertDatasets(picker, names);
}
@Override
public void assertSuggestion(String name) throws Exception {
- final UiObject2 strip = findSuggestionStrip(UI_TIMEOUT);
+ final UiObject2 strip = findSuggestionStrip();
final UiObject2 dataset = strip.findObject(By.text(name));
if (dataset == null) {
throw new AssertionError("no dataset " + name + " in " + getChildrenAsText(strip));
@@ -113,7 +114,7 @@
@Override
public void assertNoSuggestion(String name) throws Exception {
- final UiObject2 strip = findSuggestionStrip(UI_TIMEOUT);
+ final UiObject2 strip = findSuggestionStrip();
final UiObject2 dataset = strip.findObject(By.text(name));
if (dataset != null) {
throw new AssertionError("has dataset " + name + " in " + getChildrenAsText(strip));
@@ -122,7 +123,10 @@
@Override
public void scrollSuggestionView(Direction direction, int speed) throws Exception {
- final UiObject2 strip = findSuggestionStrip(UI_TIMEOUT);
+ final UiObject2 strip = findSuggestionStrip();
+ final int defaultWidth = strip.getVisibleBounds().width() / 4;
+ final int width = getEdgeSensitivityWidth(defaultWidth);
+ strip.setGestureMargin(width);
strip.fling(direction, speed);
}
@@ -133,7 +137,18 @@
}
}
- private UiObject2 findSuggestionStrip(Timeout timeout) throws Exception {
- return waitForObject(SUGGESTION_STRIP_SELECTOR, timeout);
+ private UiObject2 findSuggestionStrip() throws Exception {
+ return waitForObject(SUGGESTION_STRIP_SELECTOR, Timeouts.UI_TIMEOUT);
+ }
+
+ private int getEdgeSensitivityWidth(int defaultWidth) {
+ Resources resources = mContext.getResources();
+ int resId = resources.getIdentifier("config_backGestureInset", "dimen", "android");
+ try {
+ return resources.getDimensionPixelSize(resId) + 1;
+ } catch (Resources.NotFoundException e) {
+ Log.e(TAG, "Failed to get edge sensitivity width. Defaulting to " + defaultWidth, e);
+ return defaultWidth;
+ }
}
}
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
index e1f17da..f6b7830 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
@@ -994,23 +994,32 @@
assertNotNull(
String.format("Can't get camera characteristics from: ID %s", cameraId), props);
+ Integer lensFacing = props.get(CameraCharacteristics.LENS_FACING);
+ if (lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_EXTERNAL) {
+ // Automotive device implementations may have external cameras but they are exempted
+ // from this test case.
+ continue;
+ }
+
Integer cameraLocation = props.get(CameraCharacteristics.AUTOMOTIVE_LOCATION);
assertNotNull(
String.format("Can't get a camera location from: ID %s", cameraId),
cameraLocation);
- int[] lensFacing = props.get(CameraCharacteristics.AUTOMOTIVE_LENS_FACING);
+ int[] automotiveLensFacing = props.get(CameraCharacteristics.AUTOMOTIVE_LENS_FACING);
assertNotNull(
String.format("Can't get a lens facing direction from: ID %s", cameraId),
- lensFacing);
+ automotiveLensFacing);
if (cameraLocation == CameraCharacteristics.AUTOMOTIVE_LOCATION_EXTERIOR_OTHER ||
cameraLocation == CameraCharacteristics.AUTOMOTIVE_LOCATION_EXTRA_OTHER ||
- lensFacing[0] == CameraCharacteristics.AUTOMOTIVE_LENS_FACING_EXTERIOR_OTHER ||
- lensFacing[0] == CameraCharacteristics.AUTOMOTIVE_LENS_FACING_INTERIOR_OTHER) {
+ automotiveLensFacing[0] ==
+ CameraCharacteristics.AUTOMOTIVE_LENS_FACING_EXTERIOR_OTHER ||
+ automotiveLensFacing[0] ==
+ CameraCharacteristics.AUTOMOTIVE_LENS_FACING_INTERIOR_OTHER) {
checkAutomotiveLensPoseCharacteristics(cameraId, props);
} else {
- Pair<Integer, Integer> key = new Pair<>(cameraLocation, lensFacing[0]);
+ Pair<Integer, Integer> key = new Pair<>(cameraLocation, automotiveLensFacing[0]);
if (cameraGroup.containsKey(key)) {
cameraGroup.get(key).add(cameraId);
} else {
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 5db96a4..8b5b33d 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -3106,6 +3106,90 @@
}
/**
+ * Validate {@link CameraCharacteristics#LENS_POSE_TRANSLATION} and @{link
+ * CameraCharacteristics#LENS_POSE_ROTATION} of camera that list below characteristics in their
+ * static metadata.
+ * - CameraCharacteristics.AUTOMOTIVE_LOCATION_INTERIOR_OTHER
+ * - CameraCharacteristics.AUTOMOTIVE_LOCATION_EXTERIOR_OTHER
+ * - CameraCharacteristics.AUTOMOTIVE_LOCATION_EXTRA_OTHER
+ */
+ @Test
+ public void testAutomotiveCameraCharacteristics() throws Exception {
+ for (int i = 0; i < mAllCameraIds.length; i++) {
+ CameraCharacteristics c = mCharacteristics.get(i);
+
+ Integer location = c.get(CameraCharacteristics.AUTOMOTIVE_LOCATION);
+ int[] lensFacing = c.get(CameraCharacteristics.AUTOMOTIVE_LENS_FACING);
+ if (location == null || lensFacing == null) {
+ // CameraManagerTest#testCameraManagerAutomotiveCameras() guarantees
+ // CameraCharacteristics.AUTOMOTIVE_LOCATION and
+ // CameraCharacteristics.AUTOMOTIVE_LENS_FACING are listed in a static metadata of
+ // cameras on the automotive device implementations.
+ continue;
+ }
+
+ float[] translation = c.get(CameraCharacteristics.LENS_POSE_TRANSLATION);
+ float[] rotation = c.get(CameraCharacteristics.LENS_POSE_ROTATION);
+ assertTrue("android.lens.poseTranslation and android.lens.poseRotation must exist " +
+ "together or not at all",
+ (translation != null) == (rotation != null));
+ if (translation == null && rotation != null) {
+ // Cameras without android.lens.poseTranslation and anroid.lens.poseRotation are
+ // exempt from this test case.
+ continue;
+ }
+
+ // android.lens.poseTranslation describes the lens optical center of the camera device
+ // as a three dimensional vector (x, y, z) and in the unit of meters. On the automotive
+ // sensor coordinate system, we expect the following:
+ // - The width of the vehicle body frame would not exceed 6 meters, which is a width of
+ // the vehicle lane approximately.
+ // - The length of the vehicle body frame would not exceed 10 meters, which is an
+ // average length of the city bus. We apply approximately 20% tolerance to this value
+ // because of a relatively higher variance of the vehicle's length.
+ // - The height of the vehicle body frame would not exceed 5 meters, which is an average
+ // height of the double decker bus.
+ assertTrue("Lens pose translation vector is invalid",
+ (translation[0] >= -3 && translation[0] <= 3)
+ && (translation[1] >= -2 && translation[1] <= 10)
+ && (translation[2] >= 0 && translation[2] <= 5));
+
+ // Convert a given quaternion to axis-angle representation
+ double theta = 2.0 * Math.acos(rotation[3]);
+ double a_x = rotation[0] / Math.sin(theta / 2.0);
+ double a_y = rotation[1] / Math.sin(theta / 2.0);
+ double a_z = rotation[2] / Math.sin(theta / 2.0);
+
+ // Calculate an angle between a translation vector and a rotation axis
+ double dot = (translation[0] * a_x) + (translation[1] * a_y) + (translation[2] * a_z);
+ double mag_a = Math.sqrt(Math.pow(translation[0], 2) + Math.pow(translation[1], 2)
+ + Math.pow(translation[2], 2));
+ double mag_b =
+ Math.sqrt(Math.pow(a_x, 2) + Math.pow(a_y, 2) + Math.pow(a_z, 2));
+ double angle = Math.acos(dot / (mag_a * mag_b));
+
+ if (location == CameraCharacteristics.AUTOMOTIVE_LOCATION_EXTERIOR_OTHER
+ || location == CameraCharacteristics.AUTOMOTIVE_LOCATION_EXTRA_OTHER) {
+ // If android.automotive.location is
+ // CameraCharacteristics.AUTOMOTIVE_LOCATION_EXTERIOR_OTHER or
+ // CameraCharacteristics.AUTOMOTIVE_LOCATION_EXTRA_OTHER, its
+ // android.lens.poseRotation should not describe a direction toward the inside of
+ // the vehicle cabin.
+ assertTrue("Lens pose rotation should not describe a direction toward the cabin",
+ angle >= Math.PI / 4);
+ } else {
+ // Likewise, if android.automotive.location is
+ // CameraCharacteristics.AUTOMOTIVE_LOCATION_INTERIOR_OTHER, its
+ // android.lens.poseRotation should not describe a direction toward the outside of
+ // the vehicle cabin.
+ assertTrue("Lens pose rotation should not describe a direction toward the " +
+ "outside of the cabin",
+ angle <= Math.PI * 3 / 4);
+ }
+ }
+ }
+
+ /**
* Check key is present in characteristics if the hardware level is at least {@code hwLevel};
* check that the key is present if the actual capabilities are one of {@code capabilities}.
*
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
index 1535458..d65b7f6 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -295,7 +295,7 @@
int format, Size targetSize, int numBuffers, String overridePhysicalCameraId,
MultiResolutionStreamConfigurationMap multiResStreamConfig,
boolean createMultiResiStreamConfig, ImageDropperListener listener, Handler handler,
- long dynamicRangeProfile, int streamUseCase) {
+ long dynamicRangeProfile, long streamUseCase) {
if (createMultiResiStreamConfig) {
Collection<MultiResolutionStreamInfo> multiResolutionStreams =
multiResStreamConfig.getOutputInfo(format);
diff --git a/tests/cloudsearch/src/android/cloudsearch/cts/SearchRequestTest.java b/tests/cloudsearch/src/android/cloudsearch/cts/SearchRequestTest.java
index 3913da4..5966d95 100644
--- a/tests/cloudsearch/src/android/cloudsearch/cts/SearchRequestTest.java
+++ b/tests/cloudsearch/src/android/cloudsearch/cts/SearchRequestTest.java
@@ -45,11 +45,11 @@
Bundle constraints = new Bundle();
constraints.putBoolean(SearchRequest.CONSTRAINT_IS_PRESUBMIT_SUGGESTION,
true);
- final String source = "AiAi_CALLER";
+ final String pkgName = "android.cloudsearch.cts";
SearchRequest request = new SearchRequest.Builder("").setResultNumber(rn)
.setResultOffset(offset).setSearchConstraints(constraints).setQuery(query)
- .setMaxLatencyMillis(maxLatency).setSource(source).build();
+ .setMaxLatencyMillis(maxLatency).setCallerPackageName(pkgName).build();
/** Check the original request. */
assertThat(request.getQuery()).isEqualTo(query);
@@ -59,7 +59,7 @@
final Bundle sc = request.getSearchConstraints();
assertThat(sc.getBoolean(SearchRequest.CONSTRAINT_IS_PRESUBMIT_SUGGESTION))
.isEqualTo(true);
- assertThat(request.getSource()).isEqualTo(source);
+ assertThat(request.getCallerPackageName()).isEqualTo(pkgName);
Parcel parcel = Parcel.obtain();
parcel.setDataPosition(0);
@@ -74,7 +74,7 @@
final Bundle sccopy = request.getSearchConstraints();
assertThat(sccopy.getBoolean(SearchRequest.CONSTRAINT_IS_PRESUBMIT_SUGGESTION))
.isEqualTo(true);
- assertThat(copy.getSource()).isEqualTo(source);
+ assertThat(copy.getCallerPackageName()).isEqualTo(pkgName);
parcel.recycle();
}
diff --git a/tests/cloudsearch/src/android/cloudsearch/cts/SearchResultTest.java b/tests/cloudsearch/src/android/cloudsearch/cts/SearchResultTest.java
index 042d40c..9dd83f4 100644
--- a/tests/cloudsearch/src/android/cloudsearch/cts/SearchResultTest.java
+++ b/tests/cloudsearch/src/android/cloudsearch/cts/SearchResultTest.java
@@ -15,9 +15,14 @@
*/
package android.cloudsearch.cts;
+import static androidx.test.InstrumentationRegistry.getContext;
+
import static com.google.common.truth.Truth.assertThat;
+import android.app.PendingIntent;
import android.app.cloudsearch.SearchResult;
+import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
@@ -41,12 +46,20 @@
final String title = "title";
final String snippet = "Good Snippet";
final float score = 10;
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.android.com"));
+ PendingIntent pendingIntent = PendingIntent.getActivity(getContext(),
+ 1, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
Bundle extraInfos = new Bundle();
extraInfos.putBoolean(SearchResult.EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER,
false);
extraInfos.putString(SearchResult.EXTRAINFO_APP_DEVELOPER_NAME,
"best_app_developer");
+ extraInfos.putParcelable(SearchResult.EXTRAINFO_ACTION_INSTALL_BUTTON, pendingIntent);
+ extraInfos.putParcelable(SearchResult.EXTRAINFO_ACTION_APP_CARD, pendingIntent);
+ extraInfos.putString(SearchResult.EXTRAINFO_APP_PACKAGE_NAME,
+ "best_package_name");
+ extraInfos.putDouble(SearchResult.EXTRAINFO_APP_INSTALL_COUNT, 10);
SearchResult result = new SearchResult.Builder(title, extraInfos)
.setSnippet(snippet).setTitle(title).setExtraInfos(extraInfos)
@@ -63,6 +76,18 @@
assertThat(rExtraInfos
.getString(SearchResult.EXTRAINFO_APP_DEVELOPER_NAME))
.isEqualTo("best_app_developer");
+ assertThat((PendingIntent) rExtraInfos
+ .getParcelable(SearchResult.EXTRAINFO_ACTION_INSTALL_BUTTON))
+ .isEqualTo(pendingIntent);
+ assertThat((PendingIntent) rExtraInfos
+ .getParcelable(SearchResult.EXTRAINFO_ACTION_APP_CARD))
+ .isEqualTo(pendingIntent);
+ assertThat(rExtraInfos
+ .getString(SearchResult.EXTRAINFO_APP_PACKAGE_NAME))
+ .isEqualTo("best_package_name");
+ assertThat(rExtraInfos
+ .getDouble(SearchResult.EXTRAINFO_APP_INSTALL_COUNT))
+ .isEqualTo(10);
Parcel parcel = Parcel.obtain();
parcel.setDataPosition(0);
@@ -80,6 +105,18 @@
assertThat(rExtraInfosCopy
.getString(SearchResult.EXTRAINFO_APP_DEVELOPER_NAME))
.isEqualTo("best_app_developer");
+ assertThat((PendingIntent) rExtraInfosCopy
+ .getParcelable(SearchResult.EXTRAINFO_ACTION_INSTALL_BUTTON))
+ .isEqualTo(pendingIntent);
+ assertThat((PendingIntent) rExtraInfosCopy
+ .getParcelable(SearchResult.EXTRAINFO_ACTION_APP_CARD))
+ .isEqualTo(pendingIntent);
+ assertThat(rExtraInfosCopy
+ .getString(SearchResult.EXTRAINFO_APP_PACKAGE_NAME))
+ .isEqualTo("best_package_name");
+ assertThat(rExtraInfosCopy
+ .getDouble(SearchResult.EXTRAINFO_APP_INSTALL_COUNT))
+ .isEqualTo(10);
parcel.recycle();
}
diff --git a/tests/devicepolicy/AndroidManifest.xml b/tests/devicepolicy/AndroidManifest.xml
index c8dd6c4..c8c6c0e 100644
--- a/tests/devicepolicy/AndroidManifest.xml
+++ b/tests/devicepolicy/AndroidManifest.xml
@@ -23,6 +23,9 @@
canInteractAcrossProfiles_permissionIsSet_returnsTrue -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES"/>
+ <!-- Seemingly the INTERNET permission cannot be adopted. -->
+ <uses-permission android:name="android.permission.INTERNET" />
+
<!-- Add a network security config that trusts user added CAs for tests -->
<application android:testOnly="true"
android:appComponentFactory="com.android.eventlib.premade.EventLibAppComponentFactory"
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java
index ec18186..f3adec0 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java
@@ -408,21 +408,21 @@
private void assertBooleanKey(Bundle bundle, String key, boolean expectedValue) {
boolean value = bundle.getBoolean(key);
Log.v(TAG, "assertBooleanKey(): " + key + "=" + value);
- assertWithMessage("bundle's '%s' key")
+ assertWithMessage("bundle's '%s' key", key)
.that(value).isEqualTo(expectedValue);
}
private void assertIntKey(Bundle bundle, String key, int expectedValue) {
int value = bundle.getInt(key);
Log.v(TAG, "assertIntKey(): " + key + "=" + value);
- assertWithMessage("bundle's '%s' key")
+ assertWithMessage("bundle's '%s' key", key)
.that(value).isEqualTo(expectedValue);
}
private void assertStringKey(Bundle bundle, String key, String expectedValue) {
String value = bundle.getString(key);
Log.v(TAG, "assertStringKey(): " + key + "=" + value);
- assertWithMessage("bundle's '%s' key")
+ assertWithMessage("bundle's '%s' key", key)
.that(value).isEqualTo(expectedValue);
}
@@ -431,14 +431,14 @@
Log.v(TAG, "assertStringsKey(): " + key + "="
+ (value == null ? "null" : Arrays.toString(value)));
- assertWithMessage("bundle's '%s' key").that(value).asList()
+ assertWithMessage("bundle's '%s' key", key).that(value).asList()
.containsExactlyElementsIn(expectedValue).inOrder();
}
private Bundle getBundleKey(Bundle bundle, String key) {
Bundle value = bundle.getBundle(key);
Log.v(TAG, "getBundleKey(): " + key + "=" + value);
- assertWithMessage("bundle's '%s' key").that(value).isNotNull();
+ assertWithMessage("bundle's '%s' key", key).that(value).isNotNull();
return value;
}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/BackupTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/BackupTest.java
index a086173..f63c806 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/BackupTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/BackupTest.java
@@ -24,7 +24,6 @@
import static org.testng.Assert.assertThrows;
-import android.app.admin.DevicePolicyManager;
import android.app.backup.BackupManager;
import android.content.Context;
@@ -52,8 +51,6 @@
public static final DeviceState sDeviceState = new DeviceState();
private static final Context sContext = TestApis.context().instrumentedContext();
- private static final DevicePolicyManager sLocalDevicePolicyManager =
- sContext.getSystemService(DevicePolicyManager.class);
private static final BackupManager sLocalBackupManager = new BackupManager(sContext);
@PolicyAppliesTest(policy = Backup.class)
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/BlockUninstallTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/BlockUninstallTest.java
new file mode 100644
index 0000000..8b0b041
--- /dev/null
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/BlockUninstallTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.devicepolicy.cts;
+
+import static com.android.bedstead.metricsrecorder.truth.MetricQueryBuilderSubject.assertThat;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.app.admin.DevicePolicyManager;
+import android.stats.devicepolicy.EventId;
+
+import com.android.bedstead.harrier.BedsteadJUnit4;
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.AfterClass;
+import com.android.bedstead.harrier.annotations.BeforeClass;
+import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
+import com.android.bedstead.harrier.annotations.enterprise.CannotSetPolicyTest;
+import com.android.bedstead.harrier.annotations.enterprise.PolicyAppliesTest;
+import com.android.bedstead.harrier.annotations.enterprise.PolicyDoesNotApplyTest;
+import com.android.bedstead.harrier.policies.BlockUninstall;
+import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
+import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.testapp.TestApp;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+@RunWith(BedsteadJUnit4.class)
+public class BlockUninstallTest {
+ @ClassRule @Rule
+ public static final DeviceState sDeviceState = new DeviceState();
+
+ private static final TestApp sTestApp = sDeviceState.testApps().any();
+
+ private static final String NOT_INSTALLED_PACKAGE_NAME = "not.installed.package";
+
+ private static final DevicePolicyManager sLocalDevicePolicyManager =
+ TestApis.context().instrumentedContext().getSystemService(DevicePolicyManager.class);
+
+ @BeforeClass
+ public static void setupClass() {
+ sTestApp.install();
+ }
+
+ @AfterClass
+ public static void teardownClass() {
+ sTestApp.uninstallFromAllUsers();
+ }
+
+ @Postsubmit(reason = "new test")
+ @CannotSetPolicyTest(policy = BlockUninstall.class)
+ public void setUninstallBlocked_notAllowed_throwsException() {
+ assertThrows(SecurityException.class, () -> {
+ sDeviceState.dpc().devicePolicyManager().setUninstallBlocked(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), /* uninstallBlocked= */ true);
+ });
+ }
+
+ @Postsubmit(reason = "new test")
+ @PolicyAppliesTest(policy = BlockUninstall.class)
+ public void setUninstallBlocked_true_isUninstallBlockedIsTrue() {
+ try {
+ sDeviceState.dpc().devicePolicyManager().setUninstallBlocked(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), /* uninstallBlocked= */ true
+ );
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().isUninstallBlocked(
+ sDeviceState.dpc().componentName(), sTestApp.packageName()
+ )).isTrue();
+ assertThat(sLocalDevicePolicyManager.isUninstallBlocked(/* admin= */ null,
+ sTestApp.packageName())).isTrue();
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setUninstallBlocked(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), /* uninstallBlocked= */ false
+ );
+ }
+ }
+
+ @Postsubmit(reason = "new test")
+ @PolicyDoesNotApplyTest(policy = BlockUninstall.class)
+ public void setUninstallBlocked_true_isUninstallBlockedIsFalse() {
+ try {
+ sDeviceState.dpc().devicePolicyManager().setUninstallBlocked(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), /* uninstallBlocked= */ true
+ );
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().isUninstallBlocked(
+ sDeviceState.dpc().componentName(), sTestApp.packageName()
+ )).isTrue();
+ assertThat(sLocalDevicePolicyManager.isUninstallBlocked(/* admin= */ null,
+ sTestApp.packageName())).isFalse();
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setUninstallBlocked(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), /* uninstallBlocked= */ false
+ );
+ }
+ }
+
+ @Postsubmit(reason = "new test")
+ @PolicyAppliesTest(policy = BlockUninstall.class)
+ public void setUninstallBlocked_false_isUninstallBlockedIsFalse() {
+ sDeviceState.dpc().devicePolicyManager().setUninstallBlocked(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), /* uninstallBlocked= */ false
+ );
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().isUninstallBlocked(
+ sDeviceState.dpc().componentName(), sTestApp.packageName()
+ )).isFalse();
+ assertThat(sLocalDevicePolicyManager.isUninstallBlocked(/* admin= */ null,
+ sTestApp.packageName())).isFalse();
+ }
+
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = BlockUninstall.class)
+ public void setUninstallBlocked_true_appIsNotInstalled_silentlyFails() {
+ sDeviceState.dpc().devicePolicyManager().setUninstallBlocked(
+ sDeviceState.dpc().componentName(),
+ NOT_INSTALLED_PACKAGE_NAME, /* uninstallBlocked= */ true
+ );
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().isUninstallBlocked(
+ sDeviceState.dpc().componentName(), NOT_INSTALLED_PACKAGE_NAME
+ )).isFalse();
+ }
+
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = BlockUninstall.class)
+ public void setUninstallBlocked_logged() {
+ try (EnterpriseMetricsRecorder metrics = EnterpriseMetricsRecorder.create()) {
+ sDeviceState.dpc().devicePolicyManager().setUninstallBlocked(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), /* uninstallBlocked= */ true
+ );
+
+ assertThat(metrics.query()
+ .whereType().isEqualTo(EventId.SET_UNINSTALL_BLOCKED_VALUE)
+ .whereAdminPackageName().isEqualTo(
+ sDeviceState.dpc().packageName())
+ .whereStrings().contains(sTestApp.packageName())
+ .whereStrings().size().isEqualTo(1)
+ .whereBoolean().isEqualTo(sDeviceState.dpc().isDelegate())
+ ).wasLogged();
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setUninstallBlocked(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), /* uninstallBlocked= */ false
+ );
+ }
+ }
+}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileAppsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileAppsTest.java
index 6eb98c0..4998a6e 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileAppsTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileAppsTest.java
@@ -477,6 +477,94 @@
@Test
@RequireRunOnPrimaryUser
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ @EnsureHasPermission(START_CROSS_PROFILE_ACTIVITIES)
+ @Postsubmit(reason = "new test")
+ public void startMainActivity_byComponent_nullActivity_newTask() throws Exception {
+ int originalTaskId = ActivityContext.getWithContext(activity -> {
+ sCrossProfileApps.startMainActivity(
+ MAIN_ACTIVITY,
+ sDeviceState.workProfile().userHandle(),
+ /* callingActivity */ null,
+ /* options */ null);
+
+ return activity.getTaskId();
+ });
+
+ ActivityCreatedEvent event =
+ ActivityEvents.forActivity(MAIN_ACTIVITY, sDeviceState.workProfile())
+ .activityCreated().waitForEvent();
+ assertThat(event.taskId()).isNotEqualTo(originalTaskId);
+ }
+
+ @Test
+ @RequireRunOnPrimaryUser
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ @EnsureHasPermission(START_CROSS_PROFILE_ACTIVITIES)
+ @Postsubmit(reason = "new test")
+ public void startMainActivity_byComponent_setsActivity_sameTask() throws Exception {
+ int originalTaskId = ActivityContext.getWithContext(activity -> {
+ sCrossProfileApps.startMainActivity(
+ MAIN_ACTIVITY,
+ sDeviceState.workProfile().userHandle(),
+ activity,
+ /* options */ null);
+
+ return activity.getTaskId();
+ });
+
+ ActivityCreatedEvent event =
+ ActivityEvents.forActivity(MAIN_ACTIVITY, sDeviceState.workProfile())
+ .activityCreated().waitForEvent();
+ assertThat(event.taskId()).isEqualTo(originalTaskId);
+ }
+
+ @Test
+ @RequireRunOnPrimaryUser
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ @EnsureHasPermission(START_CROSS_PROFILE_ACTIVITIES)
+ @Postsubmit(reason = "new test")
+ public void startNonMainActivity_byComponent_nullActivity_newTask() throws Exception {
+ int originalTaskId = ActivityContext.getWithContext(activity -> {
+ sCrossProfileApps.startActivity(
+ NOT_MAIN_ACTIVITY,
+ sDeviceState.workProfile().userHandle(),
+ /* callingActivity */ null,
+ /* options */ null);
+
+ return activity.getTaskId();
+ });
+
+ ActivityCreatedEvent event =
+ ActivityEvents.forActivity(NOT_MAIN_ACTIVITY, sDeviceState.workProfile())
+ .activityCreated().waitForEvent();
+ assertThat(event.taskId()).isNotEqualTo(originalTaskId);
+ }
+
+ @Test
+ @RequireRunOnPrimaryUser
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
+ @EnsureHasPermission(START_CROSS_PROFILE_ACTIVITIES)
+ @Postsubmit(reason = "new test")
+ public void startNonMainActivity_byComponent_setsActivity_sameTask() throws Exception {
+ int originalTaskId = ActivityContext.getWithContext(activity -> {
+ sCrossProfileApps.startActivity(
+ NOT_MAIN_ACTIVITY,
+ sDeviceState.workProfile().userHandle(),
+ activity,
+ /* options */ null);
+
+ return activity.getTaskId();
+ });
+
+ ActivityCreatedEvent event =
+ ActivityEvents.forActivity(NOT_MAIN_ACTIVITY, sDeviceState.workProfile())
+ .activityCreated().waitForEvent();
+ assertThat(event.taskId()).isEqualTo(originalTaskId);
+ }
+
+ @Test
+ @RequireRunOnPrimaryUser
+ @EnsureHasWorkProfile(installInstrumentedApp = TRUE)
@EnsureHasPermission(INTERACT_ACROSS_PROFILES)
@Postsubmit(reason = "new test")
public void startActivity_byIntent_logged() throws Exception {
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java
index d2dff2a..2c6fb57 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java
@@ -63,8 +63,6 @@
@Rule
public static final DeviceState sDeviceState = new DeviceState();
- private static final Context sContext = TestApis.context().instrumentedContext();
-
private static final TestApp sTestApp = sDeviceState.testApps().query()
.whereActivities().contains(
activity().intentFilters().contains(
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerTest.java
index 5a45a66..79151e3 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerTest.java
@@ -49,6 +49,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.time.Duration;
+
@RunWith(BedsteadJUnit4.class)
public final class DeviceOwnerTest {
@ClassRule
@@ -118,11 +120,12 @@
Poll.forValue("Active admins", dpm::getActiveAdmins)
.toMeet(i -> i == null || !i.contains(RemoteDpc.DPC_COMPONENT_NAME))
.errorOnFail("Expected active admins to not contain RemoteDPC")
+ .timeout(Duration.ofMinutes(5))
.await();
}
}
- @UserTest({UserType.PRIMARY_USER, UserType.SECONDARY_USER, UserType.WORK_PROFILE})
+ @UserTest({UserType.PRIMARY_USER, UserType.SECONDARY_USER})
@EnsureHasDeviceOwner
@EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
@Postsubmit(reason = "new test")
@@ -131,7 +134,7 @@
.isEqualTo(sDeviceState.dpc().packageName());
}
- @UserTest({UserType.PRIMARY_USER, UserType.SECONDARY_USER, UserType.WORK_PROFILE})
+ @UserTest({UserType.PRIMARY_USER, UserType.SECONDARY_USER})
@EnsureHasDeviceOwner
@EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
@Postsubmit(reason = "new test")
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
index 4c9b3a1..657c61c 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.PROVISION_DEMO_DEVICE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME;
@@ -63,6 +64,7 @@
import android.os.PersistableBundle;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
@@ -110,6 +112,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@@ -139,8 +142,6 @@
private static final String ACCOUNT_TYPE = "com.android.cts.test";
private static final Account TEST_ACCOUNT = new Account(ACCOUNT_NAME, ACCOUNT_TYPE);
- private static final String USER_SETUP_COMPLETE_KEY = "user_setup_complete";
-
private static final String KEY_PRE_PROVISIONING_SYSTEM_APPS = "pre_provisioning_system_apps";
private static final String KEY_PRE_PROVISIONING_NON_SYSTEM_APPS =
"pre_provisioning_non_system_apps";
@@ -686,6 +687,123 @@
}
}
+ @Postsubmit(reason = "New test")
+ @RequireRunOnPrimaryUser
+ @EnsureHasNoDpc
+ @RequireFeature(FEATURE_DEVICE_ADMIN)
+ @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ @Test
+ public void newlyProvisionedFullyManagedDevice_setsDeviceAsDemoDeviceWhenRequested()
+ throws Exception {
+ boolean setupComplete = TestApis.users().current().getSetupComplete();
+ TestApis.users().current().setSetupComplete(false);
+ // TODO(b/222499341): replace with annotations
+ int demoDevice = TestApis.settings().global().getInt(Settings.Global.DEVICE_DEMO_MODE, 0);
+ TestApis.settings().global().putInt(Settings.Global.DEVICE_DEMO_MODE, 0);
+ try {
+ FullyManagedDeviceProvisioningParams params =
+ createDefaultManagedDeviceProvisioningParamsBuilder()
+ .setDemoDevice(true)
+ .build();
+ sDevicePolicyManager.provisionFullyManagedDevice(params);
+
+ assertThat(TestApis.settings().global().getInt(Settings.Global.DEVICE_DEMO_MODE, 0))
+ .isEqualTo(1);
+ } finally {
+ TestApis.users().current().setSetupComplete(setupComplete);
+ TestApis.settings().global().putInt(Settings.Global.DEVICE_DEMO_MODE, demoDevice);
+ }
+ }
+
+ @Postsubmit(reason = "New test")
+ @RequireRunOnPrimaryUser
+ @EnsureHasNoDpc
+ @RequireFeature(FEATURE_DEVICE_ADMIN)
+ @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ @Test
+ public void newlyProvisionedFullyManagedDevice_setsProvisioningStateWhenDemoDeviceIsRequested()
+ throws Exception {
+ boolean setupComplete = TestApis.users().current().getSetupComplete();
+ TestApis.users().current().setSetupComplete(false);
+ // TODO(b/222499341): replace with annotations
+ int demoDevice = TestApis.settings().global().getInt(Settings.Global.DEVICE_DEMO_MODE, 0);
+ try {
+ FullyManagedDeviceProvisioningParams params =
+ createDefaultManagedDeviceProvisioningParamsBuilder()
+ .setDemoDevice(true)
+ .build();
+ sDevicePolicyManager.provisionFullyManagedDevice(params);
+
+ assertThat(sDevicePolicyManager.getUserProvisioningState())
+ .isEqualTo(DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
+ } finally {
+ TestApis.users().current().setSetupComplete(setupComplete);
+ TestApis.settings().global().putInt(Settings.Global.DEVICE_DEMO_MODE, demoDevice);
+ }
+ }
+
+ @Postsubmit(reason = "New test")
+ @RequireRunOnPrimaryUser
+ @EnsureHasNoDpc
+ @RequireFeature(FEATURE_DEVICE_ADMIN)
+ @EnsureHasPermission(PROVISION_DEMO_DEVICE)
+ @EnsureDoesNotHavePermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ @Test
+ public void newlyProvisionedFullyManagedDevice_withProvisionDemoDevicePermission_throwsSecurityException()
+ throws Exception {
+ FullyManagedDeviceProvisioningParams params =
+ createDefaultManagedDeviceProvisioningParamsBuilder()
+ .build();
+
+ assertThrows(SecurityException.class, () ->
+ sDevicePolicyManager.provisionFullyManagedDevice(params));
+ }
+
+ @Postsubmit(reason = "New test")
+ @RequireRunOnPrimaryUser
+ @EnsureHasNoDpc
+ @RequireFeature(FEATURE_DEVICE_ADMIN)
+ @EnsureHasPermission(PROVISION_DEMO_DEVICE)
+ @EnsureDoesNotHavePermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ @Test
+ public void newlyProvisionedFullyManagedDevice_withProvisionDemoDevicePermissionForDemoDevice_doesNotThrowException()
+ throws Exception {
+ boolean setupComplete = TestApis.users().current().getSetupComplete();
+ TestApis.users().current().setSetupComplete(false);
+ // TODO(b/222499341): replace with annotations
+ int demoDevice = TestApis.settings().global().getInt(Settings.Global.DEVICE_DEMO_MODE, 0);
+ try {
+ FullyManagedDeviceProvisioningParams params =
+ createDefaultManagedDeviceProvisioningParamsBuilder()
+ .setDemoDevice(true)
+ .build();
+
+ sDevicePolicyManager.provisionFullyManagedDevice(params);
+
+ } finally {
+ TestApis.users().current().setSetupComplete(setupComplete);
+ TestApis.settings().global().putInt(Settings.Global.DEVICE_DEMO_MODE, demoDevice);
+ }
+ }
+
+ @Postsubmit(reason = "New test")
+ @RequireRunOnPrimaryUser
+ @EnsureHasNoDpc
+ @RequireFeature(FEATURE_DEVICE_ADMIN)
+ @EnsureDoesNotHavePermission({
+ PROVISION_DEMO_DEVICE,
+ MANAGE_PROFILE_AND_DEVICE_OWNERS})
+ @Test
+ public void newlyProvisionedFullyManagedDevice_withoutRequiredPermissionsForDemoDevice_throwsSecurityException()
+ throws Exception {
+ FullyManagedDeviceProvisioningParams params =
+ createDefaultManagedDeviceProvisioningParamsBuilder()
+ .setDemoDevice(true)
+ .build();
+
+ assertThrows(SecurityException.class, () ->
+ sDevicePolicyManager.provisionFullyManagedDevice(params));
+ }
@RequireDoesNotHaveFeature(PackageManager.FEATURE_AUTOMOTIVE)
@EnsureHasPermission(MANAGE_DEVICE_ADMINS)
@@ -703,13 +821,13 @@
(new PreferentialNetworkServiceConfig.Builder())
.setEnabled(true).build();
assertThrows(SecurityException.class,
- () -> sDevicePolicyManager.setPreferentialNetworkServiceConfig(
- preferentialNetworkServiceConfigEnabled));
+ () -> sDevicePolicyManager.setPreferentialNetworkServiceConfigs(
+ List.of(preferentialNetworkServiceConfigEnabled)));
assertThrows(SecurityException.class,
- () -> sDevicePolicyManager.setPreferentialNetworkServiceConfig(
- PreferentialNetworkServiceConfig.DEFAULT));
+ () -> sDevicePolicyManager.setPreferentialNetworkServiceConfigs(
+ List.of(PreferentialNetworkServiceConfig.DEFAULT)));
assertThrows(SecurityException.class,
- () -> sDevicePolicyManager.getPreferentialNetworkServiceConfig());
+ () -> sDevicePolicyManager.getPreferentialNetworkServiceConfigs());
}
@Test
@@ -718,12 +836,12 @@
PreferentialNetworkServiceConfig preferentialNetworkServiceConfigEnabled =
(new PreferentialNetworkServiceConfig.Builder())
.setEnabled(true).build();
- sDevicePolicyManager.setPreferentialNetworkServiceConfig(
- preferentialNetworkServiceConfigEnabled);
- assertTrue(sDevicePolicyManager.getPreferentialNetworkServiceConfig().isEnabled());
- sDevicePolicyManager.setPreferentialNetworkServiceConfig(
- PreferentialNetworkServiceConfig.DEFAULT);
- assertFalse(sDevicePolicyManager.getPreferentialNetworkServiceConfig().isEnabled());
+ sDevicePolicyManager.setPreferentialNetworkServiceConfigs(
+ List.of(preferentialNetworkServiceConfigEnabled));
+ assertTrue(sDevicePolicyManager.getPreferentialNetworkServiceConfigs().get(0).isEnabled());
+ sDevicePolicyManager.setPreferentialNetworkServiceConfigs(
+ List.of(PreferentialNetworkServiceConfig.DEFAULT));
+ assertFalse(sDevicePolicyManager.getPreferentialNetworkServiceConfigs().get(0).isEnabled());
sDevicePolicyManager.clearProfileOwner(DEVICE_ADMIN_COMPONENT_NAME);
SystemUtil.runShellCommand(REMOVE_ACTIVE_ADMIN_COMMAND);
}
@@ -1339,19 +1457,6 @@
TestApis.users().current().userHandle()));
}
- @Postsubmit(reason = "New test")
- @Test
- @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
- @EnsureHasDeviceOwner
- public void setUserProvisioningState_unmanagedDevice_stateUserUnmanaged_doesNotThrowIllegalStateException() {
- sDevicePolicyManager.setUserProvisioningState(
- DevicePolicyManager.STATE_USER_PROFILE_FINALIZED,
- TestApis.users().current().userHandle());
-
- assertThat(sDevicePolicyManager.getUserProvisioningState())
- .isEqualTo(DevicePolicyManager.STATE_USER_PROFILE_FINALIZED);
- }
-
@Test
public void setAdminExtras_managedProfileParams_works() {
ManagedProfileProvisioningParams params =
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
index b985584..00cffc3 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
@@ -35,6 +35,7 @@
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.Postsubmit;
import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
+import com.android.bedstead.harrier.annotations.enterprise.CannotSetPolicyTest;
import com.android.bedstead.harrier.annotations.enterprise.PolicyAppliesTest;
import com.android.bedstead.harrier.policies.KeyManagement;
import com.android.bedstead.nene.TestApis;
@@ -74,7 +75,7 @@
@ClassRule
@Rule
public static final DeviceState sDeviceState = new DeviceState();
- private static final int KEYCHAIN_CALLBACK_TIMEOUT_SECONDS = 600;
+ private static final int KEYCHAIN_CALLBACK_TIMEOUT_SECONDS = 540;
private static final String RSA = "RSA";
private static final String RSA_ALIAS = "com.android.test.valid-rsa-key-1";
private static final PrivateKey PRIVATE_KEY =
@@ -220,6 +221,14 @@
}
}
+
+ @Postsubmit(reason = "new test")
+ @CannotSetPolicyTest(policy = KeyManagement.class)
+ public void hasKeyPair_notAllowed_throwsException() {
+ assertThrows(SecurityException.class, () ->
+ sDeviceState.dpc().devicePolicyManager().hasKeyPair(RSA_ALIAS));
+ }
+
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = KeyManagement.class)
public void hasKeyPair_nonExistentAlias_false() {
@@ -345,6 +354,14 @@
}
@Postsubmit(reason = "new test")
+ @CannotSetPolicyTest(policy = KeyManagement.class)
+ public void getKeyPairGrants_notAllowed_throwsException() {
+ Assert.assertThrows(SecurityException.class,
+ () -> sDeviceState.dpc().devicePolicyManager()
+ .getKeyPairGrants(RSA_ALIAS));
+ }
+
+ @Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = KeyManagement.class, singleTestOnly = true)
public void getKeyPairGrants_nonExistent_throwsIllegalArgumentException() {
Assert.assertThrows(IllegalArgumentException.class,
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/LauncherAppsTests.java b/tests/devicepolicy/src/android/devicepolicy/cts/LauncherAppsTests.java
index a7dfc6f..865d80f 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/LauncherAppsTests.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/LauncherAppsTests.java
@@ -37,7 +37,7 @@
private final LauncherApps sLauncherApps = sContext.getSystemService(LauncherApps.class);
@Test
- public void testResolveInvalidActivity_doesNotCrash() {
+ public void resolveActivity_invalid_doesNotCrash() {
final Intent intent = new Intent();
intent.setComponent(new ComponentName("invalidPackage", "invalidClass"));
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.java
index 3aa148e..23e4b35 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.java
@@ -1000,8 +1000,8 @@
activity.activity().startActivity(intent);
if (TestApis.activities().foregroundActivity() != null) {
- assertThat(TestApis.activities().foregroundActivity().pkg()).isNotEqualTo(
- emergencyDialerPackageName);
+ assertThat(TestApis.activities().foregroundActivity().pkg().packageName())
+ .isNotEqualTo(emergencyDialerPackageName);
}
} finally {
activity.stopLockTask();
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/LostModeLocationTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/LostModeLocationTest.java
index 975fa1a..f63cc59 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/LostModeLocationTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/LostModeLocationTest.java
@@ -94,14 +94,14 @@
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = LostMode.class)
- @Ignore("b/216487148")
+ @Ignore("b/223148704")
public void sendLostModeLocationUpdate_noTestProviders_returnFalse() throws Exception {
sendLostModeLocationUpdate(/* expected= */ false);
}
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = LostMode.class)
- @Ignore("b/216487148")
+ @Ignore("b/223148704")
public void sendLostModeLocationUpdate_noLocation_returnFalse() throws Exception {
try (LocationProvider provider = TestApis.location().addLocationProvider()) {
sendLostModeLocationUpdate(/* expected */ false);
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/NegativeCallAuthorizationTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/NegativeCallAuthorizationTest.java
deleted file mode 100644
index d3b7087..0000000
--- a/tests/devicepolicy/src/android/devicepolicy/cts/NegativeCallAuthorizationTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.devicepolicy.cts;
-
-import static org.testng.Assert.assertThrows;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.Context;
-import android.content.pm.PackageManager;
-
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.filters.SmallTest;
-
-import com.android.bedstead.harrier.BedsteadJUnit4;
-import com.android.bedstead.harrier.DeviceState;
-import com.android.bedstead.harrier.annotations.RequireFeature;
-
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test that certain DevicePolicyManager APIs aren't available to non-owner apps and that they throw
- * SecurityException when invoked by such apps. For most of the older APIs that accept an explicit
- * ComponentName admin argument, this is tested in android.admin.cts.DevicePolicyManagerTest by
- * passing an admin that is not owner, but for newer APIs authorization is done based on caller UID,
- * so it is critical that the app is not owner. These APIs are tested here.
- */
-@SmallTest
-@RunWith(BedsteadJUnit4.class)
-public final class NegativeCallAuthorizationTest {
- private static final String ALIAS = "some-alias";
- private static final Context sContext = ApplicationProvider.getApplicationContext();
- private static final DevicePolicyManager sDpm =
- sContext.getSystemService(DevicePolicyManager.class);
-
- @ClassRule @Rule
- public static final DeviceState sDeviceState = new DeviceState();
-
- @Test
- @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
- public void testHasKeyPair_failIfNotOwner() {
- assertThrows(SecurityException.class, () -> sDpm.hasKeyPair(ALIAS));
- }
-
- @Test
- @RequireFeature(PackageManager.FEATURE_DEVICE_ADMIN)
- public void testGetKeyPairGrants_failIfNotOwner() {
- assertThrows(SecurityException.class, () -> sDpm.getKeyPairGrants(ALIAS));
- }
-}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/NetworkLoggingTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/NetworkLoggingTest.java
new file mode 100644
index 0000000..0dbc45c
--- /dev/null
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/NetworkLoggingTest.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.devicepolicy.cts;
+
+import static com.android.bedstead.nene.permissions.CommonPermissions.INTERNET;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.stats.devicepolicy.EventId;
+
+import com.android.bedstead.harrier.BedsteadJUnit4;
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.EnsureHasNoSecondaryUser;
+import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
+import com.android.bedstead.harrier.annotations.enterprise.CannotSetPolicyTest;
+import com.android.bedstead.harrier.annotations.enterprise.PolicyAppliesTest;
+import com.android.bedstead.harrier.policies.NetworkLogging;
+import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
+import com.android.bedstead.metricsrecorder.truth.MetricQueryBuilderSubject;
+import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.permissions.PermissionContext;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+// These tests currently only cover checking that the appropriate methods are callable. They should
+// be replaced with more complete tests once the other network logging tests are ready to be
+// migrated to the new infrastructure
+@RunWith(BedsteadJUnit4.class)
+public final class NetworkLoggingTest {
+
+ @ClassRule @Rule
+ public static final DeviceState sDeviceState = new DeviceState();
+
+ private static final String[] URL_LIST = {
+ "example.edu",
+ "google.co.jp",
+ "google.fr",
+ "google.com.br",
+ "google.com.tr",
+ "google.co.uk",
+ "google.de"
+ };
+
+ @Postsubmit(reason = "new test")
+ @CannotSetPolicyTest(policy = NetworkLogging.class)
+ public void isNetworkLoggingEnabled_notAllowed_throwsException() {
+ assertThrows(SecurityException.class, () -> sDeviceState.dpc().devicePolicyManager()
+ .isNetworkLoggingEnabled(sDeviceState.dpc().componentName()));
+ }
+
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = NetworkLogging.class)
+ @EnsureHasNoSecondaryUser
+ public void isNetworkLoggingEnabled_networkLoggingIsEnabled_returnsTrue() throws Exception {
+ try {
+ sDeviceState.dpc().devicePolicyManager().setNetworkLoggingEnabled(
+ sDeviceState.dpc().componentName(), true);
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().isNetworkLoggingEnabled(
+ sDeviceState.dpc().componentName())).isTrue();
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setNetworkLoggingEnabled(
+ sDeviceState.dpc().componentName(), false);
+ }
+ }
+
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = NetworkLogging.class)
+ public void isNetworkLoggingEnabled_networkLoggingIsNotEnabled_returnsFalse() throws Exception {
+ sDeviceState.dpc().devicePolicyManager().setNetworkLoggingEnabled(
+ sDeviceState.dpc().componentName(), false);
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().isNetworkLoggingEnabled(
+ sDeviceState.dpc().componentName())).isFalse();
+ }
+
+ @Postsubmit(reason = "new test")
+ @PolicyAppliesTest(policy = NetworkLogging.class)
+ public void setNetworkLoggingEnabled_networkLoggingIsEnabled() throws Exception {
+ try {
+ sDeviceState.dpc().devicePolicyManager().setNetworkLoggingEnabled(
+ sDeviceState.dpc().componentName(), true);
+ for (String url : URL_LIST) {
+ connectToWebsite(url);
+ }
+
+ TestApis.devicePolicy().forceNetworkLogs();
+
+ long batchToken = waitForBatchToken();
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().retrieveNetworkLogs(
+ sDeviceState.dpc().componentName(), batchToken)).isNotEmpty();
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setNetworkLoggingEnabled(
+ sDeviceState.dpc().componentName(), false);
+ }
+ }
+
+ private long waitForBatchToken() {
+ if (sDeviceState.dpc().isDelegate()) {
+ return sDeviceState.dpc().events().delegateNetworkLogsAvailable()
+ .waitForEvent().batchToken();
+ } else {
+ return sDeviceState.dpc().events().networkLogsAvailable().waitForEvent().batchToken();
+ }
+ }
+
+ private void connectToWebsite(String server) throws Exception {
+ try (PermissionContext p = TestApis.permissions().withPermission(INTERNET)) {
+ final URL url = new URL("http://" + server);
+ HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
+ try {
+ urlConnection.setConnectTimeout(2000);
+ urlConnection.setReadTimeout(2000);
+ urlConnection.getResponseCode();
+ } finally {
+ urlConnection.disconnect();
+ }
+ }
+ }
+
+ @Postsubmit(reason = "new test")
+ @CannotSetPolicyTest(policy = NetworkLogging.class)
+ public void setNetworkLoggingEnabled_notAllowed_throwsException() {
+ assertThrows(SecurityException.class, () -> sDeviceState.dpc().devicePolicyManager()
+ .setNetworkLoggingEnabled(sDeviceState.dpc().componentName(), true));
+ }
+
+ @Postsubmit(reason = "new test")
+ @CannotSetPolicyTest(policy = NetworkLogging.class)
+ public void retrieveNetworkLogs_notAllowed_throwsException() {
+ assertThrows(SecurityException.class, () -> sDeviceState.dpc().devicePolicyManager()
+ .retrieveNetworkLogs(sDeviceState.dpc().componentName(), /*batchToken= */ 0));
+ }
+
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = NetworkLogging.class)
+ public void setNetworkLoggingEnabled_true_logsEvent() {
+ try (EnterpriseMetricsRecorder metrics = EnterpriseMetricsRecorder.create()) {
+ sDeviceState.dpc().devicePolicyManager().setNetworkLoggingEnabled(
+ sDeviceState.dpc().componentName(), true);
+
+ MetricQueryBuilderSubject.assertThat(metrics.query()
+ .whereType().isEqualTo(EventId.SET_NETWORK_LOGGING_ENABLED_VALUE)
+ .whereAdminPackageName().isEqualTo(
+ sDeviceState.dpc().packageName())
+ .whereBoolean().isEqualTo(sDeviceState.dpc().isDelegate())
+ .whereInteger().isEqualTo(1) // Enabled
+ ).wasLogged();
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setNetworkLoggingEnabled(
+ sDeviceState.dpc().componentName(), false);
+ }
+ }
+
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = NetworkLogging.class)
+ public void setNetworkLoggingEnabled_false_logsEvent() {
+ sDeviceState.dpc().devicePolicyManager().setNetworkLoggingEnabled(
+ sDeviceState.dpc().componentName(), true);
+
+ try (EnterpriseMetricsRecorder metrics = EnterpriseMetricsRecorder.create()) {
+ sDeviceState.dpc().devicePolicyManager().setNetworkLoggingEnabled(
+ sDeviceState.dpc().componentName(), false);
+
+ MetricQueryBuilderSubject.assertThat(metrics.query()
+ .whereType().isEqualTo(EventId.SET_NETWORK_LOGGING_ENABLED_VALUE)
+ .whereAdminPackageName().isEqualTo(
+ sDeviceState.dpc().packageName())
+ .whereBoolean().isEqualTo(sDeviceState.dpc().isDelegate())
+ .whereInteger().isEqualTo(0) // Disabled
+ ).wasLogged();
+ }
+ }
+
+ @Postsubmit(reason = "new test")
+ @CanSetPolicyTest(policy = NetworkLogging.class)
+ public void retrieveNetworkLogs_logsEvent() throws Exception {
+ try (EnterpriseMetricsRecorder metrics = EnterpriseMetricsRecorder.create()) {
+ sDeviceState.dpc().devicePolicyManager().setNetworkLoggingEnabled(
+ sDeviceState.dpc().componentName(), true);
+ for (String url : URL_LIST) {
+ connectToWebsite(url);
+ }
+ TestApis.devicePolicy().forceNetworkLogs();
+ long batchToken = waitForBatchToken();
+
+ sDeviceState.dpc().devicePolicyManager().retrieveNetworkLogs(
+ sDeviceState.dpc().componentName(), batchToken);
+
+ MetricQueryBuilderSubject.assertThat(metrics.query()
+ .whereType().isEqualTo(EventId.RETRIEVE_NETWORK_LOGS_VALUE)
+ .whereAdminPackageName().isEqualTo(
+ sDeviceState.dpc().packageName())
+ .whereBoolean().isEqualTo(sDeviceState.dpc().isDelegate())
+ ).wasLogged();
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setNetworkLoggingEnabled(
+ sDeviceState.dpc().componentName(), false);
+ }
+ }
+}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/PackagesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/PackagesTest.java
new file mode 100644
index 0000000..63063c8
--- /dev/null
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/PackagesTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.devicepolicy.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import com.android.bedstead.harrier.BedsteadJUnit4;
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.AfterClass;
+import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
+import com.android.bedstead.harrier.annotations.enterprise.CannotSetPolicyTest;
+import com.android.bedstead.harrier.policies.HideApplication;
+import com.android.bedstead.harrier.policies.SuspendPackage;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppInstance;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+@RunWith(BedsteadJUnit4.class)
+public final class PackagesTest {
+
+ @ClassRule @Rule
+ public static final DeviceState sDeviceState = new DeviceState();
+
+ private static final TestApp sTestApp = sDeviceState.testApps().any();
+ private static final TestAppInstance sTestAppInstance = sTestApp.install();
+
+ @AfterClass
+ public static void teardownClass() {
+ sTestAppInstance.uninstall();
+ }
+
+ @CanSetPolicyTest(policy = HideApplication.class)
+ @Postsubmit(reason = "new test")
+ public void isApplicationHidden_applicationIsHidden_returnsTrue() {
+ try {
+ sDeviceState.dpc().devicePolicyManager().setApplicationHidden(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(), true);
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().isApplicationHidden(
+ sDeviceState.dpc().componentName(), sTestApp.packageName())).isTrue();
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationHidden(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(), false);
+ }
+ }
+
+ @CanSetPolicyTest(policy = HideApplication.class)
+ @Postsubmit(reason = "new test")
+ public void isApplicationHidden_applicationIsNotHidden_returnsFalse() {
+ sDeviceState.dpc().devicePolicyManager().setApplicationHidden(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(), false);
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().isApplicationHidden(
+ sDeviceState.dpc().componentName(), sTestApp.packageName())).isFalse();
+ }
+
+ @CannotSetPolicyTest(policy = HideApplication.class)
+ @Postsubmit(reason = "new test")
+ public void isApplicationHidden_notAllowed_throwsException() {
+ assertThrows(SecurityException.class, () ->
+ sDeviceState.dpc().devicePolicyManager()
+ .isApplicationHidden(
+ sDeviceState.dpc().componentName(), sTestApp.packageName()));
+ }
+
+ @CannotSetPolicyTest(policy = HideApplication.class)
+ @Postsubmit(reason = "new test")
+ public void setApplicationHidden_notAllowed_throwsException() {
+ assertThrows(SecurityException.class, () ->
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationHidden(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(), true));
+ }
+
+ @CanSetPolicyTest(policy = SuspendPackage.class)
+ @Postsubmit(reason = "new test")
+ public void isPackageSuspended_packageIsSuspended_returnsTrue() throws Exception {
+ try {
+ sDeviceState.dpc().devicePolicyManager().setPackagesSuspended(
+ sDeviceState.dpc().componentName(), new String[]{sTestApp.packageName()}, true);
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().isPackageSuspended(
+ sDeviceState.dpc().componentName(), sTestApp.packageName())).isTrue();
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setPackagesSuspended(
+ sDeviceState.dpc().componentName(), new String[]{sTestApp.packageName()},
+ false);
+ }
+ }
+
+ @CanSetPolicyTest(policy = SuspendPackage.class)
+ @Postsubmit(reason = "new test")
+ public void isPackageSuspended_packageIsNotSuspended_returnFalse() throws Exception {
+ sDeviceState.dpc().devicePolicyManager().setPackagesSuspended(
+ sDeviceState.dpc().componentName(), new String[]{sTestApp.packageName()}, false);
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().isPackageSuspended(
+ sDeviceState.dpc().componentName(), sTestApp.packageName())).isFalse();
+ }
+
+ @CannotSetPolicyTest(policy = SuspendPackage.class)
+ @Postsubmit(reason = "new test")
+ public void isPackageSuspended_notAllowed_throwsException() {
+ assertThrows(SecurityException.class, () ->
+ sDeviceState.dpc().devicePolicyManager()
+ .isPackageSuspended(
+ sDeviceState.dpc().componentName(), sTestApp.packageName()));
+ }
+
+ @CannotSetPolicyTest(policy = SuspendPackage.class)
+ @Postsubmit(reason = "new test")
+ public void setPackageSuspended_notAllowed_throwsException() {
+ assertThrows(SecurityException.class, () ->
+ sDeviceState.dpc().devicePolicyManager()
+ .setPackagesSuspended(
+ sDeviceState.dpc().componentName(),
+ new String[]{sTestApp.packageName()}, true));
+ }
+}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
index 522c317..6e23366 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
@@ -29,9 +29,13 @@
import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT;
import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED;
import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED;
+import static android.app.admin.DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY;
+import static android.app.admin.DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT;
+import static android.app.admin.DevicePolicyManager.PERMISSION_POLICY_PROMPT;
import static com.android.bedstead.nene.notifications.NotificationListenerQuerySubject.assertThat;
+import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.testng.Assert.assertThrows;
@@ -39,7 +43,7 @@
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.AfterClass;
-import com.android.bedstead.harrier.annotations.BeforeClass;
+import com.android.bedstead.harrier.annotations.IntTestParameter;
import com.android.bedstead.harrier.annotations.NotificationsTest;
import com.android.bedstead.harrier.annotations.StringTestParameter;
import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
@@ -51,7 +55,9 @@
import com.android.bedstead.harrier.policies.SetSmsPermissionGranted;
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.notifications.NotificationListener;
+import com.android.bedstead.nene.utils.Poll;
import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppActivity;
import com.android.bedstead.testapp.TestAppInstance;
import org.junit.ClassRule;
@@ -131,12 +137,11 @@
).wherePermissions().doesNotContain(
NOT_DECLARED_PERMISSION
).get();
- private static TestAppInstance sTestAppInstance;
-
- @BeforeClass
- public static void setupClass() {
- sTestAppInstance = sTestApp.install(TestApis.users().instrumented());
- }
+ private static final TestApp sNotInstalledTestApp = sDeviceState.testApps().query()
+ .wherePermissions().contains(GRANTABLE_PERMISSION)
+ .whereActivities().isNotEmpty().get();
+ private static TestAppInstance sTestAppInstance =
+ sTestApp.install(TestApis.users().instrumented());
@AfterClass
public static void teardownClass() {
@@ -331,6 +336,14 @@
}
}
+ @CannotSetPolicyTest(policy = SetPermissionGrantState.class)
+ public void grantPermission_cannotBeSet_throwsException(
+ @DeniablePermissionTestParameter String permission) {
+ assertThrows(SecurityException.class, () -> sDeviceState.dpc().devicePolicyManager()
+ .setPermissionGrantState(sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ permission, PERMISSION_GRANT_STATE_GRANTED));
+ }
+
// TODO(b/204041462): Add test that the user can manually grant sensor permissions
@CanSetPolicyTest(policy = SetPermissionGrantState.class)
@@ -503,6 +516,8 @@
int existingGrantState = sDeviceState.dpc().devicePolicyManager()
.getPermissionGrantState(sDeviceState.dpc().componentName(),
sTestApp.packageName(), READ_SMS);
+ sTestApp.pkg().denyPermission(READ_SMS);
+
try {
sDeviceState.dpc().devicePolicyManager().setPermissionGrantState(
sDeviceState.dpc().componentName(), sTestApp.packageName(),
@@ -597,6 +612,81 @@
}
}
+ @CannotSetPolicyTest(policy = SetPermissionGrantState.class)
+ public void getPermissionGrantState_notAllowed_throwsException() {
+ assertThrows(SecurityException.class, () -> {
+ sDeviceState.dpc().devicePolicyManager().getPermissionGrantState(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ GRANTABLE_PERMISSION);
+ });
+ }
+
+ @CannotSetPolicyTest(policy = SetPermissionGrantState.class)
+ public void setPermissionPolicy_notAllowed_throwsException() {
+ assertThrows(SecurityException.class, () -> {
+ sDeviceState.dpc().devicePolicyManager().setPermissionPolicy(
+ sDeviceState.dpc().componentName(), PERMISSION_POLICY_AUTO_GRANT);
+ });
+ }
+
+ @CanSetPolicyTest(policy = SetPermissionGrantState.class)
+ public void setPermissionPolicy_setsPolicy(@IntTestParameter(
+ {PERMISSION_POLICY_AUTO_GRANT, PERMISSION_POLICY_AUTO_DENY}) int policy) {
+ try {
+ sDeviceState.dpc().devicePolicyManager().setPermissionPolicy(
+ sDeviceState.dpc().componentName(), policy);
+
+ assertThat(sDeviceState.dpc().devicePolicyManager().getPermissionPolicy(
+ sDeviceState.dpc().componentName())).isEqualTo(policy);
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setPermissionPolicy(
+ sDeviceState.dpc().componentName(), PERMISSION_POLICY_PROMPT);
+ }
+ }
+
+ @PolicyAppliesTest(policy = SetPermissionGrantState.class)
+ public void setPermissionPolicy_grant_automaticallyGrantsPermissions() {
+ try (TestAppInstance testApp = sNotInstalledTestApp.install()) {
+ // We install fresh so the permissions are not granted
+ sDeviceState.dpc().devicePolicyManager().setPermissionPolicy(
+ sDeviceState.dpc().componentName(), PERMISSION_POLICY_AUTO_GRANT);
+
+ TestAppActivity activity = testApp.activities().any().start().activity();
+ activity.requestPermissions(new String[]{GRANTABLE_PERMISSION}, /* requestCode= */ 0);
+
+ Poll.forValue("Permission granted",
+ () -> sNotInstalledTestApp.pkg().hasPermission(GRANTABLE_PERMISSION))
+ .toBeEqualTo(true)
+ .errorOnFail()
+ .await();
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setPermissionPolicy(
+ sDeviceState.dpc().componentName(), PERMISSION_POLICY_PROMPT);
+ }
+ }
+
+ @PolicyAppliesTest(policy = SetPermissionGrantState.class)
+ public void setPermissionPolicy_deny_automaticallyDeniesPermissions() {
+ try (TestAppInstance testApp = sNotInstalledTestApp.install()) {
+ // We install fresh so the permissions are not granted
+ sDeviceState.dpc().devicePolicyManager().setPermissionPolicy(
+ sDeviceState.dpc().componentName(), PERMISSION_POLICY_AUTO_DENY);
+
+ TestAppActivity activity = testApp.activities().any().start().activity();
+ activity.requestPermissions(new String[]{GRANTABLE_PERMISSION}, /* requestCode= */ 0);
+
+ Poll.forValue("Permission granted",
+ () -> sNotInstalledTestApp.pkg().hasPermission(GRANTABLE_PERMISSION))
+ .toBeEqualTo(false)
+ .errorOnFail()
+ .await();
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setPermissionPolicy(
+ sDeviceState.dpc().componentName(), PERMISSION_POLICY_PROMPT);
+ }
+ }
+
+
@PolicyAppliesTest(policy = SetSensorPermissionGranted.class)
@NotificationsTest
@Ignore("TODO(198280344): Re-enable when we can set sensor permissions using device owner")
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/PermitInputMethodsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/PermitInputMethodsTest.java
index 1a0dc01..38c110e 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/PermitInputMethodsTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/PermitInputMethodsTest.java
@@ -106,9 +106,6 @@
SYSTEM_INPUT_METHODS_PACKAGES.isEmpty());
List<String> enabledNonSystemImes = List.of(INPUT_METHOD_PACKAGE_NAME);
- Set<String> permittedPlusSystem = new HashSet<>();
- permittedPlusSystem.addAll(SYSTEM_INPUT_METHODS_PACKAGES);
- permittedPlusSystem.addAll(enabledNonSystemImes);
assertThat(sDeviceState.dpc().devicePolicyManager().setPermittedInputMethods(
sDeviceState.dpc().componentName(), /* packageNames= */ enabledNonSystemImes)
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/ResetPasswordWithTokenTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/ResetPasswordWithTokenTest.java
index 44abc72..a3847f1 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/ResetPasswordWithTokenTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/ResetPasswordWithTokenTest.java
@@ -55,7 +55,6 @@
import org.junit.ClassRule;
import org.junit.Rule;
-import org.junit.Test;
import org.junit.runner.RunWith;
// TODO(b/191640667): Parameterize the length limit tests with multiple limits
@@ -92,7 +91,6 @@
@Rule
public static final DeviceState sDeviceState = new DeviceState();
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
public void setResetPasswordToken_validToken_passwordTokenSet() {
@@ -107,7 +105,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = ResetPasswordWithToken.class)
public void resetPasswordWithToken_validPasswordAndToken_success() {
@@ -120,7 +117,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = ResetPasswordWithToken.class)
public void resetPasswordWithToken_badToken_failure() {
@@ -129,7 +125,6 @@
DPC_COMPONENT_NAME, VALID_PASSWORD, BAD_TOKEN, /* flags = */ 0)).isFalse();
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
public void resetPasswordWithToken_noPassword_deviceIsNotSecure() {
@@ -141,7 +136,6 @@
assertThat(sLocalKeyguardManager.isDeviceSecure()).isFalse();
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
public void resetPasswordWithToken_password_deviceIsSecure() {
@@ -157,7 +151,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -185,7 +178,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -214,7 +206,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = ResetPasswordWithToken.class)
public void resetPasswordWithToken_validPasswordAndToken_logged() {
@@ -232,7 +223,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -262,7 +252,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -292,7 +281,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -324,7 +312,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -342,7 +329,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -364,7 +350,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -385,7 +370,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -405,7 +389,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -425,7 +408,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -452,7 +434,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = ResetPasswordWithToken.class)
// setPasswordMinimumLength is unsupported on automotive
@@ -471,7 +452,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -498,7 +478,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
// setPasswordMinimumUpperCase is unsupported on automotive
@RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
@@ -517,7 +496,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -544,7 +522,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
// setPasswordMinimumLowerCase is unsupported on automotive
@RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
@@ -563,7 +540,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -590,7 +566,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = ResetPasswordWithToken.class)
public void setPasswordMinimumLetters_success() {
@@ -607,7 +582,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -634,7 +608,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = ResetPasswordWithToken.class)
public void setPasswordMinimumNumeric_success() {
@@ -651,7 +624,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -678,7 +650,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = ResetPasswordWithToken.class)
public void setPasswordMinimumSymbols_success() {
@@ -695,7 +666,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -723,7 +693,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
// setPasswordMinimumNonLetter is unsupported on automotive
@RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
@@ -742,7 +711,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -770,7 +738,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -792,7 +759,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
// setPasswordQuality is unsupported on automotive
@@ -814,7 +780,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = ResetPasswordWithToken.class)
public void setRequiredPasswordComplexity_success() {
@@ -830,7 +795,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
public void setRequiredPasswordComplexity_low_passwordThatMeetsLowPasswordBandRequired() {
@@ -847,7 +811,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
public void setRequiredPasswordComplexity_medium_passwordThatMeetsMediumPasswordBandRequired() {
@@ -865,7 +828,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
public void setRequiredPasswordComplexity_high_passwordThatMeetsHighPasswordBandRequired() {
@@ -883,7 +845,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
public void getPasswordComplexity_passwordThatMeetsLowPasswordBand_lowPasswordComplexity() {
@@ -899,7 +860,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
public void getPasswordComplexity_passwordThatMeetsMediumPasswordBand_mediumPasswordComplexity() {
@@ -915,7 +875,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
public void getPasswordComplexity_passwordThatMeetsHighPasswordBand_highPasswordComplexity() {
@@ -931,7 +890,6 @@
}
}
- @Test
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
public void clearResetPasswordToken_passwordTokenIsResetAndUnableToSetNewPassword() {
@@ -948,11 +906,10 @@
}
}
- @Test
@RequireFeature(FEATURE_AUTOMOTIVE)
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
@Postsubmit(reason = "new test")
- public void testPasswordMinimumLength_featureUnsupported_ignored() {
+ public void passwordMinimumLength_featureUnsupported_ignored() {
int valueBefore = sDeviceState.dpc().devicePolicyManager().getPasswordMinimumLength(
DPC_COMPONENT_NAME);
@@ -964,11 +921,10 @@
.isEqualTo(valueBefore);
}
- @Test
@RequireFeature(FEATURE_AUTOMOTIVE)
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
@Postsubmit(reason = "new test")
- public void testPasswordMinimumNumeric_ignored() {
+ public void passwordMinimumNumeric_ignored() {
int valueBefore = sDeviceState.dpc().devicePolicyManager().getPasswordMinimumNumeric(
DPC_COMPONENT_NAME);
@@ -980,11 +936,10 @@
.isEqualTo(valueBefore);
}
- @Test
@RequireFeature(FEATURE_AUTOMOTIVE)
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
@Postsubmit(reason = "new test")
- public void testPasswordMinimumLowerCase_ignored() {
+ public void passwordMinimumLowerCase_ignored() {
int valueBefore = sDeviceState.dpc().devicePolicyManager().getPasswordMinimumLowerCase(
DPC_COMPONENT_NAME);
@@ -997,11 +952,10 @@
.isEqualTo(valueBefore);
}
- @Test
@RequireFeature(FEATURE_AUTOMOTIVE)
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
@Postsubmit(reason = "new test")
- public void testPasswordMinimumUpperCase_ignored() {
+ public void passwordMinimumUpperCase_ignored() {
int valueBefore = sDeviceState.dpc().devicePolicyManager().getPasswordMinimumUpperCase(
DPC_COMPONENT_NAME);
@@ -1014,11 +968,10 @@
.isEqualTo(valueBefore);
}
- @Test
@RequireFeature(FEATURE_AUTOMOTIVE)
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
@Postsubmit(reason = "new test")
- public void testPasswordMinimumLetters_ignored() {
+ public void passwordMinimumLetters_ignored() {
int valueBefore = sDeviceState.dpc().devicePolicyManager().getPasswordMinimumLetters(
DPC_COMPONENT_NAME);
@@ -1030,11 +983,10 @@
.isEqualTo(valueBefore);
}
- @Test
@RequireFeature(FEATURE_AUTOMOTIVE)
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
@Postsubmit(reason = "new test")
- public void testPasswordMinimumSymbols_ignored() {
+ public void passwordMinimumSymbols_ignored() {
int valueBefore = sDeviceState.dpc().devicePolicyManager().getPasswordMinimumSymbols(
DPC_COMPONENT_NAME);
@@ -1046,11 +998,10 @@
.isEqualTo(valueBefore);
}
- @Test
@RequireFeature(FEATURE_AUTOMOTIVE)
@PolicyAppliesTest(policy = ResetPasswordWithToken.class)
@Postsubmit(reason = "new test")
- public void testPasswordMinimumNonLetter_ignored() {
+ public void passwordMinimumNonLetter_ignored() {
int valueBefore = sDeviceState.dpc().devicePolicyManager().getPasswordMinimumNonLetter(
DPC_COMPONENT_NAME);
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/RingtoneTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/RingtoneTest.java
index 1fb1685..a8ad777 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/RingtoneTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/RingtoneTest.java
@@ -48,8 +48,8 @@
NOTIFICATION(Settings.System.NOTIFICATION_SOUND, RingtoneManager.TYPE_NOTIFICATION),
ALARM(Settings.System.ALARM_ALERT, RingtoneManager.TYPE_ALARM);
- String mRingtoneName;
- int mType;
+ final String mRingtoneName;
+ final int mType;
RingtoneConfig(String ringtoneName, int type) {
this.mRingtoneName = ringtoneName;
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java
index 42ebd7f..17f90a4 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java
@@ -82,7 +82,7 @@
public void setShortSupportMessage_validText_works() {
mDevicePolicyManager.setShortSupportMessage(mAdmin, VALID_SUPPORT_MESSAGE);
- assertThat(mDevicePolicyManager.getShortSupportMessage(mAdmin))
+ assertThat(mDevicePolicyManager.getShortSupportMessage(mAdmin).toString())
.isEqualTo(VALID_SUPPORT_MESSAGE);
}
@@ -91,7 +91,7 @@
public void setLongSupportMessage_validText_works() {
mDevicePolicyManager.setLongSupportMessage(mAdmin, VALID_SUPPORT_MESSAGE);
- assertThat(mDevicePolicyManager.getLongSupportMessage(mAdmin))
+ assertThat(mDevicePolicyManager.getLongSupportMessage(mAdmin).toString())
.isEqualTo(VALID_SUPPORT_MESSAGE);
}
@@ -100,7 +100,7 @@
public void setShortSupportMessage_emptyText_works() {
mDevicePolicyManager.setShortSupportMessage(mAdmin, EMPTY_SUPPORT_MESSAGE);
- assertThat(mDevicePolicyManager.getShortSupportMessage(mAdmin))
+ assertThat(mDevicePolicyManager.getShortSupportMessage(mAdmin).toString())
.isEqualTo(EMPTY_SUPPORT_MESSAGE);
}
@@ -110,7 +110,7 @@
mDevicePolicyManager.setLongSupportMessage(mAdmin, VALID_SUPPORT_MESSAGE);
mDevicePolicyManager.setLongSupportMessage(mAdmin, /* charSequence= */ null);
- assertThat(mDevicePolicyManager.getLongSupportMessage(mAdmin)).isEqualTo("null");
+ assertThat(mDevicePolicyManager.getLongSupportMessage(mAdmin).toString()).isEqualTo("null");
}
@PolicyAppliesTest(policy = SupportMessage.class)
@@ -119,7 +119,8 @@
mDevicePolicyManager.setShortSupportMessage(mAdmin, VALID_SUPPORT_MESSAGE);
mDevicePolicyManager.setShortSupportMessage(mAdmin, /* charSequence= */ null);
- assertThat(mDevicePolicyManager.getShortSupportMessage(mAdmin)).isEqualTo("null");
+ assertThat(mDevicePolicyManager.getShortSupportMessage(mAdmin).toString())
+ .isEqualTo("null");
}
@PolicyAppliesTest(policy = SupportMessage.class)
@@ -127,7 +128,7 @@
public void setLongSupportMessage_emptyText_works() {
mDevicePolicyManager.setLongSupportMessage(mAdmin, EMPTY_SUPPORT_MESSAGE);
- assertThat(mDevicePolicyManager.getLongSupportMessage(mAdmin))
+ assertThat(mDevicePolicyManager.getLongSupportMessage(mAdmin).toString())
.isEqualTo(EMPTY_SUPPORT_MESSAGE);
}
@@ -136,7 +137,7 @@
public void setShortSupportMessage_tooLongText_isTruncated() {
mDevicePolicyManager.setShortSupportMessage(mAdmin, SHORT_SUPPORT_MESSAGE_TOO_LONG);
- assertThat(mDevicePolicyManager.getShortSupportMessage(mAdmin))
+ assertThat(mDevicePolicyManager.getShortSupportMessage(mAdmin).toString())
.isEqualTo(SHORT_SUPPORT_MESSAGE_TOO_LONG_TRUNCATED);
}
@@ -145,7 +146,7 @@
public void setLongSupportMessage_longText_notTruncated() {
mDevicePolicyManager.setShortSupportMessage(mAdmin, LONG_SUPPORT_MESSAGE_REASONABLY_LONG);
- assertThat(mDevicePolicyManager.getShortSupportMessage(mAdmin))
+ assertThat(mDevicePolicyManager.getShortSupportMessage(mAdmin).toString())
.isEqualTo(LONG_SUPPORT_MESSAGE_REASONABLY_LONG);
}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/SystemAppTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/SystemAppTest.java
new file mode 100644
index 0000000..3b9ecc0
--- /dev/null
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/SystemAppTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.devicepolicy.cts;
+
+import static org.testng.Assert.assertThrows;
+
+import com.android.bedstead.harrier.BedsteadJUnit4;
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.AfterClass;
+import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
+import com.android.bedstead.harrier.annotations.enterprise.CannotSetPolicyTest;
+import com.android.bedstead.harrier.policies.EnableSystemApp;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppInstance;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+@RunWith(BedsteadJUnit4.class)
+public final class SystemAppTest {
+
+ @ClassRule @Rule
+ public static final DeviceState sDeviceState = new DeviceState();
+
+ private static final TestApp sTestApp = sDeviceState.testApps().any();
+ private static final TestAppInstance sTestAppInstance = sTestApp.install();
+
+ @AfterClass
+ public static void teardownClass() {
+ sTestAppInstance.uninstall();
+ }
+
+ @CanSetPolicyTest(policy = EnableSystemApp.class)
+ @Postsubmit(reason = "new test")
+ public void enableSystemApp_nonSystemApp_throwsException() {
+ assertThrows(IllegalArgumentException.class,
+ () -> sDeviceState.dpc().devicePolicyManager().enableSystemApp(
+ sDeviceState.dpc().componentName(), sTestApp.packageName()));
+ }
+
+ @CannotSetPolicyTest(policy = EnableSystemApp.class)
+ @Postsubmit(reason = "new test")
+ public void enableSystemApp_notAllowed_throwsException() {
+ assertThrows(SecurityException.class,
+ () -> sDeviceState.dpc().devicePolicyManager().enableSystemApp(
+ sDeviceState.dpc().componentName(), sTestApp.packageName()));
+ }
+}
diff --git a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricSimpleTests.java b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricSimpleTests.java
index 716db8d..d07c3ce 100644
--- a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricSimpleTests.java
+++ b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricSimpleTests.java
@@ -174,15 +174,31 @@
// Third case above. Since the deprecated API is intended to allow credential in addition
// to biometrics, we should be receiving BIOMETRIC_ERROR_NO_BIOMETRICS.
final boolean noSensors = mSensorProperties.isEmpty();
+ int expectedError;
+ if (noSensors) {
+ expectedError = BiometricPrompt.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL;
+ } else if (hasOnlyConvenienceSensors()) {
+ expectedError = BiometricPrompt.BIOMETRIC_ERROR_HW_NOT_PRESENT;
+ } else {
+ expectedError = BiometricPrompt.BIOMETRIC_ERROR_NO_BIOMETRICS;
+ }
callback = mock(BiometricPrompt.AuthenticationCallback.class);
showDeviceCredentialAllowedBiometricPrompt(callback, new CancellationSignal(),
false /* shouldShow */);
verify(callback).onAuthenticationError(
- eq(noSensors ? BiometricPrompt.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL
- : BiometricPrompt.BIOMETRIC_ERROR_NO_BIOMETRICS),
+ eq(expectedError),
any());
}
+ private boolean hasOnlyConvenienceSensors() {
+ for (SensorProperties sensor : mSensorProperties) {
+ if (sensor.getSensorStrength() != SensorProperties.STRENGTH_CONVENIENCE) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* When device credential is enrolled, check the behavior for
* 1) BiometricManager#canAuthenticate(DEVICE_CREDENTIAL)
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index 9eb7bac..91be9196 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -538,6 +538,10 @@
android:exported="true"/>
<activity android:name="android.server.wm.PinnedStackTests$TestActivity"
android:exported="true"/>
+ <activity android:name="android.server.wm.TaskFragmentTrustedModeTest$TranslucentActivity"
+ android:exported="true"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar" />
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
index d8c804f..59194c6 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
@@ -18,50 +18,33 @@
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.server.wm.jetpack.utils.ExtensionUtil.MINIMUM_EXTENSION_VERSION;
import static android.server.wm.jetpack.utils.ExtensionUtil.assertEqualWindowLayoutInfo;
import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
import static android.server.wm.jetpack.utils.ExtensionUtil.assumeHasDisplayFeatures;
import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowLayoutComponent;
import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowLayoutInfo;
-import static android.server.wm.jetpack.utils.ExtensionUtil.getWindowExtensions;
-import static android.server.wm.jetpack.utils.ExtensionUtil.isExtensionVersionValid;
import static android.server.wm.jetpack.utils.SidecarUtil.assumeSidecarSupportedDevice;
import static android.server.wm.jetpack.utils.SidecarUtil.getSidecarInterface;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.areExtensionAndSidecarDeviceStateEqual;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.assertNotBothDimensionsZero;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.assertHasNonNegativeDimensions;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.doesDisplayRotateForOrientation;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityBounds;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityWindowToken;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getMaximumActivityBounds;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.setActivityOrientationActivityDoesNotHandleOrientationChanges;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.setActivityOrientationActivityHandlesOrientationChanges;
+
+import static androidx.window.extensions.layout.FoldingFeature.STATE_FLAT;
+import static androidx.window.extensions.layout.FoldingFeature.STATE_HALF_OPENED;
+import static androidx.window.extensions.layout.FoldingFeature.TYPE_FOLD;
+import static androidx.window.extensions.layout.FoldingFeature.TYPE_HINGE;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeNotNull;
-import static org.junit.Assume.assumeTrue;
-import static androidx.window.extensions.layout.FoldingFeature.TYPE_FOLD;
-import static androidx.window.extensions.layout.FoldingFeature.TYPE_HINGE;
-import static androidx.window.extensions.layout.FoldingFeature.STATE_FLAT;
-import static androidx.window.extensions.layout.FoldingFeature.STATE_HALF_OPENED;
-
-import android.app.Activity;
import android.graphics.Rect;
-import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
+import android.platform.test.annotations.Presubmit;
import android.server.wm.jetpack.utils.TestActivity;
import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
import android.server.wm.jetpack.utils.TestValueCountConsumer;
-import android.platform.test.annotations.Presubmit;
+import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
-import androidx.annotation.NonNull;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.window.extensions.layout.DisplayFeature;
@@ -78,7 +61,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.Collections;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
@@ -111,6 +93,41 @@
assumeNotNull(mWindowLayoutComponent);
}
+ /**
+ * Test adding and removing a window layout change listener.
+ */
+ @Test
+ public void testWindowLayoutComponent_onWindowLayoutChangeListener() throws Exception {
+ // Set activity to portrait
+ setActivityOrientationActivityDoesNotHandleOrientationChanges(mActivity,
+ ORIENTATION_PORTRAIT);
+
+ // Create the callback, onWindowLayoutChanged should only be called twice in this
+ // test, not the third time when the orientation will change because the listener will be
+ // removed.
+ TestValueCountConsumer<WindowLayoutInfo> windowLayoutInfoConsumer =
+ new TestValueCountConsumer<>();
+ windowLayoutInfoConsumer.setCount(2);
+
+ // Add window layout listener for mWindowToken - onWindowLayoutChanged should be called
+ mWindowLayoutComponent.addWindowLayoutInfoListener(mActivity, windowLayoutInfoConsumer);
+
+ // Change the activity orientation - onWindowLayoutChanged should be called
+ setActivityOrientationActivityDoesNotHandleOrientationChanges(mActivity,
+ ORIENTATION_LANDSCAPE);
+
+ // Remove the listener
+ mWindowLayoutComponent.removeWindowLayoutInfoListener(windowLayoutInfoConsumer);
+
+ // Change the activity orientation - onWindowLayoutChanged should NOT be called
+ setActivityOrientationActivityDoesNotHandleOrientationChanges(mActivity,
+ ORIENTATION_PORTRAIT);
+
+ // Check that the countdown is zero
+ WindowLayoutInfo lastValue = windowLayoutInfoConsumer.waitAndGet();
+ assertNotNull(lastValue);
+ }
+
@Test
public void testWindowLayoutComponent_WindowLayoutInfoListener() {
TestValueCountConsumer<WindowLayoutInfo> windowLayoutInfoConsumer =
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/KeepClearRectsTests.java b/tests/framework/base/windowmanager/src/android/server/wm/KeepClearRectsTests.java
index 3cd15d8..0fda662 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/KeepClearRectsTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/KeepClearRectsTests.java
@@ -38,6 +38,7 @@
import android.server.wm.cts.R;
import android.view.Gravity;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.RelativeLayout;
@@ -45,6 +46,8 @@
import androidx.test.filters.FlakyTest;
+import com.android.compatibility.common.util.PollingCheck;
+
import org.junit.Before;
import org.junit.Test;
@@ -56,6 +59,7 @@
@Presubmit
@FlakyTest(detail = "Promote once confirmed non-flaky")
public class KeepClearRectsTests extends WindowManagerTestBase {
+ private static final long FOCUS_VIEW_CHECK_TIMEOUT = 3000;
private static final List<Rect> TEST_KEEP_CLEAR_RECTS =
Arrays.asList(new Rect(0, 0, 25, 25),
new Rect(30, 0, 50, 25),
@@ -319,6 +323,38 @@
}
@Test
+ public void testFocusedViewDeclaredAsKeepClearArea() throws Exception {
+ int preferKeepClearForFocusDelay = ViewConfiguration.get(
+ mContext).getPreferKeepClearForFocusDelay();
+
+ assumeTrue(preferKeepClearForFocusDelay >= 0);
+
+ mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
+ final TestActivity activity = mTestSession.getActivity();
+
+ final Rect viewBounds = new Rect(0, 0, 60, 60);
+ final View v = createTestViewInActivity(activity, viewBounds);
+ assertSameElements(EMPTY_LIST, getKeepClearRectsForActivity(activity));
+
+ mTestSession.runOnMainSyncAndWait(() -> {
+ v.setFocusable(true);
+ v.requestFocus();
+ });
+
+ PollingCheck.check("Expected focused view bounds as keep clear area",
+ preferKeepClearForFocusDelay + FOCUS_VIEW_CHECK_TIMEOUT,
+ () -> hasSameElements(
+ getRectsInScreenSpace(Arrays.asList(viewBounds),
+ activity.getComponentName()),
+ getKeepClearRectsForActivity(activity)));
+
+ mTestSession.runOnMainSyncAndWait(() -> v.setFocusable(false));
+ PollingCheck.check("Expected no keep clear areas after clearing focus, but found some",
+ preferKeepClearForFocusDelay + FOCUS_VIEW_CHECK_TIMEOUT,
+ () -> hasSameElements(EMPTY_LIST, getKeepClearRectsForActivity(activity)));
+ }
+
+ @Test
public void testKeepClearRectsGetTranslatedToWindowSpace() {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity = mTestSession.getActivity();
@@ -353,12 +389,14 @@
v.setPreferKeepClear(false);
v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS);
});
- assertSameElements(getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS, componentName),
+ List<Rect> expectedRectsInScreenSpace =
+ getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS, componentName);
+ assertSameElements(expectedRectsInScreenSpace,
getKeepClearRectsForActivity(activity));
activity.finishAndRemoveTask();
assertTrue(Collections.disjoint(
- getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS, componentName),
+ expectedRectsInScreenSpace,
getKeepClearRectsOnDefaultDisplay()));
}
@@ -374,7 +412,7 @@
assertSameElements(getRectsInScreenSpace(Arrays.asList(viewBounds), componentName),
getKeepClearRectsForActivity(activity));
- final String title = "KeepCleasrRectsTestWindow";
+ final String title = "KeepClearRectsTestWindow";
mTestSession.runOnMainSyncAndWait(() -> {
final View testView = new View(activity);
testView.setPreferKeepClear(true);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
index ca205fd..defe2de 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
@@ -334,13 +334,13 @@
extraString(EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR, Integer.toString(2)),
extraString(EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR, Integer.toString(1)),
extraString(EXTRA_EXPANDED_PIP_ASPECT_RATIO_NUMERATOR, Integer.toString(1)),
- extraString(EXTRA_EXPANDED_PIP_ASPECT_RATIO_DENOMINATOR, Integer.toString(5)));
+ extraString(EXTRA_EXPANDED_PIP_ASPECT_RATIO_DENOMINATOR, Integer.toString(4)));
// Wait for animation complete since we are comparing aspect ratio
waitForEnterPipAnimationComplete(PIP_ACTIVITY);
assertPinnedStackExists();
// Assert that we have entered PIP and that the aspect ratio is correct
final Rect bounds = getPinnedStackBounds();
- assertFloatEquals((float) bounds.width() / bounds.height(), (float) 1.0f / 5.0f);
+ assertFloatEquals((float) bounds.width() / bounds.height(), (float) 1.0f / 4.0f);
}
@Test
@@ -515,16 +515,16 @@
}
@Test
- public void testPreferDockBigOverlaysWithExpandedPip() {
- testPreferDockBigOverlaysWithExpandedPip(true);
+ public void testShouldDockBigOverlaysWithExpandedPip() {
+ testShouldDockBigOverlaysWithExpandedPip(true);
}
@Test
- public void testNotPreferDockBigOverlaysWithExpandedPip() {
- testPreferDockBigOverlaysWithExpandedPip(false);
+ public void testShouldNotDockBigOverlaysWithExpandedPip() {
+ testShouldDockBigOverlaysWithExpandedPip(false);
}
- private void testPreferDockBigOverlaysWithExpandedPip(boolean preferDock) {
+ private void testShouldDockBigOverlaysWithExpandedPip(boolean shouldDock) {
assumeTrue(supportsExpandedPip());
TestActivitySession<TestActivity> testSession = createManagedTestActivitySession();
final Intent intent = new Intent(mContext, TestActivity.class);
@@ -541,7 +541,7 @@
waitForEnterPipAnimationComplete(PIP_ACTIVITY);
assertPinnedStackExists();
- testSession.runOnMainSyncAndWait(() -> activity.setPreferDockBigOverlays(preferDock));
+ testSession.runOnMainSyncAndWait(() -> activity.setShouldDockBigOverlays(shouldDock));
mWmState.assertResumedActivity("Activity must be resumed", activity.getComponentName());
assertPinnedStackExists();
@@ -549,8 +549,15 @@
final Task task = mWmState.getTaskByActivity(activity.getComponentName());
final TaskInfo info = mTaskOrganizer.getTaskInfo(task.getTaskId());
- assertEquals(preferDock, info.getPreferDockBigOverlays());
+ assertEquals(shouldDock, info.shouldDockBigOverlays());
});
+
+ final boolean[] actual = new boolean[] {!shouldDock};
+ testSession.runOnMainSyncAndWait(() -> {
+ actual[0] = activity.shouldDockBigOverlays();
+ });
+
+ assertEquals(shouldDock, actual[0]);
}
@Test
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java
index 4cf56b9..35beba0 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java
@@ -23,13 +23,11 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.Intent.ACTION_MAIN;
-import static android.content.Intent.CATEGORY_HOME;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.server.wm.CliIntentExtra.extraBool;
import static android.server.wm.CliIntentExtra.extraString;
import static android.server.wm.WindowManagerState.STATE_RESUMED;
import static android.server.wm.app.Components.HANDLE_SPLASH_SCREEN_EXIT_ACTIVITY;
-import static android.server.wm.app.Components.HOME_ACTIVITY;
import static android.server.wm.app.Components.SPLASHSCREEN_ACTIVITY;
import static android.server.wm.app.Components.SPLASH_SCREEN_REPLACE_ICON_ACTIVITY;
import static android.server.wm.app.Components.SPLASH_SCREEN_REPLACE_THEME_ACTIVITY;
@@ -128,21 +126,15 @@
mWmState.setSanityCheckWithFocusedWindow(true);
}
- private CommandSession.ActivitySession prepareTestLauncher() {
- createManagedHomeActivitySession(HOME_ACTIVITY);
+ /**
+ * @return The starter activity session to start the test activity
+ */
+ private CommandSession.ActivitySession prepareTestStarter() {
return createManagedActivityClientSession()
- .startActivity(new Intent(ACTION_MAIN)
- .addCategory(CATEGORY_HOME)
- .addFlags(FLAG_ACTIVITY_NEW_TASK)
- .setComponent(HOME_ACTIVITY));
+ .startActivity(getLaunchActivityBuilder().setUseInstrumentation());
}
- private void startActivityFromTestLauncher(CommandSession.ActivitySession homeActivity,
- ComponentName componentName, Consumer<Intent> fillExtra) {
- startActivityFromTestLauncher(homeActivity, componentName, fillExtra, null /* options */);
- }
-
- private void startActivitiesFromTestLauncher(CommandSession.ActivitySession homeActivity,
+ private void startActivitiesFromStarter(CommandSession.ActivitySession starter,
Intent[] intents, ActivityOptions options) {
final Bundle data = new Bundle();
@@ -150,10 +142,10 @@
if (options != null) {
data.putParcelable(EXTRA_OPTION, options.toBundle());
}
- homeActivity.sendCommand(COMMAND_START_ACTIVITIES, data);
+ starter.sendCommand(COMMAND_START_ACTIVITIES, data);
}
- private void startActivityFromTestLauncher(CommandSession.ActivitySession homeActivity,
+ private void startActivityFromStarter(CommandSession.ActivitySession starter,
ComponentName componentName, Consumer<Intent> fillExtra, ActivityOptions options) {
final Bundle data = new Bundle();
@@ -165,7 +157,7 @@
if (options != null) {
data.putParcelable(EXTRA_OPTION, options.toBundle());
}
- homeActivity.sendCommand(COMMAND_START_ACTIVITY, data);
+ starter.sendCommand(COMMAND_START_ACTIVITY, data);
}
@Test
@@ -174,7 +166,14 @@
// applied insets by system bars in AAOS.
assumeFalse(isCar());
- launchActivityNoWait(SPLASHSCREEN_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
+ final CommandSession.ActivitySession starter = prepareTestStarter();
+ final ActivityOptions noIconOptions = ActivityOptions.makeBasic()
+ .setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR);
+ noIconOptions.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ // launch from app with no-icon options
+ startActivityFromStarter(starter, SPLASHSCREEN_ACTIVITY,
+ intent -> {}, noIconOptions);
// The windowSplashScreenContent attribute is set to RED. We check that it is ignored.
testSplashScreenColor(SPLASHSCREEN_ACTIVITY, Color.BLUE, Color.WHITE);
}
@@ -186,7 +185,13 @@
assumeFalse(isCar());
assumeTrue(supportsFreeform());
- launchActivityNoWait(SPLASHSCREEN_ACTIVITY, WINDOWING_MODE_FREEFORM);
+ final CommandSession.ActivitySession starter = prepareTestStarter();
+ final ActivityOptions noIconOptions = ActivityOptions.makeBasic()
+ .setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR);
+ noIconOptions.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+ // launch from app with no-icon options
+ startActivityFromStarter(starter, SPLASHSCREEN_ACTIVITY,
+ intent -> {}, noIconOptions);
// The windowSplashScreenContent attribute is set to RED. We check that it is ignored.
testSplashScreenColor(SPLASHSCREEN_ACTIVITY, Color.BLUE, Color.WHITE);
}
@@ -373,12 +378,11 @@
private void launchRuntimeHandleExitAnimationActivity(boolean extraOnCreate,
boolean extraOnResume, boolean extraCancel, boolean expectResult) throws Exception {
TestJournalProvider.TestJournalContainer.start();
- final CommandSession.ActivitySession homeActivity = prepareTestLauncher();
- startActivityFromTestLauncher(homeActivity, HANDLE_SPLASH_SCREEN_EXIT_ACTIVITY, intent -> {
- intent.putExtra(REQUEST_HANDLE_EXIT_ON_CREATE, extraOnCreate);
- intent.putExtra(REQUEST_HANDLE_EXIT_ON_RESUME, extraOnResume);
- intent.putExtra(CANCEL_HANDLE_EXIT, extraCancel);
- });
+
+ launchActivityNoWait(HANDLE_SPLASH_SCREEN_EXIT_ACTIVITY,
+ extraBool(REQUEST_HANDLE_EXIT_ON_CREATE, extraOnCreate),
+ extraBool(REQUEST_HANDLE_EXIT_ON_RESUME, extraOnResume),
+ extraBool(CANCEL_HANDLE_EXIT, extraCancel));
mWmState.computeState(HANDLE_SPLASH_SCREEN_EXIT_ACTIVITY);
mWmState.assertVisibility(HANDLE_SPLASH_SCREEN_EXIT_ACTIVITY, true);
@@ -420,8 +424,15 @@
// applied insets by system bars in AAOS.
assumeFalse(isCar());
- launchActivityNoWait(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, WINDOWING_MODE_FULLSCREEN,
- extraBool(DELAY_RESUME, true));
+ final CommandSession.ActivitySession starter = prepareTestStarter();
+ final ActivityOptions noIconOptions = ActivityOptions.makeBasic()
+ .setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR);
+ noIconOptions.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ // launch from app with no-icon options
+ startActivityFromStarter(starter, SPLASH_SCREEN_REPLACE_ICON_ACTIVITY,
+ intent -> intent.putExtra(DELAY_RESUME, true), noIconOptions);
+
testSplashScreenColor(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, Color.BLUE, Color.WHITE);
}
@@ -432,20 +443,25 @@
assumeFalse(isCar());
assumeTrue(supportsFreeform());
- launchActivityNoWait(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, WINDOWING_MODE_FREEFORM,
- extraBool(DELAY_RESUME, true));
+ final CommandSession.ActivitySession starter = prepareTestStarter();
+ final ActivityOptions noIconOptions = ActivityOptions.makeBasic()
+ .setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR);
+ noIconOptions.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+
+ // launch from app with no-icon options
+ startActivityFromStarter(starter, SPLASH_SCREEN_REPLACE_ICON_ACTIVITY,
+ intent -> intent.putExtra(DELAY_RESUME, true), noIconOptions);
+
testSplashScreenColor(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, Color.BLUE, Color.WHITE);
}
@Test
public void testHandleExitIconAnimatingActivity() throws Exception {
assumeFalse(isLeanBack());
- final CommandSession.ActivitySession homeActivity = prepareTestLauncher();
- TestJournalProvider.TestJournalContainer.start();
- startActivityFromTestLauncher(homeActivity, SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, intent -> {
- intent.putExtra(REQUEST_HANDLE_EXIT_ON_CREATE, true);
- });
+ TestJournalProvider.TestJournalContainer.start();
+ launchActivityNoWait(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY,
+ extraBool(REQUEST_HANDLE_EXIT_ON_CREATE, true));
mWmState.computeState(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY);
mWmState.assertVisibility(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, true);
@@ -456,12 +472,12 @@
@Test
public void testCancelHandleExitIconAnimatingActivity() {
assumeFalse(isLeanBack());
- final CommandSession.ActivitySession homeActivity = prepareTestLauncher();
+
TestJournalProvider.TestJournalContainer.start();
- startActivityFromTestLauncher(homeActivity, SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, intent -> {
- intent.putExtra(REQUEST_HANDLE_EXIT_ON_CREATE, true);
- intent.putExtra(CANCEL_HANDLE_EXIT, true);
- });
+ launchActivityNoWait(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY,
+ extraBool(REQUEST_HANDLE_EXIT_ON_CREATE, true),
+ extraBool(CANCEL_HANDLE_EXIT, true));
+
mWmState.waitForActivityState(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, STATE_RESUMED);
mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
@@ -511,13 +527,13 @@
}
@Test
- public void testLaunchFromLauncherWithSolidColorOptions() throws Exception {
+ public void testLaunchWithSolidColorOptions() throws Exception {
assumeFalse(isLeanBack());
- final CommandSession.ActivitySession homeActivity = prepareTestLauncher();
+ final CommandSession.ActivitySession starter = prepareTestStarter();
TestJournalProvider.TestJournalContainer.start();
final ActivityOptions noIconOptions = ActivityOptions.makeBasic()
.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR);
- startActivityFromTestLauncher(homeActivity, SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, intent ->
+ startActivityFromStarter(starter, SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, intent ->
intent.putExtra(REQUEST_HANDLE_EXIT_ON_CREATE, true), noIconOptions);
mWmState.waitForActivityState(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, STATE_RESUMED);
mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
@@ -544,13 +560,13 @@
true /* containsBranding */, false /* iconAnimatable */);
}
- private void launchActivitiesFromLauncherWithOptions(Intent[] intents,
+ private void launchActivitiesFromStarterWithOptions(Intent[] intents,
ActivityOptions options, ComponentName waitResumeComponent) {
assumeFalse(isLeanBack());
- final CommandSession.ActivitySession homeActivity = prepareTestLauncher();
+ final CommandSession.ActivitySession starter = prepareTestStarter();
TestJournalProvider.TestJournalContainer.start();
- startActivitiesFromTestLauncher(homeActivity, intents, options);
+ startActivitiesFromStarter(starter, intents, options);
mWmState.waitForActivityState(waitResumeComponent, STATE_RESUMED);
mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
@@ -566,7 +582,7 @@
new Intent().setComponent(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY)
.putExtra(REQUEST_HANDLE_EXIT_ON_CREATE, true)
};
- launchActivitiesFromLauncherWithOptions(intents, options,
+ launchActivitiesFromStarterWithOptions(intents, options,
SPLASH_SCREEN_REPLACE_ICON_ACTIVITY);
assertHandleExit(REPLACE_ICON_EXIT, true /* containsIcon */, false /* containsBranding */,
true /* iconAnimatable */);
@@ -584,7 +600,7 @@
new Intent().setComponent(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY)
.putExtra(REQUEST_HANDLE_EXIT_ON_CREATE, true)
};
- launchActivitiesFromLauncherWithOptions(intents, options,
+ launchActivitiesFromStarterWithOptions(intents, options,
SPLASH_SCREEN_REPLACE_ICON_ACTIVITY);
assertHandleExit(REPLACE_ICON_EXIT, false /* containsIcon */, false /* containsBranding */,
false /* iconAnimatable */);
@@ -621,28 +637,31 @@
@Test
public void testOverrideSplashscreenTheme() {
assumeFalse(isLeanBack());
- final CommandSession.ActivitySession homeActivity = prepareTestLauncher();
-
// Pre-launch the activity to ensure status is cleared on the device
- startActivityFromTestLauncher(homeActivity, SPLASH_SCREEN_REPLACE_THEME_ACTIVITY,
- intent -> {});
+ launchActivityNoWait(SPLASH_SCREEN_REPLACE_THEME_ACTIVITY);
+ mWmState.waitForActivityState(SPLASH_SCREEN_REPLACE_THEME_ACTIVITY, STATE_RESUMED);
+ mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
waitAndAssertOverrideThemeColor(0 /* ignore */);
// Launch the activity a first time, check that the splashscreen use the default theme,
// and override the theme for the next launch
- startActivityFromTestLauncher(homeActivity, SPLASH_SCREEN_REPLACE_THEME_ACTIVITY,
- intent -> intent.putExtra(OVERRIDE_THEME_ENABLED, true));
+ launchActivityNoWait(SPLASH_SCREEN_REPLACE_THEME_ACTIVITY,
+ extraBool(OVERRIDE_THEME_ENABLED, true));
+ mWmState.waitForActivityState(SPLASH_SCREEN_REPLACE_THEME_ACTIVITY, STATE_RESUMED);
+ mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
waitAndAssertOverrideThemeColor(Color.BLUE);
// Launch the activity a second time, check that the theme has been overridden and reset
// to the default theme
- startActivityFromTestLauncher(homeActivity, SPLASH_SCREEN_REPLACE_THEME_ACTIVITY,
- intent -> {});
+ launchActivityNoWait(SPLASH_SCREEN_REPLACE_THEME_ACTIVITY);
+ mWmState.waitForActivityState(SPLASH_SCREEN_REPLACE_THEME_ACTIVITY, STATE_RESUMED);
+ mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
waitAndAssertOverrideThemeColor(Color.RED);
// Launch the activity a third time just to check that the theme has indeed been reset.
- startActivityFromTestLauncher(homeActivity, SPLASH_SCREEN_REPLACE_THEME_ACTIVITY,
- intent -> {});
+ launchActivityNoWait(SPLASH_SCREEN_REPLACE_THEME_ACTIVITY);
+ mWmState.waitForActivityState(SPLASH_SCREEN_REPLACE_THEME_ACTIVITY, STATE_RESUMED);
+ mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
waitAndAssertOverrideThemeColor(Color.BLUE);
}
@@ -671,23 +690,25 @@
@Test
public void testDefineSplashScreenStyleFromTheme() {
assumeFalse(isLeanBack());
- final CommandSession.ActivitySession homeActivity = prepareTestLauncher();
+ final CommandSession.ActivitySession starter = prepareTestStarter();
final ActivityOptions noIconOptions = ActivityOptions.makeBasic()
.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR);
- startActivityFromTestLauncher(homeActivity, SPLASH_SCREEN_STYLE_THEME_ACTIVITY,
+ // launch from app with sold color options
+ startActivityFromStarter(starter, SPLASH_SCREEN_STYLE_THEME_ACTIVITY,
intent -> {}, noIconOptions);
waitAndAssertStyleThemeIcon(false);
- startActivityFromTestLauncher(homeActivity, SPLASH_SCREEN_STYLE_THEME_ACTIVITY,
- intent -> {});
+ // launch from app with icon options
+ final ActivityOptions iconOptions = ActivityOptions.makeBasic()
+ .setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
+ startActivityFromStarter(starter, SPLASH_SCREEN_STYLE_THEME_ACTIVITY,
+ intent -> {}, iconOptions);
waitAndAssertStyleThemeIcon(true);
- // launch from app
- final Intent intent = new Intent(Intent.ACTION_VIEW)
- .setComponent(SPLASH_SCREEN_STYLE_THEME_ACTIVITY)
- .setFlags(FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(intent);
+ // launch from app without activity options
+ startActivityFromStarter(starter, SPLASH_SCREEN_STYLE_THEME_ACTIVITY,
+ intent -> {}, null /* options */);
waitAndAssertStyleThemeIcon(true);
}
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java b/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
index 2fa3ec8..ffd7d95 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
@@ -44,7 +44,6 @@
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import org.junit.Ignore;
import org.junit.Test;
/**
@@ -60,8 +59,6 @@
*/
@Presubmit
public class SplitActivityLifecycleTest extends TaskFragmentOrganizerTestBase {
- private Activity mOwnerActivity;
- private IBinder mOwnerToken;
private final Rect mPrimaryBounds = new Rect();
private final Rect mSideBounds = new Rect();
private TaskFragmentRecord mTaskFragA;
@@ -72,13 +69,11 @@
private final Intent mIntent = new Intent().setComponent(mActivityC);
@Override
- public void setUp() throws Exception {
- super.setUp();
+ Activity setUpOwnerActivity() {
// Launch activities in fullscreen, otherwise, some tests fail on devices which use freeform
// as the default windowing mode, because tests' prerequisite are that activity A, B, and C
// need to overlay completely, but they can be partially overlay as freeform windows.
- mOwnerActivity = startActivityInWindowingModeFullScreen(ActivityA.class);
- mOwnerToken = getActivityToken(mOwnerActivity);
+ return startActivityInWindowingModeFullScreen(ActivityA.class);
}
/** Launch two Activities in two adjacent TaskFragments side-by-side. */
@@ -393,32 +388,6 @@
testActivityLaunchInExpandedTaskFragmentInternal();
}
- /**
- * Verifies the behavior to launch Activity in expanded TaskFragment and occludes the embedded
- * Task.
- * <p>
- * For example, given that Activity A and B are showed side-by-side, which Activity B is in
- * embedded Task, this test verifies the behavior to launch Activity C in the TaskFragment which
- * fills the Task bounds of owner Activity:
- * <pre class="prettyprint">
- * - Fullscreen -
- * TaskFragmentC
- * - ActivityC <---- new started Activity
- * - Left - - Right -
- * TaskFragmentA TaskFragmentB
- * - ActivityA - Embedded Task
- * - ActivityB
- * </pre></p>
- */
- @Test
- @Ignore("b/197364677")
- public void testActivityLaunchInExpandedTaskFragment_AboveEmbeddedTask() {
- // Initialize test environment by launching Activity A and B side-by-side.
- initializeSplitActivities(true /* verifyEmbeddedTask */);
-
- testActivityLaunchInExpandedTaskFragmentInternal();
- }
-
private void testActivityLaunchInExpandedTaskFragmentInternal() {
final TaskFragmentCreationParams fullScreenParamsC = mTaskFragmentOrganizer
@@ -444,91 +413,6 @@
}
/**
- * Verifies the behavior to launch Activity above the embedded Task in TaskFragment.
- * <p>
- * For example, given that Activity A and B are showed side-by-side, which Activity B is in
- * embedded Task, this test verifies the behavior to launch Activity C on top of the embedded
- * Task in the same TaskFragment as Activity B:
- * <pre class="prettyprint">
- * - Left - - Right -
- * TaskFragmentA TaskFragmentB
- * - ActivityA - ActivityC <---- new started Activity
- * - Embedded Task
- * - ActivityB
- * </pre></p>
- */
- @Test
- @Ignore("b/197364677")
- public void testActivityLaunchAboveEmbeddedTaskInTaskFragment() {
- // Initialize test environment by launching Activity A and B side-by-side.
- initializeSplitActivities(true /* verifyEmbeddedTask */);
-
- final IBinder taskFragTokenB = mTaskFragB.getTaskFragToken();
-
- WindowContainerTransaction wct = new WindowContainerTransaction()
- .startActivityInTaskFragment(taskFragTokenB, mOwnerToken, mIntent,
- null /* activityOptions */);
-
- mTaskFragmentOrganizer.applyTransaction(wct);
-
- mTaskFragmentOrganizer.waitForTaskFragmentInfoChanged();
-
- final TaskFragmentInfo infoB = mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragTokenB);
-
- assertNotEmptyTaskFragment(infoB, taskFragTokenB);
-
- waitAndAssertResumedActivity(mActivityC, "Activity C must be resumed.");
- waitAndAssertResumedActivity(mActivityA, "Activity A must be resumed.");
- waitAndAssertActivityState(mActivityB, WindowManagerState.STATE_STOPPED,
- "Activity B is occluded by Activity C, so it must be stopped.");
-
- final TaskFragment taskFragmentB = mWmState.getTaskFragmentByActivity(mActivityB);
- assertWithMessage("TaskFragmentB must contain Activity C")
- .that(taskFragmentB.mActivities).containsExactly(mWmState.getActivity(mActivityC));
- }
-
- /**
- * Verifies the behavior to launch Activity to the embedded Task in TaskFragment.
- * <p>
- * For example, given that Activity A and B are showed side-by-side, which Activity B is in
- * embedded Task, this test verifies the behavior to launch Activity C to the embedded Task
- * and on top of Activity B:
- * <pre class="prettyprint">
- * - Left - - Right -
- * TaskFragmentA TaskFragmentB
- * - ActivityA - Embedded Task
- * - ActivityC <---- new started Activity
- * - ActivityB
- * </pre></p>
- */
- @Test
- @Ignore("b/197364677")
- public void testActivityLaunchToEmbeddedTaskInTaskFragment() {
- // Initialize test environment by launching Activity A and B side-by-side.
- initializeSplitActivities(true /* verifyEmbeddedTask */);
-
- final IBinder taskFragTokenB = mTaskFragB.getTaskFragToken();
- // Make Activity C launch to the embedded Task.
- final Intent intent = new Intent(mIntent).addFlags(FLAG_ACTIVITY_NEW_TASK);
-
- WindowContainerTransaction wct = new WindowContainerTransaction()
- .startActivityInTaskFragment(taskFragTokenB, mOwnerToken, intent,
- null /* activityOptions */);
-
- mTaskFragmentOrganizer.applyTransaction(wct);
-
- waitAndAssertResumedActivity(mActivityC, "Activity C must be resumed.");
- waitAndAssertResumedActivity(mActivityA, "Activity A must be resumed.");
- waitAndAssertActivityState(mActivityB, STATE_STOPPED,
- "Activity B is occluded by Activity C, so it must be stopped.");
-
- final Task embeddedTask = mWmState.getTaskByActivity(mActivityB);
- assertWithMessage("Embedded Task must contain Activity B and Activity C")
- .that(embeddedTask.mActivities).containsExactly(mWmState.getActivity(mActivityB),
- mWmState.getActivity(mActivityC));
- }
-
- /**
* Verifies the show-when-locked behavior while launch embedded activities. Don't show the
* embedded activities even if one of Activity has showWhenLocked flag.
*/
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserTests.java b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserTests.java
index b1975db..d6728f41 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserTests.java
@@ -24,6 +24,7 @@
import static org.junit.Assume.assumeTrue;
import android.app.ActivityManager;
+import android.app.ActivityOptions;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -78,6 +79,25 @@
@Test
public void startActivityValidUser() throws Throwable {
+ verifyStartActivityAsValidUser(false /* withOptions */);
+ }
+
+ @Test
+ public void startActivityInvalidUser() {
+ verifyStartActivityAsInvalidUser(false /* withOptions */);
+ }
+
+ @Test
+ public void startActivityAsValidUserWithOptions() throws Throwable {
+ verifyStartActivityAsValidUser(true /* withOptions */);
+ }
+
+ @Test
+ public void startActivityAsInvalidUserWithOptions() {
+ verifyStartActivityAsInvalidUser(true /* withOptions */);
+ }
+
+ private void verifyStartActivityAsValidUser(boolean withOptions) throws Throwable {
int[] secondUser= {-1};
CountDownLatch latch = new CountDownLatch(1);
RemoteCallback cb = new RemoteCallback((Bundle result) -> {
@@ -102,7 +122,12 @@
try {
runWithShellPermissionIdentity(() -> {
- mContext.startActivityAsUser(intent, secondUserHandle);
+ if (withOptions) {
+ mContext.startActivityAsUser(intent, ActivityOptions.makeBasic().toBundle(),
+ secondUserHandle);
+ } else {
+ mContext.startActivityAsUser(intent, secondUserHandle);
+ }
mAm.switchUser(secondUserHandle);
try {
latch.await(5, TimeUnit.SECONDS);
@@ -120,8 +145,7 @@
returnToOriginalUserLatch.await(20, TimeUnit.SECONDS);
}
- @Test
- public void startActivityInvalidUser() {
+ private void verifyStartActivityAsInvalidUser(boolean withOptions) {
UserHandle secondUserHandle = UserHandle.of(mSecondUserId * 100);
int[] stackId = {-1};
@@ -129,7 +153,12 @@
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
runWithShellPermissionIdentity(() -> {
- mContext.startActivityAsUser(intent, secondUserHandle);
+ if (withOptions) {
+ mContext.startActivityAsUser(intent, ActivityOptions.makeBasic().toBundle(),
+ secondUserHandle);
+ } else {
+ mContext.startActivityAsUser(intent, secondUserHandle);
+ }
WindowManagerState amState = mAmWmState;
amState.computeState();
ComponentName componentName = ComponentName.createRelative(PACKAGE, CLASS);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java
index 9f8d6e0..318e6f7 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java
@@ -19,7 +19,6 @@
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.server.wm.TaskFragmentOrganizerTestBase.assertEmptyTaskFragment;
-import static android.server.wm.TaskFragmentOrganizerTestBase.assertNotEmptyTaskFragment;
import static android.server.wm.TaskFragmentOrganizerTestBase.getActivityToken;
import static android.server.wm.WindowManagerState.STATE_RESUMED;
import static android.server.wm.app.Components.LAUNCHING_ACTIVITY;
@@ -53,7 +52,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -177,16 +175,10 @@
}
/**
- * Verifies the behavior to start Activity from another process in a new created Task under
- * TaskFragment with {@link android.permission#ACTIVITY_EMBEDDING}.
- * <p>
- * If the application to start Activity holds the permission, the activity is allowed to start
- * on the Task. Otherwise, the TaskFragment should remain empty.
- * </p>
+ * Verifies the behavior to start Activity in a new created Task in TaskFragment is forbidden.
*/
@Test
- @Ignore("b/197364677")
- public void testStartActivityFromAnotherProcessInEmbeddedTask() {
+ public void testStartActivityFromAnotherProcessInNewTask_ThrowException() {
final Activity activity = startNewActivity();
final IBinder ownerToken = getActivityToken(activity);
final TaskFragmentCreationParams params = mTaskFragmentOrganizer.generateTaskFragParams(
@@ -209,29 +201,13 @@
TaskFragmentInfo info = mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken);
- // TaskFragment must remain empty because we don't hold EMBEDDING_ACTIVITY permission to
- // launch Activity in the embedded Task.
+ // TaskFragment must remain empty because embedding activities in a new task is not allowed.
assertEmptyTaskFragment(info, taskFragToken);
mTaskFragmentOrganizer.waitForTaskFragmentError();
assertThat(mTaskFragmentOrganizer.getThrowable()).isInstanceOf(SecurityException.class);
assertThat(mTaskFragmentOrganizer.getErrorCallbackToken()).isEqualTo(errorCallbackToken);
-
- final WindowContainerTransaction wctWithPermission = new WindowContainerTransaction()
- .startActivityInTaskFragment(taskFragToken, ownerToken, intent,
- null /* activityOptions */);
-
- NestedShellPermission.run(() -> mTaskFragmentOrganizer.applyTransaction(wctWithPermission),
- "android.permission.ACTIVITY_EMBEDDING");
-
- mTaskFragmentOrganizer.waitForTaskFragmentInfoChanged();
-
- info = mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken);
-
- // The new started Activity must be launched in the new created Task under the TaskFragment
- // with token taskFragToken.
- assertNotEmptyTaskFragment(info, taskFragToken);
}
/**
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java
index ced35b8..7d4d4f0 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java
@@ -17,8 +17,9 @@
package android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.server.wm.WindowManagerState.STATE_RESUMED;
+import static android.server.wm.WindowManagerState.STATE_STOPPED;
+import static android.server.wm.jetpack.second.Components.SECOND_UNTRUSTED_EMBEDDING_ACTIVITY;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -33,10 +34,8 @@
import android.os.Bundle;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
-import android.server.wm.WindowContextTests.TestActivity;
import android.server.wm.WindowManagerState.Task;
import android.server.wm.WindowManagerState.TaskFragment;
-import android.server.wm.jetpack.second.Components;
import android.view.SurfaceControl;
import android.window.TaskFragmentCreationParams;
import android.window.TaskFragmentInfo;
@@ -45,10 +44,7 @@
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import java.util.ArrayList;
@@ -62,23 +58,9 @@
*/
@Presubmit
public class TaskFragmentOrganizerTest extends TaskFragmentOrganizerTestBase {
- private Activity mOwnerActivity;
- private IBinder mOwnerToken;
- private ComponentName mOwnerActivityName;
- private int mOwnerTaskId;
private final ComponentName mLaunchingActivity = new ComponentName(mContext,
WindowMetricsActivityTests.MetricsActivity.class);
- @Before
- @Override
- public void setUp() throws Exception {
- super.setUp();
- mOwnerActivity = startActivity(TestActivity.class);
- mOwnerToken = getActivityToken(mOwnerActivity);
- mOwnerActivityName = mOwnerActivity.getComponentName();
- mOwnerTaskId = mOwnerActivity.getTaskId();
- }
-
/**
* Verifies the behavior of
* {@link WindowContainerTransaction#createTaskFragment(TaskFragmentCreationParams)} to create
@@ -140,7 +122,7 @@
assertNotEmptyTaskFragment(mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken),
taskFragToken, mOwnerToken);
- mWmState.waitForActivityState(mOwnerActivityName, WindowManagerState.STATE_RESUMED);
+ mWmState.waitForActivityState(mOwnerActivityName, STATE_RESUMED);
final Task parentTask = mWmState.getTaskByActivity(mOwnerActivityName);
final TaskFragment taskFragment = mWmState.getTaskFragmentByActivity(mOwnerActivityName);
@@ -158,7 +140,6 @@
* Bundle)} to start Activity in TaskFragment without creating new Task.
*/
@Test
- @Ignore("b/197364677")
public void testStartActivityInTaskFragment_reuseTask() {
final TaskFragmentCreationParams params = generateTaskFragCreationParams();
final IBinder taskFragToken = params.getFragmentToken();
@@ -173,7 +154,7 @@
TaskFragmentInfo info = mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken);
assertNotEmptyTaskFragment(info, taskFragToken);
- mWmState.waitForActivityState(mLaunchingActivity, WindowManagerState.STATE_RESUMED);
+ mWmState.waitForActivityState(mLaunchingActivity, STATE_RESUMED);
Task parentTask = mWmState.getRootTask(mOwnerActivity.getTaskId());
TaskFragment taskFragment = mWmState.getTaskFragmentByActivity(mLaunchingActivity);
@@ -192,47 +173,6 @@
/**
* Verifies the behavior of
- * {@link WindowContainerTransaction#startActivityInTaskFragment(IBinder, IBinder, Intent,
- * Bundle)} to start Activity on new created Task.
- */
- @Test
- @Ignore("b/197364677")
- public void testStartActivityInTaskFragment_createNewTask() {
- final TaskFragmentCreationParams params = generateTaskFragCreationParams();
- final IBinder taskFragToken = params.getFragmentToken();
- final Intent intent = new Intent()
- .setComponent(mLaunchingActivity)
- .addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK);
- final WindowContainerTransaction wct = new WindowContainerTransaction()
- .createTaskFragment(params)
- .startActivityInTaskFragment(taskFragToken, mOwnerToken, intent,
- null /* activityOptions */);
- mTaskFragmentOrganizer.applyTransaction(wct);
-
- mTaskFragmentOrganizer.waitForTaskFragmentCreated();
-
- TaskFragmentInfo info = mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken);
- assertNotEmptyTaskFragment(info, taskFragToken);
-
- mWmState.waitForActivityState(mLaunchingActivity, WindowManagerState.STATE_RESUMED);
-
- Task parentTask = mWmState.getRootTask(mOwnerActivity.getTaskId());
- TaskFragment taskFragment = mWmState.getTaskFragmentByActivity(mLaunchingActivity);
- Task childTask = mWmState.getTaskByActivity(mLaunchingActivity);
-
- // Assert window hierarchy must be as follows
- // - owner Activity's Task (parentTask)
- // - taskFragment
- // - new created Task
- // - LAUNCHING_ACTIVITY
- // - owner Activity
- assertWindowHierarchy(parentTask, taskFragment, childTask,
- mWmState.getActivity(mLaunchingActivity));
- assertWindowHierarchy(parentTask, mWmState.getActivity(mOwnerActivityName));
- }
-
- /**
- * Verifies the behavior of
* {@link WindowContainerTransaction#deleteTaskFragment(WindowContainerToken)} to remove
* the organized TaskFragment.
*/
@@ -279,7 +219,7 @@
mTaskFragmentOrganizer.applyTransaction(wct);
mTaskFragmentOrganizer.waitForTaskFragmentCreated();
// The activity below must be occluded and stopped.
- waitAndAssertActivityState(mOwnerActivityName, WindowManagerState.STATE_STOPPED,
+ waitAndAssertActivityState(mOwnerActivityName, STATE_STOPPED,
"Activity must be stopped");
// Finishing the top activity and remain the TaskFragment on top. The next top activity
@@ -310,7 +250,7 @@
@Test
public void testTaskFragmentConfigChange_disallowedUntrustedMode() {
final TaskFragmentInfo taskFragmentInfo = createTaskFragment(
- Components.SECOND_UNTRUSTED_EMBEDDING_ACTIVITY);
+ SECOND_UNTRUSTED_EMBEDDING_ACTIVITY);
List<WindowContainerTransaction> transactions = createConfigChangingTransactions(
taskFragmentInfo);
@@ -325,30 +265,6 @@
}
}
- /**
- * Builds, runs and waits for completion of task fragment creation transaction.
- * @param componentName name of the activity to launch in the TF, or {@code null} if none.
- * @return token of the created task fragment.
- */
- private TaskFragmentInfo createTaskFragment(@Nullable ComponentName componentName) {
- final TaskFragmentCreationParams params = generateTaskFragCreationParams();
- final IBinder taskFragToken = params.getFragmentToken();
- final WindowContainerTransaction wct = new WindowContainerTransaction()
- .createTaskFragment(params);
- if (componentName != null) {
- wct.startActivityInTaskFragment(taskFragToken, mOwnerToken,
- new Intent().setComponent(componentName), null /* activityOptions */);
- }
- mTaskFragmentOrganizer.applyTransaction(wct);
- mTaskFragmentOrganizer.waitForTaskFragmentCreated();
-
- if (componentName != null) {
- mWmState.waitForActivityState(componentName, WindowManagerState.STATE_RESUMED);
- }
-
- return mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken);
- }
-
private List<WindowContainerTransaction> createConfigChangingTransactions(
@NonNull TaskFragmentInfo taskFragmentInfo) {
final WindowContainerToken wct = taskFragmentInfo.getToken();
@@ -367,9 +283,4 @@
return transactionList;
}
-
- @NonNull
- private TaskFragmentCreationParams generateTaskFragCreationParams() {
- return mTaskFragmentOrganizer.generateTaskFragParams(mOwnerToken);
- }
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
index 34a16a5..6edbc9a 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
@@ -17,6 +17,7 @@
package android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.server.wm.WindowManagerState.STATE_RESUMED;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -24,10 +25,13 @@
import static org.junit.Assert.fail;
import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
+import android.server.wm.WindowContextTests.TestActivity;
import android.server.wm.WindowManagerState.WindowContainer;
import android.util.ArrayMap;
import android.window.TaskFragmentCreationParams;
@@ -48,6 +52,10 @@
public class TaskFragmentOrganizerTestBase extends WindowManagerTestBase {
public BasicTaskFragmentOrganizer mTaskFragmentOrganizer;
+ Activity mOwnerActivity;
+ IBinder mOwnerToken;
+ ComponentName mOwnerActivityName;
+ int mOwnerTaskId;
@Before
@Override
@@ -55,6 +63,17 @@
super.setUp();
mTaskFragmentOrganizer = new BasicTaskFragmentOrganizer();
mTaskFragmentOrganizer.registerOrganizer();
+ mOwnerActivity = setUpOwnerActivity();
+ mOwnerToken = getActivityToken(mOwnerActivity);
+ mOwnerActivityName = mOwnerActivity.getComponentName();
+ mOwnerTaskId = mOwnerActivity.getTaskId();
+ }
+
+ /** Setups the owner activity of the organized TaskFragment. */
+ Activity setUpOwnerActivity() {
+ // Launch activities in fullscreen in case the device may use freeform as the default
+ // windowing mode.
+ return startActivityInWindowingModeFullScreen(TestActivity.class);
}
@After
@@ -121,6 +140,50 @@
}
}
+ /**
+ * Builds, runs and waits for completion of task fragment creation transaction.
+ * @param componentName name of the activity to launch in the TF, or {@code null} if none.
+ * @return token of the created task fragment.
+ */
+ TaskFragmentInfo createTaskFragment(@Nullable ComponentName componentName) {
+ return createTaskFragment(componentName, new Rect());
+ }
+
+ /**
+ * Same as {@link #createTaskFragment(ComponentName)}, but allows to specify the bounds for the
+ * new task fragment.
+ */
+ TaskFragmentInfo createTaskFragment(@Nullable ComponentName componentName,
+ @NonNull Rect bounds) {
+ final TaskFragmentCreationParams params = generateTaskFragCreationParams(bounds);
+ final IBinder taskFragToken = params.getFragmentToken();
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .createTaskFragment(params);
+ if (componentName != null) {
+ wct.startActivityInTaskFragment(taskFragToken, mOwnerToken,
+ new Intent().setComponent(componentName), null /* activityOptions */);
+ }
+ mTaskFragmentOrganizer.applyTransaction(wct);
+ mTaskFragmentOrganizer.waitForTaskFragmentCreated();
+
+ if (componentName != null) {
+ mWmState.waitForActivityState(componentName, STATE_RESUMED);
+ }
+
+ return mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken);
+ }
+
+ @NonNull
+ TaskFragmentCreationParams generateTaskFragCreationParams() {
+ return mTaskFragmentOrganizer.generateTaskFragParams(mOwnerToken);
+ }
+
+ @NonNull
+ TaskFragmentCreationParams generateTaskFragCreationParams(@NonNull Rect bounds) {
+ return mTaskFragmentOrganizer.generateTaskFragParams(mOwnerToken, bounds,
+ WINDOWING_MODE_UNDEFINED);
+ }
+
public static class BasicTaskFragmentOrganizer extends TaskFragmentOrganizer {
private final static int WAIT_TIMEOUT_IN_SECOND = 10;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
new file mode 100644
index 0000000..d133cec
--- /dev/null
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm;
+
+import static android.server.wm.WindowManagerState.STATE_RESUMED;
+import static android.server.wm.WindowManagerState.STATE_STOPPED;
+import static android.server.wm.jetpack.second.Components.SECOND_UNTRUSTED_EMBEDDING_ACTIVITY;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.window.TaskFragmentInfo;
+import android.window.WindowContainerTransaction;
+
+import androidx.annotation.NonNull;
+
+import org.junit.Test;
+
+/**
+ * Tests that verifies the behaviors of embedding activities in different trusted modes.
+ *
+ * Build/Install/Run:
+ * atest CtsWindowManagerDeviceTestCases:TaskFragmentTrustedModeTest
+ */
+public class TaskFragmentTrustedModeTest extends TaskFragmentOrganizerTestBase {
+
+ private final ComponentName mTranslucentActivity = new ComponentName(mContext,
+ TranslucentActivity.class);
+
+ /**
+ * Verifies the visibility of a task fragment that has overlays on top of activities embedded
+ * in untrusted mode when there is an overlay over the task fragment.
+ */
+ @Test
+ public void testUntrustedModeTaskFragmentVisibility_overlayTaskFragment() {
+ // Create a task fragment with activity in untrusted mode.
+ final TaskFragmentInfo tf = createTaskFragment(SECOND_UNTRUSTED_EMBEDDING_ACTIVITY);
+
+ // Start a translucent activity over the TaskFragment.
+ createTaskFragment(mTranslucentActivity, partialOverlayBounds(tf));
+ mWmState.waitForActivityState(mTranslucentActivity, STATE_RESUMED);
+
+ // The task fragment must be made invisible when there is an overlay activity in it.
+ mWmState.waitForActivityState(SECOND_UNTRUSTED_EMBEDDING_ACTIVITY, STATE_STOPPED);
+ final String overlayMessage = "Activities embedded in untrusted mode should be made "
+ + "invisible in a task fragment with overlay";
+ assertTrue(overlayMessage, mWmState.hasActivityState(SECOND_UNTRUSTED_EMBEDDING_ACTIVITY,
+ STATE_STOPPED));
+ assertFalse(overlayMessage, mWmState.isActivityVisible(
+ SECOND_UNTRUSTED_EMBEDDING_ACTIVITY));
+ assertFalse(overlayMessage, mWmState.getTaskFragmentByActivity(
+ SECOND_UNTRUSTED_EMBEDDING_ACTIVITY).isVisible());
+ // The activity that appeared on top would stay resumed
+ assertTrue(overlayMessage, mWmState.hasActivityState(mTranslucentActivity, STATE_RESUMED));
+ assertTrue(overlayMessage, mWmState.isActivityVisible(mTranslucentActivity));
+ assertTrue(overlayMessage, mWmState.getTaskFragmentByActivity(
+ mTranslucentActivity).isVisible());
+ }
+
+ /**
+ * Verifies the visibility of a task fragment that has overlays on top of activities embedded
+ * in untrusted mode when an activity from another process is started on top.
+ */
+ @Test
+ public void testUntrustedModeTaskFragmentVisibility_startActivityInTaskFragment() {
+ // Create a task fragment with activity in untrusted mode.
+ final TaskFragmentInfo taskFragmentInfo = createTaskFragment(
+ SECOND_UNTRUSTED_EMBEDDING_ACTIVITY);
+
+ // Start an activity with a different UID in the TaskFragment.
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .startActivityInTaskFragment(taskFragmentInfo.getFragmentToken(), mOwnerToken,
+ new Intent().setComponent(mTranslucentActivity),
+ null /* activityOptions */);
+ mTaskFragmentOrganizer.applyTransaction(wct);
+ mWmState.waitForActivityState(mTranslucentActivity, STATE_RESUMED);
+
+ // Some activities in the task fragment must be made invisible when there is an overlay.
+ mWmState.waitForActivityState(SECOND_UNTRUSTED_EMBEDDING_ACTIVITY, STATE_STOPPED);
+ final String overlayMessage = "Activities embedded in untrusted mode should be made "
+ + "invisible in a task fragment with overlay";
+ assertTrue(overlayMessage, mWmState.hasActivityState(SECOND_UNTRUSTED_EMBEDDING_ACTIVITY,
+ STATE_STOPPED));
+ assertFalse(overlayMessage, mWmState.isActivityVisible(
+ SECOND_UNTRUSTED_EMBEDDING_ACTIVITY));
+ // The activity that appeared on top would stay resumed, and the task fragment is still
+ // visible.
+ assertTrue(overlayMessage, mWmState.hasActivityState(mTranslucentActivity, STATE_RESUMED));
+ assertTrue(overlayMessage, mWmState.isActivityVisible(mTranslucentActivity));
+ assertTrue(overlayMessage, mWmState.getTaskFragmentByActivity(
+ SECOND_UNTRUSTED_EMBEDDING_ACTIVITY).isVisible());
+ }
+
+ /**
+ * Verifies the visibility of a task fragment that has overlays on top of activities embedded
+ * in untrusted mode when an activity from another process is reparented on top.
+ */
+ @Test
+ public void testUntrustedModeTaskFragmentVisibility_reparentActivityInTaskFragment() {
+ final Activity translucentActivity = startActivity(TranslucentActivity.class);
+
+ // Create a task fragment with activity in untrusted mode.
+ final TaskFragmentInfo taskFragmentInfo = createTaskFragment(
+ SECOND_UNTRUSTED_EMBEDDING_ACTIVITY);
+
+ // Reparent a translucent activity with a different UID to the TaskFragment.
+ final IBinder embeddedActivityToken = getActivityToken(translucentActivity);
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .reparentActivityToTaskFragment(taskFragmentInfo.getFragmentToken(),
+ embeddedActivityToken);
+ mTaskFragmentOrganizer.applyTransaction(wct);
+ mWmState.waitForActivityState(mTranslucentActivity, STATE_RESUMED);
+
+ // Some activities in the task fragment must be made invisible when there is an overlay.
+ mWmState.waitForActivityState(SECOND_UNTRUSTED_EMBEDDING_ACTIVITY, STATE_STOPPED);
+ final String overlayMessage = "Activities embedded in untrusted mode should be made "
+ + "invisible in a task fragment with overlay";
+ assertTrue(overlayMessage, mWmState.hasActivityState(SECOND_UNTRUSTED_EMBEDDING_ACTIVITY,
+ STATE_STOPPED));
+ assertFalse(overlayMessage, mWmState.isActivityVisible(
+ SECOND_UNTRUSTED_EMBEDDING_ACTIVITY));
+ // The activity that appeared on top would stay resumed, and the task fragment is still
+ // visible
+ assertTrue(overlayMessage, mWmState.hasActivityState(mTranslucentActivity, STATE_RESUMED));
+ assertTrue(overlayMessage, mWmState.isActivityVisible(mTranslucentActivity));
+ assertTrue(overlayMessage, mWmState.getTaskFragmentByActivity(
+ SECOND_UNTRUSTED_EMBEDDING_ACTIVITY).isVisible());
+
+ // Finishing the overlay activity must make TaskFragment visible again.
+ translucentActivity.finish();
+ waitAndAssertResumedActivity(SECOND_UNTRUSTED_EMBEDDING_ACTIVITY,
+ "Activity must be resumed without overlays");
+ assertTrue("Activity must be visible without overlays",
+ mWmState.isActivityVisible(SECOND_UNTRUSTED_EMBEDDING_ACTIVITY));
+ }
+
+ /**
+ * Creates bounds for a container that would appear on top and partially occlude the provided
+ * one.
+ */
+ @NonNull
+ private Rect partialOverlayBounds(@NonNull TaskFragmentInfo info) {
+ final Rect baseBounds = info.getConfiguration().windowConfiguration.getBounds();
+ final Rect result = new Rect(baseBounds);
+ result.inset(50 /* left */, 50 /* top */, 50 /* right */, 50 /* bottom */);
+ return result;
+ }
+
+ public static class TranslucentActivity extends FocusableActivity {}
+}
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index df00ed5..1046f871 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -236,7 +236,7 @@
private static final int UI_MODE_TYPE_VR_HEADSET = 0x07;
static final boolean ENABLE_SHELL_TRANSITIONS =
- SystemProperties.getBoolean("persist.debug.shell_transit", false);
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
private static Boolean sHasHomeScreen = null;
private static Boolean sSupportsSystemDecorsOnSecondaryDisplays = null;
diff --git a/tests/input/OWNERS b/tests/input/OWNERS
index 8ed76d2..824b5ac 100644
--- a/tests/input/OWNERS
+++ b/tests/input/OWNERS
@@ -1,5 +1,2 @@
-# Bug component: 136048
+include platform/frameworks/base:/INPUT_OWNERS
arthurhung@google.com
-lzye@google.com
-michaelwr@google.com
-svv@google.com
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 d03bf4b..329d29d 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
@@ -514,17 +514,15 @@
return decorView != null && decorView.isAttachedToWindow()
&& decorView.getVisibility() == View.VISIBLE;
}
- case "setStylusHandwritingWindowTouchListener": {
- View decorView = getStylusHandwritingWindow().getDecorView();
- if (decorView != null && decorView.getVisibility() == View.VISIBLE) {
- mEvents = new ArrayList<>();
- decorView.setOnTouchListener((view, event) ->
- mEvents.add(MotionEvent.obtain(event)));
- return true;
- }
- return false;
+ case "setStylusHandwritingInkView": {
+ View inkView = new View(attrContext);
+ getStylusHandwritingWindow().setContentView(inkView);
+ mEvents = new ArrayList<>();
+ inkView.setOnTouchListener((view, event) ->
+ mEvents.add(MotionEvent.obtain(event)));
+ return true;
}
- case "getStylusHandwritingWindowEvents": {
+ case "getStylusHandwritingEvents": {
return mEvents;
}
case "finishStylusHandwriting": {
@@ -964,11 +962,24 @@
@Override
public boolean onStartStylusHandwriting() {
+ if (mEvents != null) {
+ mEvents.clear();
+ }
getTracer().onStartStylusHandwriting(() -> super.onStartStylusHandwriting());
return true;
}
@Override
+ public void onStylusHandwritingMotionEvent(@NonNull MotionEvent motionEvent) {
+ if (mEvents == null) {
+ mEvents = new ArrayList<>();
+ }
+ mEvents.add(MotionEvent.obtain(motionEvent));
+ getTracer().onStylusHandwritingMotionEvent(()
+ -> super.onStylusHandwritingMotionEvent(motionEvent));
+ }
+
+ @Override
public void onFinishStylusHandwriting() {
getTracer().onFinishStylusHandwriting(() -> super.onFinishStylusHandwriting());
}
@@ -1358,6 +1369,10 @@
recordEventInternal("onStartStylusHandwriting", runnable, arguments);
}
+ void onStylusHandwritingMotionEvent(@NonNull Runnable runnable) {
+ recordEventInternal("onStylusMotionEvent", runnable);
+ }
+
void onFinishStylusHandwriting(@NonNull Runnable runnable) {
final Bundle arguments = new Bundle();
arguments.putParcelable("editorInfo", mIme.getCurrentInputEditorInfo());
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
index a779410..87cd773 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
@@ -1450,13 +1450,13 @@
}
@NonNull
- public ImeCommand callSetStylusHandwritingWindowTouchListener() {
- return callCommandInternal("setStylusHandwritingWindowTouchListener", new Bundle());
+ public ImeCommand callSetStylusHandwritingInkView() {
+ return callCommandInternal("setStylusHandwritingInkView", new Bundle());
}
@NonNull
- public ImeCommand callGetStylusHandwritingWindowEvents() {
- return callCommandInternal("getStylusHandwritingWindowEvents", new Bundle());
+ public ImeCommand callGetStylusHandwritingEvents() {
+ return callCommandInternal("getStylusHandwritingEvents", new Bundle());
}
@NonNull
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
index 265940f2..1398785 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
@@ -30,6 +30,7 @@
import android.Manifest;
import android.content.Context;
+import android.inputmethodservice.InputMethodService;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Pair;
@@ -154,12 +155,28 @@
/**
* Call {@link InputMethodManager#startStylusHandwriting(View)} and inject Stylus touch events
- * on screen. Make sure InkWindow receives those events via Spy window surface.
+ * on screen. Make sure {@link InputMethodService#onStylusHandwritingMotionEvent(MotionEvent)}
+ * receives those events via Spy window surface.
* @throws Exception
*/
@Test
- public void testHandwritingStylusEvents() throws Exception {
- final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
+ public void testHandwritingStylusEvents_onStylusHandwritingMotionEvent() throws Exception {
+ testHandwritingStylusEvents(false /* verifyOnInkView */);
+ }
+
+ /**
+ * Call {@link InputMethodManager#startStylusHandwriting(View)} and inject Stylus touch events
+ * on screen. Make sure Inking view receives those events via Spy window surface.
+ * @throws Exception
+ */
+ @Test
+ public void testHandwritingStylusEvents_dispatchToInkView() throws Exception {
+ testHandwritingStylusEvents(false /* verifyOnInkView */);
+ }
+
+ private void testHandwritingStylusEvents(boolean verifyOnInkView) throws Exception {
+ final InputMethodManager imm = InstrumentationRegistry.getInstrumentation()
+ .getTargetContext().getSystemService(InputMethodManager.class);
try (MockImeSession imeSession = MockImeSession.create(
InstrumentationRegistry.getInstrumentation().getContext(),
InstrumentationRegistry.getInstrumentation().getUiAutomation(),
@@ -187,19 +204,25 @@
stream, imeSession.callGetStylusHandwritingWindowVisibility(), TIMEOUT)
.getReturnBooleanValue());
- // Verify IME stylus window receives the motion Event.
- assertTrue(expectCommand(
- stream, imeSession.callSetStylusHandwritingWindowTouchListener(), TIMEOUT)
- .getReturnBooleanValue());
+ if (verifyOnInkView) {
+ // Verify IME stylus Ink view receives the motion Event.
+ assertTrue(expectCommand(
+ stream,
+ imeSession.callSetStylusHandwritingInkView(),
+ TIMEOUT).getReturnBooleanValue());
+ }
// inject Stylus touch events to screen
List<MotionEvent> injectedEvents =
TestUtils.getStylusMoveEventsOnDisplay(0 /* displayId */);
TestUtils.injectAll(injectedEvents);
- // get Stylus events from InkWindow.
- ArrayList<MotionEvent> capturedEvents = expectCommand(
- stream, imeSession.callGetStylusHandwritingWindowEvents(), TIMEOUT)
+ expectEvent(
+ stream, event -> "onStylusMotionEvent".equals(event.getEventName()), TIMEOUT);
+
+ // get Stylus events from Ink view.
+ ArrayList<MotionEvent> capturedEvents = expectCommand(
+ stream, imeSession.callGetStylusHandwritingEvents(), TIMEOUT)
.getReturnParcelableArrayListValue();
assertNotNull(capturedEvents);
diff --git a/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementCorrectionsInjectionTest.java b/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementCorrectionsInjectionTest.java
index ee7b466..21f3d2b 100644
--- a/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementCorrectionsInjectionTest.java
+++ b/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementCorrectionsInjectionTest.java
@@ -25,6 +25,7 @@
import android.location.cts.common.TestGnssStatusCallback;
import android.location.cts.common.TestLocationListener;
import android.location.cts.common.TestLocationManager;
+import android.location.cts.common.TestMeasurementUtil;
import android.util.Log;
import androidx.test.core.app.ApplicationProvider;
@@ -40,6 +41,8 @@
import java.util.ArrayList;
import java.util.List;
+import static org.junit.Assume.assumeTrue;
+
/**
* Tests for {@link GnssMeasurementCorrections} injection.
*
@@ -62,6 +65,7 @@
InstrumentationRegistry.getInstrumentation()
.getUiAutomation()
.adoptShellPermissionIdentity(Manifest.permission.LOCATION_HARDWARE);
+ assumeTrue(TestMeasurementUtil.canTestRunOnCurrentDevice(mTestLocationManager, TAG));
}
@After
diff --git a/tests/media/jni/NativeCodecDecoderTest.cpp b/tests/media/jni/NativeCodecDecoderTest.cpp
index d005322..8ea1136 100644
--- a/tests/media/jni/NativeCodecDecoderTest.cpp
+++ b/tests/media/jni/NativeCodecDecoderTest.cpp
@@ -44,7 +44,7 @@
void setUpAudioReference(const char* refFile);
void deleteReference();
- bool setUpExtractor(const char* srcFile);
+ bool setUpExtractor(const char* srcFile, int colorFormat);
void deleteExtractor();
bool configureCodec(AMediaFormat* format, bool isAsync, bool signalEOSWithLastFrame,
bool isEncoder) override;
@@ -60,10 +60,10 @@
~CodecDecoderTest();
bool testSimpleDecode(const char* decoder, const char* testFile, const char* refFile,
- float rmsError, uLong checksum);
- bool testFlush(const char* decoder, const char* testFile);
- bool testOnlyEos(const char* decoder, const char* testFile);
- bool testSimpleDecodeQueueCSD(const char* decoder, const char* testFile);
+ int colorFormat, float rmsError, uLong checksum);
+ bool testFlush(const char* decoder, const char* testFile, int colorFormat);
+ bool testOnlyEos(const char* decoder, const char* testFile, int colorFormat);
+ bool testSimpleDecodeQueueCSD(const char* decoder, const char* testFile, int colorFormat);
};
CodecDecoderTest::CodecDecoderTest(const char* mime, ANativeWindow* window)
@@ -103,7 +103,7 @@
mRefLength = 0;
}
-bool CodecDecoderTest::setUpExtractor(const char* srcFile) {
+bool CodecDecoderTest::setUpExtractor(const char* srcFile, int colorFormat) {
FILE* fp = fopen(srcFile, "rbe");
struct stat buf {};
if (fp && !fstat(fileno(fp), &buf)) {
@@ -114,6 +114,7 @@
if (res != AMEDIA_OK) {
deleteExtractor();
} else {
+ mBytesPerSample = (colorFormat == COLOR_FormatYUVP010) ? 2 : 1;
for (size_t trackID = 0; trackID < AMediaExtractor_getTrackCount(mExtractor);
trackID++) {
AMediaFormat* currFormat = AMediaExtractor_getTrackFormat(mExtractor, trackID);
@@ -123,7 +124,7 @@
AMediaExtractor_selectTrack(mExtractor, trackID);
if (!mIsAudio) {
AMediaFormat_setInt32(currFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT,
- COLOR_FormatYUV420Flexible);
+ colorFormat);
}
mInpDecFormat = currFormat;
// TODO: determine this from the extractor format when it becomes exposed.
@@ -239,7 +240,7 @@
AMediaFormat_getInt32(format, "width", &width);
AMediaFormat_getInt32(format, "height", &height);
AMediaFormat_getInt32(format, "stride", &stride);
- mOutputBuff->updateChecksum(buf, info, width, height, stride);
+ mOutputBuff->updateChecksum(buf, info, width, height, stride, mBytesPerSample);
}
}
mOutputBuff->saveOutPTS(info->presentationTimeUs);
@@ -300,9 +301,10 @@
}
bool CodecDecoderTest::testSimpleDecode(const char* decoder, const char* testFile,
- const char* refFile, float rmsError, uLong checksum) {
+ const char* refFile, int colorFormat, float rmsError,
+ uLong checksum) {
bool isPass = true;
- if (!setUpExtractor(testFile)) return false;
+ if (!setUpExtractor(testFile, colorFormat)) return false;
mSaveToMem = (mWindow == nullptr);
auto ref = &mRefBuff;
auto test = &mTestBuff;
@@ -400,9 +402,9 @@
return isPass;
}
-bool CodecDecoderTest::testFlush(const char* decoder, const char* testFile) {
+bool CodecDecoderTest::testFlush(const char* decoder, const char* testFile, int colorFormat) {
bool isPass = true;
- if (!setUpExtractor(testFile)) return false;
+ if (!setUpExtractor(testFile, colorFormat)) return false;
mCsdBuffers.clear();
for (int i = 0;; i++) {
char csdName[16];
@@ -527,9 +529,9 @@
return isPass;
}
-bool CodecDecoderTest::testOnlyEos(const char* decoder, const char* testFile) {
+bool CodecDecoderTest::testOnlyEos(const char* decoder, const char* testFile, int colorFormat) {
bool isPass = true;
- if (!setUpExtractor(testFile)) return false;
+ if (!setUpExtractor(testFile, colorFormat)) return false;
mSaveToMem = (mWindow == nullptr);
auto ref = &mRefBuff;
auto test = &mTestBuff;
@@ -568,9 +570,10 @@
return isPass;
}
-bool CodecDecoderTest::testSimpleDecodeQueueCSD(const char* decoder, const char* testFile) {
+bool CodecDecoderTest::testSimpleDecodeQueueCSD(const char* decoder, const char* testFile,
+ int colorFormat) {
bool isPass = true;
- if (!setUpExtractor(testFile)) return false;
+ if (!setUpExtractor(testFile, colorFormat)) return false;
std::vector<AMediaFormat*> formats;
formats.push_back(mInpDecFormat);
mInpDecDupFormat = AMediaFormat_new();
@@ -664,7 +667,7 @@
static jboolean nativeTestSimpleDecode(JNIEnv* env, jobject, jstring jDecoder, jobject surface,
jstring jMime, jstring jtestFile, jstring jrefFile,
- jfloat jrmsError, jlong jChecksum) {
+ jint jColorFormat, jfloat jrmsError, jlong jChecksum) {
const char* cDecoder = env->GetStringUTFChars(jDecoder, nullptr);
const char* cMime = env->GetStringUTFChars(jMime, nullptr);
const char* cTestFile = env->GetStringUTFChars(jtestFile, nullptr);
@@ -673,8 +676,8 @@
uLong cChecksum = jChecksum;
ANativeWindow* window = surface ? ANativeWindow_fromSurface(env, surface) : nullptr;
auto* codecDecoderTest = new CodecDecoderTest(cMime, window);
- bool isPass =
- codecDecoderTest->testSimpleDecode(cDecoder, cTestFile, cRefFile, cRmsError, cChecksum);
+ bool isPass = codecDecoderTest->testSimpleDecode(cDecoder, cTestFile, cRefFile, jColorFormat,
+ cRmsError, cChecksum);
delete codecDecoderTest;
if (window) {
ANativeWindow_release(window);
@@ -688,12 +691,12 @@
}
static jboolean nativeTestOnlyEos(JNIEnv* env, jobject, jstring jDecoder, jstring jMime,
- jstring jtestFile) {
+ jstring jtestFile, jint jColorFormat) {
const char* cDecoder = env->GetStringUTFChars(jDecoder, nullptr);
const char* cMime = env->GetStringUTFChars(jMime, nullptr);
const char* cTestFile = env->GetStringUTFChars(jtestFile, nullptr);
auto* codecDecoderTest = new CodecDecoderTest(cMime, nullptr);
- bool isPass = codecDecoderTest->testOnlyEos(cDecoder, cTestFile);
+ bool isPass = codecDecoderTest->testOnlyEos(cDecoder, cTestFile, jColorFormat);
delete codecDecoderTest;
env->ReleaseStringUTFChars(jDecoder, cDecoder);
env->ReleaseStringUTFChars(jMime, cMime);
@@ -702,13 +705,13 @@
}
static jboolean nativeTestFlush(JNIEnv* env, jobject, jstring jDecoder, jobject surface,
- jstring jMime, jstring jtestFile) {
+ jstring jMime, jstring jtestFile, jint jColorFormat) {
const char* cDecoder = env->GetStringUTFChars(jDecoder, nullptr);
const char* cMime = env->GetStringUTFChars(jMime, nullptr);
const char* cTestFile = env->GetStringUTFChars(jtestFile, nullptr);
ANativeWindow* window = surface ? ANativeWindow_fromSurface(env, surface) : nullptr;
auto* codecDecoderTest = new CodecDecoderTest(cMime, window);
- bool isPass = codecDecoderTest->testFlush(cDecoder, cTestFile);
+ bool isPass = codecDecoderTest->testFlush(cDecoder, cTestFile, jColorFormat);
delete codecDecoderTest;
if (window) {
ANativeWindow_release(window);
@@ -721,12 +724,13 @@
}
static jboolean nativeTestSimpleDecodeQueueCSD(JNIEnv* env, jobject, jstring jDecoder,
- jstring jMime, jstring jtestFile) {
+ jstring jMime, jstring jtestFile,
+ jint jColorFormat) {
const char* cDecoder = env->GetStringUTFChars(jDecoder, nullptr);
const char* cMime = env->GetStringUTFChars(jMime, nullptr);
const char* cTestFile = env->GetStringUTFChars(jtestFile, nullptr);
auto codecDecoderTest = new CodecDecoderTest(cMime, nullptr);
- bool isPass = codecDecoderTest->testSimpleDecodeQueueCSD(cDecoder, cTestFile);
+ bool isPass = codecDecoderTest->testSimpleDecodeQueueCSD(cDecoder, cTestFile, jColorFormat);
delete codecDecoderTest;
env->ReleaseStringUTFChars(jDecoder, cDecoder);
env->ReleaseStringUTFChars(jMime, cMime);
@@ -738,15 +742,15 @@
const JNINativeMethod methodTable[] = {
{"nativeTestSimpleDecode",
"(Ljava/lang/String;Landroid/view/Surface;Ljava/lang/String;Ljava/lang/String;Ljava/"
- "lang/String;FJ)Z",
+ "lang/String;IFJ)Z",
(void*)nativeTestSimpleDecode},
- {"nativeTestOnlyEos", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
+ {"nativeTestOnlyEos", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Z",
(void*)nativeTestOnlyEos},
{"nativeTestFlush",
- "(Ljava/lang/String;Landroid/view/Surface;Ljava/lang/String;Ljava/lang/String;)Z",
+ "(Ljava/lang/String;Landroid/view/Surface;Ljava/lang/String;Ljava/lang/String;I)Z",
(void*)nativeTestFlush},
{"nativeTestSimpleDecodeQueueCSD",
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
+ "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Z",
(void*)nativeTestSimpleDecodeQueueCSD},
};
jclass c = env->FindClass("android/mediav2/cts/CodecDecoderTest");
@@ -757,10 +761,10 @@
const JNINativeMethod methodTable[] = {
{"nativeTestSimpleDecode",
"(Ljava/lang/String;Landroid/view/Surface;Ljava/lang/String;Ljava/lang/String;Ljava/"
- "lang/String;FJ)Z",
+ "lang/String;IFJ)Z",
(void*)nativeTestSimpleDecode},
{"nativeTestFlush",
- "(Ljava/lang/String;Landroid/view/Surface;Ljava/lang/String;Ljava/lang/String;)Z",
+ "(Ljava/lang/String;Landroid/view/Surface;Ljava/lang/String;Ljava/lang/String;I)Z",
(void*)nativeTestFlush},
};
jclass c = env->FindClass("android/mediav2/cts/CodecDecoderSurfaceTest");
diff --git a/tests/media/jni/NativeCodecTestBase.cpp b/tests/media/jni/NativeCodecTestBase.cpp
index 1516185..391ef1e 100644
--- a/tests/media/jni/NativeCodecTestBase.cpp
+++ b/tests/media/jni/NativeCodecTestBase.cpp
@@ -207,8 +207,8 @@
return result;
}
-void OutputManager::updateChecksum(
- uint8_t* buf, AMediaCodecBufferInfo* info, int width, int height, int stride) {
+void OutputManager::updateChecksum(uint8_t* buf, AMediaCodecBufferInfo* info, int width, int height,
+ int stride, int bytesPerSample) {
uint8_t flattenInfo[16];
int pos = 0;
if (width <= 0 || height <= 0 || stride <= 0) {
@@ -218,15 +218,15 @@
info->flags & ~AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
flattenField<int64_t>(flattenInfo, &pos, info->presentationTimeUs);
crc32value = crc32(crc32value, flattenInfo, pos);
- if (width > 0 && height > 0 && stride > 0) {
+ if (width > 0 && height > 0 && stride > 0 && bytesPerSample > 0) {
// Only checksum Y plane
- std::vector<uint8_t> tmp(width * height, 0u);
+ std::vector<uint8_t> tmp(width * height * bytesPerSample, 0u);
size_t offset = 0;
for (int i = 0; i < height; ++i) {
- memcpy(tmp.data() + (i * width), buf + offset, width);
+ memcpy(tmp.data() + (i * width * bytesPerSample), buf + offset, width * bytesPerSample);
offset += stride;
}
- crc32value = crc32(crc32value, tmp.data(), width * height);
+ crc32value = crc32(crc32value, tmp.data(), width * height * bytesPerSample);
} else {
crc32value = crc32(crc32value, buf, info->size);
}
@@ -342,6 +342,7 @@
mSaveToMem = false;
mOutputBuff = nullptr;
mCodec = nullptr;
+ mBytesPerSample = mIsAudio ? 2 : 1;
}
CodecTestBase::~CodecTestBase() {
diff --git a/tests/media/jni/NativeCodecTestBase.h b/tests/media/jni/NativeCodecTestBase.h
index d67933a..9a22108 100644
--- a/tests/media/jni/NativeCodecTestBase.h
+++ b/tests/media/jni/NativeCodecTestBase.h
@@ -106,10 +106,11 @@
memory.insert(memory.end(), buf, buf + info->size);
}
void updateChecksum(uint8_t* buf, AMediaCodecBufferInfo* info) {
- updateChecksum(buf, info, 0, 0, 0);
+ updateChecksum(buf, info, 0, 0, 0, 0);
}
- void updateChecksum(
- uint8_t* buf, AMediaCodecBufferInfo* info, int width, int height, int stride);
+
+ void updateChecksum(uint8_t* buf, AMediaCodecBufferInfo* info, int width, int height,
+ int stride, int bytesPerSample);
uLong getChecksum() { return crc32value; }
void reset() {
inpPtsArray.clear();
@@ -136,6 +137,7 @@
int64_t mPrevOutputPts;
bool mSignalledOutFormatChanged;
AMediaFormat* mOutFormat;
+ int mBytesPerSample;
bool mSaveToMem;
OutputManager* mOutputBuff;
diff --git a/tests/media/jni/NativeMediaCommon.h b/tests/media/jni/NativeMediaCommon.h
index c597923..fd8aba1 100644
--- a/tests/media/jni/NativeMediaCommon.h
+++ b/tests/media/jni/NativeMediaCommon.h
@@ -56,6 +56,7 @@
constexpr int COLOR_FormatYUV420SemiPlanar = 21;
constexpr int COLOR_FormatYUV420Flexible = 0x7F420888;
constexpr int COLOR_FormatSurface = 0x7f000789;
+constexpr int COLOR_FormatYUVP010 = 54;
// constants not defined in NDK
extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_REQUEST_SYNC_FRAME;
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
index 0dc1e95..b0da46f 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
@@ -443,7 +443,7 @@
}
private native boolean nativeTestSimpleDecode(String decoder, Surface surface, String mime,
- String testFile, String refFile, float rmsError, long checksum);
+ String testFile, String refFile, int colorFormat, float rmsError, long checksum);
@LargeTest
@Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
@@ -452,11 +452,12 @@
mExtractor.release();
mActivity.setScreenParams(getWidth(format), getHeight(format), false);
assertTrue(nativeTestSimpleDecode(mCodecName, mSurface, mMime, mInpPrefix + mTestFile,
- mInpPrefix + mReconfigFile, -1.0f, 0L));
+ mInpPrefix + mReconfigFile, format.getInteger(MediaFormat.KEY_COLOR_FORMAT), -1.0f,
+ 0L));
}
private native boolean nativeTestFlush(String decoder, Surface surface, String mime,
- String testFile);
+ String testFile, int colorFormat);
@LargeTest
@Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
@@ -464,6 +465,7 @@
MediaFormat format = setUpSource(mTestFile);
mExtractor.release();
mActivity.setScreenParams(getWidth(format), getHeight(format), true);
- assertTrue(nativeTestFlush(mCodecName, mSurface, mMime, mInpPrefix + mTestFile));
+ assertTrue(nativeTestFlush(mCodecName, mSurface, mMime, mInpPrefix + mTestFile,
+ format.getInteger(MediaFormat.KEY_COLOR_FORMAT)));
}
}
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
index ff5ca6d..5cc2861 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
@@ -190,7 +190,7 @@
}
private native boolean nativeTestSimpleDecode(String decoder, Surface surface, String mime,
- String testFile, String refFile, float rmsError, long checksum);
+ String testFile, String refFile, int colorFormat, float rmsError, long checksum);
static void verify(OutputManager outBuff, String refFile, float rmsError, int audioFormat,
long refCRC) throws IOException {
@@ -328,15 +328,17 @@
}
}
mCodec.release();
+ mExtractor.release();
+ int colorFormat = mIsAudio ? 0 : format.getInteger(MediaFormat.KEY_COLOR_FORMAT);
+ assertTrue(nativeTestSimpleDecode(mCodecName, null, mMime, mInpPrefix + mTestFile,
+ mInpPrefix + mRefFile, colorFormat, mRmsError, ref.getCheckSumBuffer()));
if (mSaveToMem) {
int audioEncoding = mIsAudio ? format.getInteger(MediaFormat.KEY_PCM_ENCODING,
AudioFormat.ENCODING_PCM_16BIT) : AudioFormat.ENCODING_INVALID;
+ Assume.assumeFalse("skip checksum due to tone mapping", mSkipChecksumVerification);
verify(mOutputBuff, mRefFile, mRmsError, audioEncoding, mRefCRC);
}
- assertTrue(nativeTestSimpleDecode(mCodecName, null, mMime, mInpPrefix + mTestFile,
- mInpPrefix + mRefFile, mRmsError, ref.getCheckSumBuffer()));
}
- mExtractor.release();
}
/**
@@ -453,15 +455,19 @@
}
private native boolean nativeTestFlush(String decoder, Surface surface, String mime,
- String testFile);
+ String testFile, int colorFormat);
@Ignore("TODO(b/147576107)")
@LargeTest
@Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
- public void testFlushNative() {
- {
- assertTrue(nativeTestFlush(mCodecName, null, mMime, mInpPrefix + mTestFile));
+ public void testFlushNative() throws IOException {
+ int colorFormat = 0;
+ if (!mIsAudio) {
+ MediaFormat format = setUpSource(mTestFile);
+ mExtractor.release();
+ colorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT);
}
+ assertTrue(nativeTestFlush(mCodecName, null, mMime, mInpPrefix + mTestFile, colorFormat));
}
/**
@@ -677,14 +683,19 @@
mExtractor.release();
}
- private native boolean nativeTestOnlyEos(String decoder, String mime, String testFile);
+ private native boolean nativeTestOnlyEos(String decoder, String mime, String testFile,
+ int colorFormat);
@SmallTest
@Test
- public void testOnlyEosNative() {
- {
- assertTrue(nativeTestOnlyEos(mCodecName, mMime, mInpPrefix + mTestFile));
+ public void testOnlyEosNative() throws IOException {
+ int colorFormat = 0;
+ if (!mIsAudio) {
+ MediaFormat format = setUpSource(mTestFile);
+ mExtractor.release();
+ colorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT);
}
+ assertTrue(nativeTestOnlyEos(mCodecName, mMime, mInpPrefix + mTestFile, colorFormat));
}
/**
@@ -778,7 +789,7 @@
}
private native boolean nativeTestSimpleDecodeQueueCSD(String decoder, String mime,
- String testFile);
+ String testFile, int colorFormat);
@LargeTest
@Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
@@ -788,10 +799,10 @@
mExtractor.release();
return;
}
- {
- assertTrue(nativeTestSimpleDecodeQueueCSD(mCodecName, mMime, mInpPrefix + mTestFile));
- }
mExtractor.release();
+ int colorFormat = mIsAudio ? 0 : format.getInteger(MediaFormat.KEY_COLOR_FORMAT);
+ assertTrue(nativeTestSimpleDecodeQueueCSD(mCodecName, mMime, mInpPrefix + mTestFile,
+ colorFormat));
}
/**
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java
index 1938b8f..9729cc6 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java
@@ -23,6 +23,7 @@
import androidx.test.filters.LargeTest;
+import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -639,6 +640,7 @@
assertEquals("width mismatch", mWidth, getWidth(mOutFormat));
assertEquals("height mismatch", mHeight, getHeight(mOutFormat));
}
+ Assume.assumeFalse("skip checksum due to tonemapping", mSkipChecksumVerification);
CodecDecoderTest.verify(ref, mRefFile, mRmsError, audioEncoding, mRefCRC);
}
}
diff --git a/tests/media/src/android/mediav2/cts/CodecTestBase.java b/tests/media/src/android/mediav2/cts/CodecTestBase.java
index d07a1df..fd68507 100644
--- a/tests/media/src/android/mediav2/cts/CodecTestBase.java
+++ b/tests/media/src/android/mediav2/cts/CodecTestBase.java
@@ -66,6 +66,7 @@
import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
import static android.media.MediaCodecInfo.CodecProfileLevel.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -293,36 +294,37 @@
}
void checksum(ByteBuffer buf, int size) {
- checksum(buf, size, 0, 0, 0);
+ checksum(buf, size, 0, 0, 0, 0);
}
- void checksum(ByteBuffer buf, int size, int width, int height, int stride) {
+ void checksum(ByteBuffer buf, int size, int width, int height, int stride, int bytesPerSample) {
int cap = buf.capacity();
assertTrue("checksum() params are invalid: size = " + size + " cap = " + cap,
size > 0 && size <= cap);
if (buf.hasArray()) {
- if (width > 0 && height > 0 && stride > 0) {
+ if (width > 0 && height > 0 && stride > 0 && bytesPerSample > 0) {
int offset = buf.position() + buf.arrayOffset();
- byte[] bb = new byte[width * height];
+ byte[] bb = new byte[width * height * bytesPerSample];
for (int i = 0; i < height; ++i) {
- System.arraycopy(buf.array(), offset, bb, i * width, width);
+ System.arraycopy(buf.array(), offset, bb, i * width * bytesPerSample,
+ width * bytesPerSample);
offset += stride;
}
- mCrc32UsingBuffer.update(bb, 0, width * height);
+ mCrc32UsingBuffer.update(bb, 0, width * height * bytesPerSample);
} else {
mCrc32UsingBuffer.update(buf.array(), buf.position() + buf.arrayOffset(), size);
}
- } else if (width > 0 && height > 0 && stride > 0) {
+ } else if (width > 0 && height > 0 && stride > 0 && bytesPerSample > 0) {
// Checksum only the Y plane
int pos = buf.position();
int offset = pos;
- byte[] bb = new byte[width * height];
+ byte[] bb = new byte[width * height * bytesPerSample];
for (int i = 0; i < height; ++i) {
buf.position(offset);
- buf.get(bb, i * width, width);
+ buf.get(bb, i * width * bytesPerSample, width * bytesPerSample);
offset += stride;
}
- mCrc32UsingBuffer.update(bb, 0, width * height);
+ mCrc32UsingBuffer.update(bb, 0, width * height * bytesPerSample);
buf.position(pos);
} else {
int pos = buf.position();
@@ -340,7 +342,9 @@
void checksum(Image image) {
int format = image.getFormat();
- assertEquals("unexpected image format", ImageFormat.YUV_420_888, format);
+ assertTrue("unexpected image format",
+ format == ImageFormat.YUV_420_888 || format == ImageFormat.YCBCR_P010);
+ int bytesPerSample = (ImageFormat.getBitsPerPixel(format) * 2) / (8 * 3); // YUV420
Rect cropRect = image.getCropRect();
int imageWidth = cropRect.width();
@@ -356,6 +360,7 @@
rowStride = planes[i].getRowStride();
pixelStride = planes[i].getPixelStride();
if (i == 0) {
+ assertEquals(bytesPerSample, pixelStride);
width = imageWidth;
height = imageHeight;
left = imageLeft;
@@ -368,30 +373,35 @@
}
int cropOffset = (left * pixelStride) + top * rowStride;
// local contiguous pixel buffer
- byte[] bb = new byte[width * height];
+ byte[] bb = new byte[width * height * bytesPerSample];
+
if (buf.hasArray()) {
byte[] b = buf.array();
int offs = buf.arrayOffset() + cropOffset;
- if (pixelStride == 1) {
+ if (pixelStride == bytesPerSample) {
for (y = 0; y < height; ++y) {
- System.arraycopy(b, offs + y * rowStride, bb, y * width, width);
+ System.arraycopy(b, offs + y * rowStride, bb, y * width * bytesPerSample,
+ width * bytesPerSample);
}
} else {
// do it pixel-by-pixel
for (y = 0; y < height; ++y) {
int lineOffset = offs + y * rowStride;
for (x = 0; x < width; ++x) {
- bb[y * width + x] = b[lineOffset + x * pixelStride];
+ for (int bytePos = 0; bytePos < bytesPerSample; ++bytePos) {
+ bb[y * width * bytesPerSample + x * bytesPerSample + bytePos] =
+ b[lineOffset + x * pixelStride + bytePos];
+ }
}
}
}
} else { // almost always ends up here due to direct buffers
int base = buf.position();
int pos = base + cropOffset;
- if (pixelStride == 1) {
+ if (pixelStride == bytesPerSample) {
for (y = 0; y < height; ++y) {
buf.position(pos + y * rowStride);
- buf.get(bb, y * width, width);
+ buf.get(bb, y * width * bytesPerSample, width * bytesPerSample);
}
} else {
// local line buffer
@@ -399,16 +409,20 @@
// do it pixel-by-pixel
for (y = 0; y < height; ++y) {
buf.position(pos + y * rowStride);
- // we're only guaranteed to have pixelStride * (width - 1) + 1 bytes
- buf.get(lb, 0, pixelStride * (width - 1) + 1);
+ // we're only guaranteed to have pixelStride * (width - 1) +
+ // bytesPerSample bytes
+ buf.get(lb, 0, pixelStride * (width - 1) + bytesPerSample);
for (x = 0; x < width; ++x) {
- bb[y * width + x] = lb[x * pixelStride];
+ for (int bytePos = 0; bytePos < bytesPerSample; ++bytePos) {
+ bb[y * width * bytesPerSample + x * bytesPerSample + bytePos] =
+ lb[x * pixelStride + bytePos];
+ }
}
}
}
buf.position(base);
}
- mCrc32UsingImage.update(bb, 0, width * height);
+ mCrc32UsingImage.update(bb, 0, width * height * bytesPerSample);
}
}
@@ -683,6 +697,35 @@
return isSupported;
}
+ static boolean doesAnyFormatHaveHBDProfile(String mime, ArrayList<MediaFormat> formats) {
+ // check for HLG profiles
+ for (MediaFormat format : formats) {
+ assertEquals(mime, format.getString(MediaFormat.KEY_MIME));
+ switch (mime) {
+ case MediaFormat.MIMETYPE_VIDEO_VP9: {
+ int profile = format.getInteger(MediaFormat.KEY_PROFILE, VP9Profile0);
+ if (profile == VP9Profile2 || profile == VP9Profile3) {
+ return true;
+ }
+ }
+ case MediaFormat.MIMETYPE_VIDEO_HEVC: {
+ int profile = format.getInteger(MediaFormat.KEY_PROFILE, HEVCProfileMain);
+ if (profile == HEVCProfileMain10) {
+ return true;
+ }
+ }
+ case MediaFormat.MIMETYPE_VIDEO_AV1: {
+ int profile = format.getInteger(MediaFormat.KEY_PROFILE, AV1ProfileMain8);
+ if (profile == AV1ProfileMain10) {
+ return true;
+ }
+ }
+ }
+ }
+ // check for HDR profiles (if necessary)
+ return doesAnyFormatHaveHDRProfile(mime, formats);
+ }
+
static boolean doesAnyFormatHaveHDRProfile(String mime, ArrayList<MediaFormat> formats) {
for (MediaFormat format : formats) {
assertEquals(mime, format.getString(MediaFormat.KEY_MIME));
@@ -1225,6 +1268,7 @@
String mMime;
String mTestFile;
boolean mIsInterlaced;
+ boolean mSkipChecksumVerification;
ArrayList<ByteBuffer> mCsdBuffers;
private int mCurrCsdIdx;
@@ -1248,6 +1292,7 @@
}
MediaFormat setUpSource(String prefix, String srcFile) throws IOException {
+ Preconditions.assertTestFileExists(prefix + srcFile);
mExtractor = new MediaExtractor();
mExtractor.setDataSource(prefix + srcFile);
for (int trackID = 0; trackID < mExtractor.getTrackCount(); trackID++) {
@@ -1265,11 +1310,15 @@
}
}
} else {
- if (mSurface == null) {
- // COLOR_FormatYUV420Flexible must be supported by all components
- format.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatYUV420Flexible);
- } else {
- format.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatSurface);
+ ArrayList<MediaFormat> formatList = new ArrayList<>();
+ formatList.add(format);
+ boolean selectHBD = doesAnyFormatHaveHBDProfile(mMime, formatList) ||
+ srcFile.contains("10bit");
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+ getColorFormat(mCodecName, mMime, mSurface != null, selectHBD));
+ if (selectHBD && (format.getInteger(MediaFormat.KEY_COLOR_FORMAT) !=
+ COLOR_FormatYUVP010)) {
+ mSkipChecksumVerification = true;
}
}
// TODO: determine this from the extractor format when it becomes exposed.
@@ -1281,6 +1330,23 @@
return null;
}
+ int getColorFormat(String name, String mediaType, boolean surfaceMode, boolean hbdMode)
+ throws IOException {
+ if (surfaceMode) return COLOR_FormatSurface;
+ if (hbdMode) {
+ MediaCodec codec = MediaCodec.createByCodecName(name);
+ MediaCodecInfo.CodecCapabilities cap =
+ codec.getCodecInfo().getCapabilitiesForType(mediaType);
+ codec.release();
+ for (int c : cap.colorFormats) {
+ if (c == COLOR_FormatYUVP010) {
+ return c;
+ }
+ }
+ }
+ return COLOR_FormatYUV420Flexible;
+ }
+
boolean hasCSD(MediaFormat format) {
return format.containsKey("csd-0");
}
@@ -1371,15 +1437,18 @@
} else {
// tests both getOutputImage and getOutputBuffer. Can do time division
// multiplexing but lets allow it for now
- MediaFormat format = mCodec.getOutputFormat();
- int width = format.getInteger(MediaFormat.KEY_WIDTH);
- int height = format.getInteger(MediaFormat.KEY_HEIGHT);
- int stride = format.getInteger(MediaFormat.KEY_STRIDE);
- mOutputBuff.checksum(buf, info.size, width, height, stride);
-
Image img = mCodec.getOutputImage(bufferIndex);
assertTrue(img != null);
mOutputBuff.checksum(img);
+ int imgFormat = img.getFormat();
+ int bytesPerSample = (ImageFormat.getBitsPerPixel(imgFormat) * 2) / (8 * 3);
+
+ MediaFormat format = mCodec.getOutputFormat();
+ buf = mCodec.getOutputBuffer(bufferIndex);
+ int width = format.getInteger(MediaFormat.KEY_WIDTH);
+ int height = format.getInteger(MediaFormat.KEY_HEIGHT);
+ int stride = format.getInteger(MediaFormat.KEY_STRIDE);
+ mOutputBuff.checksum(buf, info.size, width, height, stride, bytesPerSample);
}
}
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
diff --git a/tests/media/src/android/mediav2/cts/ExtractorTest.java b/tests/media/src/android/mediav2/cts/ExtractorTest.java
index b7840db..502a5ba 100644
--- a/tests/media/src/android/mediav2/cts/ExtractorTest.java
+++ b/tests/media/src/android/mediav2/cts/ExtractorTest.java
@@ -1612,26 +1612,38 @@
}
}
extractor.release();
- assertTrue(format != null);
+ assertTrue("missing track format from file " + file, format != null);
if (mMime.equals(MediaFormat.MIMETYPE_AUDIO_AAC)) {
- assertTrue(format.containsKey(MediaFormat.KEY_AAC_PROFILE) ||
+ assertTrue("neither KEY_AAC_PROFILE nor KEY_PROFILE found in file " + file,
+ format.containsKey(MediaFormat.KEY_AAC_PROFILE) ||
format.containsKey(MediaFormat.KEY_PROFILE));
if (format.containsKey(MediaFormat.KEY_AAC_PROFILE)) {
- assertEquals(mProfile, format.getInteger(MediaFormat.KEY_AAC_PROFILE));
+ int profile = format.getInteger(MediaFormat.KEY_AAC_PROFILE, -1);
+ assertEquals("mismatched KEY_AAC_PROFILE in file " + file,
+ mProfile, profile);
}
if (format.containsKey(MediaFormat.KEY_PROFILE)) {
- assertEquals(mProfile, format.getInteger(MediaFormat.KEY_PROFILE));
+ int profile = format.getInteger(MediaFormat.KEY_PROFILE, -1);
+ assertEquals("mismatched KEY_PROFILE in file " + file, mProfile, profile);
}
} else {
- assertEquals(mProfile, format.getInteger(MediaFormat.KEY_PROFILE));
- assertEquals(mLevel, format.getInteger(MediaFormat.KEY_LEVEL));
+ int profile = format.getInteger(MediaFormat.KEY_PROFILE, -1);
+ assertEquals("mismatched KEY_PROFILE in file " + file, mProfile, profile);
+ int level = format.getInteger(MediaFormat.KEY_LEVEL, -1);
+ assertEquals("mismatched KEY_LEVEL in file " + file, mLevel, level);
}
if (mMime.startsWith("audio/")) {
- assertEquals(mWR, format.getInteger(MediaFormat.KEY_SAMPLE_RATE));
- assertEquals(mHCh, format.getInteger(MediaFormat.KEY_CHANNEL_COUNT));
+ int sample_rate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE, -1);
+ assertEquals("mismatched KEY_SAMPLE_RATE in file " + file,
+ mWR, sample_rate);
+ int channel_count = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT, -1);
+ assertEquals("mismatched KEY_CHANNEL_COUNT in file " + file,
+ mHCh, channel_count);
} else if (mMime.startsWith("video/")) {
- assertEquals(mWR, format.getInteger(MediaFormat.KEY_WIDTH));
- assertEquals(mHCh, format.getInteger(MediaFormat.KEY_HEIGHT));
+ int width = format.getInteger(MediaFormat.KEY_WIDTH, -1);
+ assertEquals("mismatched KEY_WIDTH in file " + file, mWR, width);
+ int height = format.getInteger(MediaFormat.KEY_HEIGHT, -1);
+ assertEquals("mismatched KEY_HEIGHT in file " + file, mHCh, height);
}
}
}
diff --git a/tests/mediapc/AndroidTest.xml b/tests/mediapc/AndroidTest.xml
index 904368d..dcc8995 100644
--- a/tests/mediapc/AndroidTest.xml
+++ b/tests/mediapc/AndroidTest.xml
@@ -26,7 +26,7 @@
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
- <option name="media-folder-name" value="CtsMediaPerformanceClassTestCases-1.1" />
+ <option name="media-folder-name" value="CtsMediaPerformanceClassTestCases-1.2" />
<option name="dynamic-config-module" value="CtsMediaPerformanceClassTestCases" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/mediapc/DynamicConfig.xml b/tests/mediapc/DynamicConfig.xml
index 973305e..d7ba901 100644
--- a/tests/mediapc/DynamicConfig.xml
+++ b/tests/mediapc/DynamicConfig.xml
@@ -1,6 +1,6 @@
<dynamicConfig>
<entry key="media_files_url">
- <value>https://storage.googleapis.com/android_media/cts/tests/mediapc/CtsMediaPerformanceClassTestCases-1.1.zip</value>
+ <value>https://storage.googleapis.com/android_media/cts/tests/mediapc/CtsMediaPerformanceClassTestCases-1.2.zip</value>
</entry>
</dynamicConfig>
diff --git a/tests/mediapc/README.md b/tests/mediapc/README.md
index 1cb0ec5..f21aeb9 100644
--- a/tests/mediapc/README.md
+++ b/tests/mediapc/README.md
@@ -1,7 +1,7 @@
## Media Performance Class CTS Tests
Current folder comprises of files necessary for testing media performance class.
-The test vectors used by the test suite is available at [link](https://storage.googleapis.com/android_media/cts/tests/mediapc/CtsMediaPerformanceClassTestCases-1.1.zip) and is downloaded automatically while running tests. Manual installation of these can be done using copy_media.sh script in this directory.
+The test vectors used by the test suite is available at [link](https://storage.googleapis.com/android_media/cts/tests/mediapc/CtsMediaPerformanceClassTestCases-1.2.zip) and is downloaded automatically while running tests. Manual installation of these can be done using copy_media.sh script in this directory.
### Commands
```sh
diff --git a/tests/mediapc/copy_media.sh b/tests/mediapc/copy_media.sh
index 20437d1..054fe76 100644
--- a/tests/mediapc/copy_media.sh
+++ b/tests/mediapc/copy_media.sh
@@ -17,7 +17,7 @@
## script to install media performance class test files manually
adbOptions=" "
-resLabel=CtsMediaPerformanceClassTestCases-1.1
+resLabel=CtsMediaPerformanceClassTestCases-1.2
srcDir="/tmp/$resLabel"
tgtDir="/sdcard/test"
usage="Usage: $0 [-h] [-s serial]"
diff --git a/tests/mediapc/src/android/mediapc/cts/CodecTestBase.java b/tests/mediapc/src/android/mediapc/cts/CodecTestBase.java
index ecc8c3a..c6a0c60 100644
--- a/tests/mediapc/src/android/mediapc/cts/CodecTestBase.java
+++ b/tests/mediapc/src/android/mediapc/cts/CodecTestBase.java
@@ -16,6 +16,11 @@
package android.mediapc.cts;
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import android.graphics.ImageFormat;
import android.media.Image;
import android.media.MediaCodec;
@@ -43,11 +48,6 @@
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
-import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
class CodecAsyncHandler extends MediaCodec.Callback {
private static final String LOG_TAG = CodecAsyncHandler.class.getSimpleName();
private final Lock mLock = new ReentrantLock();
@@ -729,28 +729,33 @@
/**
* The following class encodes a YUV video file to a given mimeType using encoder created by the
- * given encoderName and configuring to 720p 30fps format.
+ * given encoderName and configuring to 30fps format.
*/
class Encode extends CodecEncoderTestBase implements Callable<Double> {
private static final String LOG_TAG = Encode.class.getSimpleName();
private final String mEncoderName;
private final boolean mIsAsync;
+ private final int mBitrate;
- Encode(String mime, String encoderName, boolean isAsync) {
+ Encode(String mime, String encoderName, boolean isAsync, int height, int width, int frameRate,
+ int bitrate) {
super(mime);
mEncoderName = encoderName;
mIsAsync = isAsync;
mSurface = MediaCodec.createPersistentInputSurface();
- mFrameRate = 30;
+ mFrameRate = frameRate;
+ mBitrate = bitrate;
+ mHeight = height;
+ mWidth = width;
}
private MediaFormat setUpFormat() {
MediaFormat format = new MediaFormat();
format.setString(MediaFormat.KEY_MIME, mMime);
- format.setInteger(MediaFormat.KEY_BIT_RATE, 4000000);
- format.setInteger(MediaFormat.KEY_WIDTH, 1280);
- format.setInteger(MediaFormat.KEY_HEIGHT, 720);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrate);
+ format.setInteger(MediaFormat.KEY_WIDTH, mWidth);
+ format.setInteger(MediaFormat.KEY_HEIGHT, mHeight);
format.setInteger(MediaFormat.KEY_FRAME_RATE, mFrameRate);
format.setInteger(MediaFormat.KEY_MAX_B_FRAMES, 0);
format.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 1.0f);
diff --git a/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java b/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java
index 6a2372f..9168e24 100644
--- a/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java
@@ -16,6 +16,13 @@
package android.mediapc.cts;
+import static android.mediapc.cts.CodecTestBase.selectCodecs;
+import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
import android.app.Instrumentation;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -34,9 +41,6 @@
import androidx.test.rule.ActivityTestRule;
import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.ReportLog;
-import com.android.compatibility.common.util.ReportLog.Metric;
-
import com.android.compatibility.common.util.DeviceReportLog;
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
@@ -55,13 +59,6 @@
import java.util.Collection;
import java.util.List;
-import static android.mediapc.cts.CodecTestBase.selectCodecs;
-import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
-
/**
* The following test class validates the codec initialization latency (time for codec create +
* configure) for the audio encoders and hardware video encoders available in the device, under the
@@ -75,6 +72,8 @@
private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_R_MS = 65;
private static final int MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_S_MS = 40;
private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_S_MS = 50;
+ private static final int MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_T_MS = 30;
+ private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_T_MS = 40;
private static final int MAX_AUDIOENC_INITIALIZATION_LATENCY_MS;
private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_MS;
@@ -88,10 +87,13 @@
if (Utils.isRPerfClass()) {
MAX_AUDIOENC_INITIALIZATION_LATENCY_MS = MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_R_MS;
MAX_VIDEOENC_INITIALIZATION_LATENCY_MS = MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_R_MS;
- } else {
- // Performance class Build.VERSION_CODES.S and beyond
+ } else if (Utils.isSPerfClass()) {
MAX_AUDIOENC_INITIALIZATION_LATENCY_MS = MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_S_MS;
MAX_VIDEOENC_INITIALIZATION_LATENCY_MS = MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_S_MS;
+ } else {
+ // Performance class Build.VERSION_CODES.TIRAMISU and beyond
+ MAX_AUDIOENC_INITIALIZATION_LATENCY_MS = MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_T_MS;
+ MAX_VIDEOENC_INITIALIZATION_LATENCY_MS = MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_T_MS;
}
}
@@ -109,7 +111,7 @@
public void setUp() throws Exception {
Utils.assumeDeviceMeetsPerformanceClassPreconditions();
- ArrayList<String> listOfAvcHwDecoders = selectHardwareCodecs(AVC, null, null, false);
+ ArrayList<String> listOfAvcHwDecoders = selectHardwareCodecs(AVC, null, null, false);
assumeFalse("Test requires h/w avc decoder", listOfAvcHwDecoders.isEmpty());
AVC_DECODER_NAME = listOfAvcHwDecoders.get(0);
@@ -196,14 +198,15 @@
listOfEncoders = selectHardwareCodecs(mime, null, null, true);
}
for (String encoder : listOfEncoders) {
- argsList.add(new Object[] {mime, encoder});
+ argsList.add(new Object[]{mime, encoder});
}
}
return argsList;
}
private MediaRecorder createMediaRecorderLoad(Surface surface) throws Exception {
- MediaRecorder mediaRecorder = new MediaRecorder();
+ MediaRecorder mediaRecorder = new MediaRecorder(InstrumentationRegistry.getInstrumentation()
+ .getContext());
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
@@ -259,7 +262,7 @@
mMediaRecorderLoad.stop();
mMediaRecorderLoad.release();
mMediaRecorderLoad = null;
- if(mTempRecordedFile != null && mTempRecordedFile.exists()) {
+ if (mTempRecordedFile != null && mTempRecordedFile.exists()) {
mTempRecordedFile.delete();
mTempRecordedFile = null;
}
@@ -290,7 +293,7 @@
*/
@LargeTest
@Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
- @CddTest(requirement="2.2.7.1/5.1/H-1-7,H-1-8")
+ @CddTest(requirement = "2.2.7.1/5.1/H-1-7,H-1-8")
public void testInitializationLatency() throws Exception {
final int NUM_MEASUREMENTS = 5;
// Test gathers initialization latency for a number of iterations and
@@ -328,17 +331,21 @@
expectedMaxCodecInitializationLatencyMs);
assertTrue(errorLog, initializationLatency <= expectedMaxCodecInitializationLatencyMs);
} else {
- int pc = 0;
+ int pc;
if (mMime.startsWith("audio/")) {
- pc = initializationLatency < MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_S_MS
- ? Build.VERSION_CODES.S
- : initializationLatency < MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_R_MS
- ? Build.VERSION_CODES.R : 0;
+ pc = initializationLatency < MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_T_MS ?
+ Build.VERSION_CODES.TIRAMISU :
+ initializationLatency < MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_S_MS ?
+ Build.VERSION_CODES.S : initializationLatency <
+ MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_R_MS ?
+ Build.VERSION_CODES.R : 0;
} else {
- pc = initializationLatency < MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_S_MS
- ? Build.VERSION_CODES.S
- : initializationLatency < MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_R_MS
- ? Build.VERSION_CODES.R : 0;
+ pc = initializationLatency < MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_T_MS ?
+ Build.VERSION_CODES.TIRAMISU :
+ initializationLatency < MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_S_MS ?
+ Build.VERSION_CODES.S : initializationLatency <
+ MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_R_MS ?
+ Build.VERSION_CODES.R : 0;
}
DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
"InitializationLatency_" + mEncoderName);
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java b/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java
index 07ee73a..a140c30 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java
@@ -16,12 +16,16 @@
package android.mediapc.cts;
+import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
+import static org.junit.Assert.assertTrue;
+
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint;
import android.media.MediaFormat;
-import android.util.Pair;
import android.util.Log;
+import android.util.Pair;
+
import org.junit.Before;
import java.io.IOException;
@@ -31,10 +35,6 @@
import java.util.List;
import java.util.Map;
-import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
-
public class MultiCodecPerfTestBase {
private static final String LOG_TAG = MultiCodecPerfTestBase.class.getSimpleName();
static final boolean[] boolStates = {true, false};
@@ -44,22 +44,24 @@
// that is greater than (FPS_TOLERANCE_FACTOR * expectedFps) will be considered as
// passing the test
static final double FPS_TOLERANCE_FACTOR = 0.95;
- static ArrayList<String> mMimeList = new ArrayList<String>();
+ static ArrayList<String> mMimeList = new ArrayList<>();
static Map<String, String> mTestFiles = new HashMap<>();
+ static Map<String, String> m720pTestFiles = new HashMap<>();
+
static {
mMimeList.add(MediaFormat.MIMETYPE_VIDEO_AVC);
mMimeList.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
- mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1280x720_3mbps_30fps_avc.mp4");
- mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_1280x720_3mbps_30fps_hevc.mp4");
+ m720pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1280x720_3mbps_30fps_avc.mp4");
+ m720pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_1280x720_3mbps_30fps_hevc.mp4");
// Test VP9 and AV1 as well for Build.VERSION_CODES.S
if (Utils.isSPerfClass()) {
mMimeList.add(MediaFormat.MIMETYPE_VIDEO_VP9);
mMimeList.add(MediaFormat.MIMETYPE_VIDEO_AV1);
- mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_1280x720_3mbps_30fps_vp9.webm");
- mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_1280x720_3mbps_30fps_av1.mp4");
+ m720pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_1280x720_3mbps_30fps_vp9.webm");
+ m720pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_1280x720_3mbps_30fps_av1.mp4");
}
}
@@ -80,18 +82,14 @@
mIsAsync = isAsync;
}
- // Returns the list of hardware codecs supporting the 720p 30fps format.
- public static ArrayList<String> getHardwareCodecsFor720p(String mime, boolean isEncoder) {
- MediaFormat fmt = MediaFormat.createVideoFormat(mime, 1280, 720);
- fmt.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
- ArrayList<MediaFormat> formatsList = new ArrayList<>();
- formatsList.add(fmt);
- return selectHardwareCodecs(mime, formatsList, null, isEncoder);
+ // Returns the list of hardware codecs for given mime
+ public static ArrayList<String> getHardwareCodecsForMime(String mime, boolean isEncoder) {
+ return selectHardwareCodecs(mime, null, null, isEncoder);
}
- // Returns the max number of 720p 30 fps instances that the given list of mimeCodecPairs
- // supports. It also checks that the each codec supports 720p 180 fps PerformancePoint.
- public int checkAndGetMaxSupportedInstancesFor720p(
+ // Returns the max number of 30 fps instances that the given list of mimeCodecPairs
+ // supports. It also checks that the each codec supports 180 fps PerformancePoint.
+ public int checkAndGetMaxSupportedInstancesForCodecCombinations(int height, int width,
ArrayList<Pair<String, String>> mimeCodecPairs) throws IOException {
int[] maxInstances = new int[mimeCodecPairs.size()];
int[] maxFrameRates = new int[mimeCodecPairs.size()];
@@ -104,20 +102,17 @@
List<PerformancePoint> pps = cap.getVideoCapabilities().getSupportedPerformancePoints();
assertTrue(pps.size() > 0);
- int requiredFrameRate = 180;
- // VP9 requires 60 fps at 720p and minimum of 2 instances
- if (mimeCodecPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
- requiredFrameRate = 60;
- }
+ boolean hasVP9 = mimeCodecPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
+ int requiredFrameRate = getRequiredMinConcurrentInstances(hasVP9) * 30;
maxInstances[loopCount] = cap.getMaxSupportedInstances();
- PerformancePoint PP720p = new PerformancePoint(1280, 720, requiredFrameRate);
+ PerformancePoint PPRes = new PerformancePoint(width, height, requiredFrameRate);
maxMacroBlockRates[loopCount] = 0;
- boolean supports720pPerformance = false;
+ boolean supportsResolutionPerformance = false;
for (PerformancePoint pp : pps) {
- if (pp.covers(PP720p)) {
- supports720pPerformance = true;
+ if (pp.covers(PPRes)) {
+ supportsResolutionPerformance = true;
if (pp.getMaxMacroBlockRate() > maxMacroBlockRates[loopCount]) {
maxMacroBlockRates[loopCount] = (int) pp.getMaxMacroBlockRate();
maxFrameRates[loopCount] = pp.getMaxFrameRate();
@@ -125,9 +120,10 @@
}
}
codec.release();
- if (!supports720pPerformance) {
- Log.e(LOG_TAG, "Codec " + mimeCodecPair.second + " doesn't support 720p " +
- requiredFrameRate + " performance point");
+ if (!supportsResolutionPerformance) {
+ Log.e(LOG_TAG,
+ "Codec " + mimeCodecPair.second + " doesn't support " + height + "p/" +
+ requiredFrameRate + " performance point");
return 0;
}
loopCount++;
@@ -142,9 +138,17 @@
// Allow a tolerance in expected frame rate
mMaxFrameRate = minOfMaxFrameRates * FPS_TOLERANCE_FACTOR;
- // Calculate how many 720p 30fps max instances it can support from it's mMaxFrameRate
- // amd maxMacroBlockRate. (720p is 3,600 macro blocks assuming 16x16 macroblocks)
+ // Calculate how many 30fps max instances it can support from it's mMaxFrameRate
+ // amd maxMacroBlockRate. (assuming 16x16 macroblocks)
return Math.min(minOfMaxInstances, Math.min((int) (minOfMaxFrameRates / 30.0),
- (int) (minOfMaxMacroBlockRates / 3600.0 / 30)));
+ (int) (minOfMaxMacroBlockRates / ((width / 16) * (height / 16)) / 30.0)));
+ }
+
+ public int getRequiredMinConcurrentInstances(boolean hasVP9) {
+ // Below T, VP9 requires 60 fps at 720p and minimum of 2 instances
+ if (!Utils.isTPerfClass() && hasVP9) {
+ return REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9;
+ }
+ return REQUIRED_MIN_CONCURRENT_INSTANCES;
}
}
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java
index bff0793..4899f83 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java
@@ -16,6 +16,8 @@
package android.mediapc.cts;
+import static org.junit.Assert.assertTrue;
+
import android.media.MediaFormat;
import android.os.Build;
import android.util.Pair;
@@ -28,6 +30,7 @@
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
+import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -35,12 +38,11 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
-import static org.junit.Assert.assertTrue;
-
/**
* The following test class calculates the maximum number of concurrent decode sessions that it can
* support by the two hardware (mime - decoder) pair calculated via the
@@ -71,7 +73,7 @@
final List<Object[]> argsList = new ArrayList<>();
ArrayList<Pair<String, String>> mimeTypeDecoderPairs = new ArrayList<>();
for (String mime : mMimeList) {
- ArrayList<String> listOfDecoders = getHardwareCodecsFor720p(mime, false);
+ ArrayList<String> listOfDecoders = getHardwareCodecsForMime(mime, false);
for (String decoder : listOfDecoders) {
mimeTypeDecoderPairs.add(Pair.create(mime, decoder));
}
@@ -96,17 +98,24 @@
*/
@LargeTest
@Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
- @CddTest(requirement="2.2.7.1/5.1/H-1-1,H-1-2")
+ @CddTest(requirement = "2.2.7.1/5.1/H-1-1,H-1-2")
public void test720p() throws Exception {
+ Assume.assumeTrue(Utils.isSPerfClass() || Utils.isRPerfClass() || !Utils.isPerfClass());
+
+ boolean hasVP9 = mFirstPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9) ||
+ mSecondPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
+ int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9);
+ testCodec(m720pTestFiles, 720, 1280, requiredMinInstances);
+ }
+
+ private void testCodec(Map<String, String> testFiles, int height, int width,
+ int requiredMinInstances) throws Exception {
+ mTestFiles = testFiles;
ArrayList<Pair<String, String>> mimeDecoderPairs = new ArrayList<>();
mimeDecoderPairs.add(mFirstPair);
mimeDecoderPairs.add(mSecondPair);
- int maxInstances = checkAndGetMaxSupportedInstancesFor720p(mimeDecoderPairs);
- int requiredMinInstances = REQUIRED_MIN_CONCURRENT_INSTANCES;
- if (mFirstPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9)
- || mSecondPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
- requiredMinInstances = REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9;
- }
+ int maxInstances = checkAndGetMaxSupportedInstancesForCodecCombinations(height, width,
+ mimeDecoderPairs);
double achievedFrameRate = 0.0;
if (maxInstances >= requiredMinInstances) {
int secondPairInstances = maxInstances / 2;
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java
index 3e3881b..cbdd391 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java
@@ -15,6 +15,9 @@
*/
package android.mediapc.cts;
+
+import static org.junit.Assert.assertTrue;
+
import android.media.MediaFormat;
import android.os.Build;
import android.util.Pair;
@@ -27,6 +30,7 @@
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
+import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -34,12 +38,11 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
-import static org.junit.Assert.assertTrue;
-
/**
* The following test class validates the maximum number of concurrent decode sessions that it can
* support by the hardware decoders calculated via the CodecCapabilities.getMaxSupportedInstances()
@@ -52,23 +55,22 @@
private final String mDecoderName;
- public MultiDecoderPerfTest(String mimeType, String testFile, String decoderName,
- boolean isAsync) {
- super(mimeType, testFile, isAsync);
+ public MultiDecoderPerfTest(String mimeType, String decoderName, boolean isAsync) {
+ super(mimeType, null, isAsync);
mDecoderName = decoderName;
}
- // Returns the params list with the mime, testFile and their hardware decoders in
+ // Returns the params list with the mime and corresponding hardware decoders in
// both sync and async modes.
- // Parameters {0}_{2}_{3} -- Mime_DecoderName_isAsync
- @Parameterized.Parameters(name = "{index}({0}_{2}_{3})")
+ // Parameters {0}_{1}_{2} -- Mime_DecoderName_isAsync
+ @Parameterized.Parameters(name = "{index}({0}_{1}_{2})")
public static Collection<Object[]> inputParams() {
final List<Object[]> argsList = new ArrayList<>();
for (String mime : mMimeList) {
- ArrayList<String> listOfDecoders = getHardwareCodecsFor720p(mime, false);
+ ArrayList<String> listOfDecoders = getHardwareCodecsForMime(mime, false);
for (String decoder : listOfDecoders) {
for (boolean isAsync : boolStates) {
- argsList.add(new Object[]{mime, mTestFiles.get(mime), decoder, isAsync});
+ argsList.add(new Object[]{mime, decoder, isAsync});
}
}
}
@@ -82,15 +84,23 @@
*/
@LargeTest
@Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
- @CddTest(requirement="2.2.7.1/5.1/H-1-1,H-1-2")
+ @CddTest(requirement = "2.2.7.1/5.1/H-1-1,H-1-2")
public void test720p() throws Exception {
+ Assume.assumeTrue(Utils.isSPerfClass() || Utils.isRPerfClass() || !Utils.isPerfClass());
+
+ boolean hasVP9 = mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
+ int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9);
+ testCodec(m720pTestFiles, 720, 1280, requiredMinInstances);
+ }
+
+ private void testCodec(Map<String, String> testFiles, int height, int width,
+ int requiredMinInstances) throws Exception {
+ mTestFile = testFiles.get(mMime);
ArrayList<Pair<String, String>> mimeDecoderPairs = new ArrayList<>();
mimeDecoderPairs.add(Pair.create(mMime, mDecoderName));
- int maxInstances = checkAndGetMaxSupportedInstancesFor720p(mimeDecoderPairs);
- int requiredMinInstances = REQUIRED_MIN_CONCURRENT_INSTANCES;
- if (mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
- requiredMinInstances = REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9;
- }
+ int maxInstances =
+ checkAndGetMaxSupportedInstancesForCodecCombinations(height, width,
+ mimeDecoderPairs);
double achievedFrameRate = 0.0;
if (maxInstances >= requiredMinInstances) {
ExecutorService pool = Executors.newFixedThreadPool(maxInstances);
@@ -124,6 +134,5 @@
ResultUnit.NONE);
log.submit(InstrumentationRegistry.getInstrumentation());
}
-
}
}
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java
index 4cd2a0c..b9cc45d 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java
@@ -16,8 +16,11 @@
package android.mediapc.cts;
+import static org.junit.Assert.assertTrue;
+
import android.media.MediaFormat;
import android.os.Build;
+import android.util.Log;
import android.util.Pair;
import androidx.test.filters.LargeTest;
@@ -27,6 +30,8 @@
import com.android.compatibility.common.util.DeviceReportLog;
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
+
+import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -38,7 +43,6 @@
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
-import static org.junit.Assert.assertTrue;
/**
* The following test class calculates the maximum number of concurrent encode sessions that it can
* support by the two hardware (mime - encoder) pair calculated via the
@@ -69,7 +73,7 @@
final List<Object[]> argsList = new ArrayList<>();
ArrayList<Pair<String, String>> mimeTypeEncoderPairs = new ArrayList<>();
for (String mime : mMimeList) {
- ArrayList<String> listOfEncoders = getHardwareCodecsFor720p(mime, true);
+ ArrayList<String> listOfEncoders = getHardwareCodecsForMime(mime, true);
for (String encoder : listOfEncoders) {
mimeTypeEncoderPairs.add(Pair.create(mime, encoder));
}
@@ -94,39 +98,50 @@
*/
@LargeTest
@Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
- @CddTest(requirement="2.2.7.1/5.1/H-1-3,H-1-4")
+ @CddTest(requirement = "2.2.7.1/5.1/H-1-3,H-1-4")
public void test720p() throws Exception {
+ Assume.assumeTrue(Utils.isSPerfClass() || Utils.isRPerfClass() || !Utils.isPerfClass());
+
+ boolean hasVP9 = mFirstPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9) ||
+ mSecondPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
+ int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9);
+ testCodec(720, 1280, 4000000, requiredMinInstances);
+ }
+
+ private void testCodec(int height, int width, int bitrate, int requiredMinInstances)
+ throws Exception {
ArrayList<Pair<String, String>> mimeEncoderPairs = new ArrayList<>();
mimeEncoderPairs.add(mFirstPair);
mimeEncoderPairs.add(mSecondPair);
- int maxInstances = checkAndGetMaxSupportedInstancesFor720p(mimeEncoderPairs);
- int requiredMinInstances = REQUIRED_MIN_CONCURRENT_INSTANCES;
- if (mFirstPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9)
- || mSecondPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
- requiredMinInstances = REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9;
- }
+ int maxInstances = checkAndGetMaxSupportedInstancesForCodecCombinations(height, width,
+ mimeEncoderPairs);
+ double achievedFrameRate = 0.0;
if (maxInstances >= requiredMinInstances) {
int secondPairInstances = maxInstances / 2;
int firstPairInstances = maxInstances - secondPairInstances;
ExecutorService pool = Executors.newFixedThreadPool(maxInstances);
List<Encode> testList = new ArrayList<>();
for (int i = 0; i < firstPairInstances; i++) {
- testList.add(new Encode(mFirstPair.first, mFirstPair.second, mIsAsync));
+ testList.add(
+ new Encode(mFirstPair.first, mFirstPair.second, mIsAsync, height, width, 30,
+ bitrate));
}
for (int i = 0; i < secondPairInstances; i++) {
- testList.add(new Encode(mSecondPair.first, mSecondPair.second, mIsAsync));
+ testList.add(
+ new Encode(mSecondPair.first, mSecondPair.second, mIsAsync, height, width,
+ 30, bitrate));
}
List<Future<Double>> resultList = pool.invokeAll(testList);
- double achievedFrameRate = 0.0;
for (Future<Double> result : resultList) {
achievedFrameRate += result.get();
}
}
- // Achieved frame rate is not compared as this test runs in byte buffer mode.
if (Utils.isPerfClass()) {
assertTrue("Encoder pair " + mFirstPair.second + " and " + mSecondPair.second
+ " unable to support minimum concurrent instances. act/exp: " + maxInstances
+ "/" + requiredMinInstances, maxInstances >= requiredMinInstances);
+ Log.v(LOG_TAG, "Achieved fps: " + achievedFrameRate +
+ "\nAchieved frame rate is not compared as this test runs in byte buffer mode");
} else {
int pc = maxInstances >= requiredMinInstances ? Build.VERSION_CODES.R : 0;
DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java
index f45c411..79a684e 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java
@@ -15,8 +15,12 @@
*/
package android.mediapc.cts;
+
+import static org.junit.Assert.assertTrue;
+
import android.media.MediaFormat;
import android.os.Build;
+import android.util.Log;
import android.util.Pair;
import androidx.test.filters.LargeTest;
@@ -27,6 +31,7 @@
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
+import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -38,8 +43,6 @@
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
-import static org.junit.Assert.assertTrue;
-
/**
* The following test class validates the maximum number of concurrent encode sessions that it can
* support by the hardware encoders calculated via the CodecCapabilities.getMaxSupportedInstances()
@@ -65,7 +68,7 @@
public static Collection<Object[]> inputParams() {
final List<Object[]> argsList = new ArrayList<>();
for (String mime : mMimeList) {
- ArrayList<String> listOfEncoders = getHardwareCodecsFor720p(mime, true);
+ ArrayList<String> listOfEncoders = getHardwareCodecsForMime(mime, true);
for (String encoder : listOfEncoders) {
for (boolean isAsync : boolStates) {
argsList.add(new Object[]{mime, encoder, isAsync});
@@ -81,23 +84,29 @@
*/
@LargeTest
@Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
- @CddTest(requirement="2.2.7.1/5.1/H-1-3,H-1-4")
+ @CddTest(requirement = "2.2.7.1/5.1/H-1-3,H-1-4")
public void test720p() throws Exception {
+ Assume.assumeTrue(Utils.isSPerfClass() || Utils.isRPerfClass() || !Utils.isPerfClass());
+
+ boolean hasVP9 = mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
+ int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9);
+ testCodec(720, 1280, 4000000, requiredMinInstances);
+ }
+
+ private void testCodec(int height, int width, int bitrate, int requiredMinInstances)
+ throws Exception {
ArrayList<Pair<String, String>> mimeEncoderPairs = new ArrayList<>();
mimeEncoderPairs.add(Pair.create(mMime, mEncoderName));
- int maxInstances = checkAndGetMaxSupportedInstancesFor720p(mimeEncoderPairs);
- int requiredMinInstances = REQUIRED_MIN_CONCURRENT_INSTANCES;
- if (mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
- requiredMinInstances = REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9;
- }
+ int maxInstances = checkAndGetMaxSupportedInstancesForCodecCombinations(height, width,
+ mimeEncoderPairs);
+ double achievedFrameRate = 0.0;
if (maxInstances >= requiredMinInstances) {
ExecutorService pool = Executors.newFixedThreadPool(maxInstances);
List<Encode> testList = new ArrayList<>();
for (int i = 0; i < maxInstances; i++) {
- testList.add(new Encode(mMime, mEncoderName, mIsAsync));
+ testList.add(new Encode(mMime, mEncoderName, mIsAsync, height, width, 30, bitrate));
}
List<Future<Double>> resultList = pool.invokeAll(testList);
- double achievedFrameRate = 0.0;
for (Future<Double> result : resultList) {
achievedFrameRate += result.get();
}
@@ -107,6 +116,8 @@
assertTrue("Encoder " + mEncoderName + " unable to support minimum concurrent " +
"instances. act/exp: " + maxInstances + "/" + requiredMinInstances,
maxInstances >= requiredMinInstances);
+ Log.v(LOG_TAG, "Achieved fps: " + achievedFrameRate +
+ "\nAchieved frame rate is not compared as this test runs in byte buffer mode");
} else {
int pc = maxInstances >= requiredMinInstances ? Build.VERSION_CODES.R : 0;
DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java
index 29c8dcb..98c3183 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java
@@ -15,20 +15,24 @@
*/
package android.mediapc.cts;
+
+import static org.junit.Assert.assertTrue;
+
import android.media.MediaFormat;
import android.os.Build;
import android.util.Pair;
import android.view.Surface;
import androidx.test.filters.LargeTest;
-import androidx.test.rule.ActivityTestRule;
import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
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;
+import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -37,12 +41,11 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
-import static org.junit.Assert.assertTrue;
-
/**
* The following test class validates the maximum number of concurrent Transcode sessions that
* it can support by the (mime, decoder - mime, encoder) pair calculated via the
@@ -77,11 +80,11 @@
ArrayList<Pair<String, String>> mimeTypeDecoderPairs = new ArrayList<>();
ArrayList<Pair<String, String>> mimeTypeEncoderPairs = new ArrayList<>();
for (String mime : mMimeList) {
- ArrayList<String> listOfDecoders = getHardwareCodecsFor720p(mime, false);
+ ArrayList<String> listOfDecoders = getHardwareCodecsForMime(mime, false);
for (String decoder : listOfDecoders) {
mimeTypeDecoderPairs.add(Pair.create(mime, decoder));
}
- ArrayList<String> listOfEncoders = getHardwareCodecsFor720p(mime, true);
+ ArrayList<String> listOfEncoders = getHardwareCodecsForMime(mime, true);
for (String encoder : listOfEncoders) {
mimeTypeEncoderPairs.add(Pair.create(mime, encoder));
}
@@ -97,7 +100,7 @@
}
/**
- * This test calculates the validates number of concurrent Transcode sessions that
+ * This test calculates the validates number of concurrent 720p Transcode sessions that
* it can support by the (mime, decoder - mime, encoder) pairs. Creates maxInstances / 2
* Transcode sessions. If maximum instances is odd, creates one additional decoder which decodes
* to surface and render. And ensures that all the supported sessions succeed in
@@ -105,25 +108,32 @@
*/
@LargeTest
@Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
- @CddTest(requirement="2.2.7.1/5.1/H-1-5,H-1-6")
+ @CddTest(requirement = "2.2.7.1/5.1/H-1-5,H-1-6")
public void test720p() throws Exception {
+ Assume.assumeTrue(Utils.isSPerfClass() || Utils.isRPerfClass() || !Utils.isPerfClass());
+
+ boolean hasVP9 = mDecoderPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9)
+ || mEncoderPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
+ int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9) / 2;
+ testCodec(m720pTestFiles, 720, 1280, requiredMinInstances);
+ }
+
+ private void testCodec(Map<String, String> testFiles, int height, int width,
+ int requiredMinInstances) throws Exception {
+ mTestFiles = testFiles;
ArrayList<Pair<String, String>> mimeCodecPairs = new ArrayList<>();
mimeCodecPairs.add(mDecoderPair);
mimeCodecPairs.add(mEncoderPair);
- int maxInstances = checkAndGetMaxSupportedInstancesFor720p(mimeCodecPairs);
- int requiredMinInstances = REQUIRED_MIN_CONCURRENT_INSTANCES / 2;
- if (mDecoderPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9)
- || mEncoderPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
- requiredMinInstances = REQUIRED_MIN_CONCURRENT_INSTANCES_FOR_VP9 / 2;
- }
+ int maxInstances =
+ checkAndGetMaxSupportedInstancesForCodecCombinations(height, width, mimeCodecPairs);
double achievedFrameRate = 0.0;
if (maxInstances >= requiredMinInstances) {
- ExecutorService pool = Executors.newFixedThreadPool(
- maxInstances / 2 + maxInstances % 2);
+ ExecutorService pool =
+ Executors.newFixedThreadPool(maxInstances / 2 + maxInstances % 2);
List<Transcode> transcodeList = new ArrayList<>();
for (int i = 0; i < maxInstances / 2; i++) {
- transcodeList.add(
- new Transcode(mEncoderPair.first, mTestFiles.get(mDecoderPair.first),
+ transcodeList
+ .add(new Transcode(mEncoderPair.first, mTestFiles.get(mDecoderPair.first),
mDecoderPair.second, mEncoderPair.second, mIsAsync));
}
List<Future<Double>> decodeResultList = null;
@@ -133,7 +143,7 @@
Surface surface = mActivityRule.getActivity().getSurface();
assertTrue("Surface created is null.", surface != null);
assertTrue("Surface created is invalid.", surface.isValid());
- mActivityRule.getActivity().setScreenParams(1280, 720, true);
+ mActivityRule.getActivity().setScreenParams(width, height, true);
decodeList.add(new DecodeToSurface(mDecoderPair.first,
mTestFiles.get(mDecoderPair.first), mDecoderPair.second, surface,
mIsAsync));
@@ -173,6 +183,5 @@
ResultUnit.NONE);
log.submit(InstrumentationRegistry.getInstrumentation());
}
-
}
}
diff --git a/tests/mediapc/src/android/mediapc/cts/WorkDir.java b/tests/mediapc/src/android/mediapc/cts/WorkDir.java
index d45c14b..cd5ad7e 100644
--- a/tests/mediapc/src/android/mediapc/cts/WorkDir.java
+++ b/tests/mediapc/src/android/mediapc/cts/WorkDir.java
@@ -40,7 +40,7 @@
// user has specified the mediaDirString via instrumentation-arg
return mediaDirString + ((mediaDirString.endsWith("/")) ? "" : "/");
} else {
- return (getTopDirString() + "test/CtsMediaPerformanceClassTestCases-1.1/");
+ return (getTopDirString() + "test/CtsMediaPerformanceClassTestCases-1.2/");
}
}
}
diff --git a/tests/sensor/src/android/hardware/cts/SensorTest.java b/tests/sensor/src/android/hardware/cts/SensorTest.java
index e4f4613..c73f581 100644
--- a/tests/sensor/src/android/hardware/cts/SensorTest.java
+++ b/tests/sensor/src/android/hardware/cts/SensorTest.java
@@ -242,15 +242,23 @@
sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_HEADING);
boolean hasHeadingSensor = getContext().getPackageManager().hasSystemFeature(
PackageManager.FEATURE_SENSOR_HEADING);
- if (hasHeadingSensor) {
+ boolean isAutomotive = mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE);
+ if (isAutomotive && hasHeadingSensor) {
assertNotNull(sensor);
assertEquals(Sensor.TYPE_HEADING, sensor.getType());
assertSensorValues(sensor);
assertTrue("Max range must not be greater or equal to 360. Range="
+ sensor.getMaximumRange() + " " + sensor.getName(),
sensor.getMaximumRange() < 360);
- } else {
+ } else if (isAutomotive) {
assertNull(sensor);
+ } else {
+ // There isn't good test coverage for heading, particularly for non-automotive devices.
+ // So if a non-automotive device wants to implement this, requirements for the sensor
+ // and how to test for those requirements should be re-discussed.
+ assertNull("If the heading sensor is being implemented on a non-automotive device, "
+ + "the team would love to hear from you. Please reach out!", sensor);
}
}
@@ -268,41 +276,6 @@
}
}
- public void testLimitedAxesImuConfiguration() {
- boolean hasAccelerometer = getContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_SENSOR_ACCELEROMETER);
- boolean hasLimitedAxesAccelerometer = getContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_SENSOR_ACCELEROMETER_LIMITED_AXES);
- boolean hasLimitedAxesAccelerometerUncalibrated =
- getContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_SENSOR_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED);
-
- // Only the 3-axis accelerometer or the limited axes accelerometer should be implemented
- // by the system at the same time. The composite sensors for limited axes accelerometer can
- // still be present when a 3-axis accelerometer is supported.
- if (hasAccelerometer) {
- assertFalse(hasLimitedAxesAccelerometer);
- assertFalse(hasLimitedAxesAccelerometerUncalibrated);
- }
-
- boolean hasGyroscope = getContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_SENSOR_GYROSCOPE);
- boolean hasLimitedAxesGyroscope = getContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_SENSOR_GYROSCOPE_LIMITED_AXES);
- boolean hasLimitedAxesGyroscopeUncalibrated =
- getContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_SENSOR_GYROSCOPE_LIMITED_AXES_UNCALIBRATED);
-
-
- // Only the 3-axis gyroscope or the limited axes gyroscope should be implemented by the
- // system at the same time. The composite sensors for limited axes gyroscope can still be
- // present when a 3-axis gyroscope is supported.
- if (hasGyroscope) {
- assertFalse(hasLimitedAxesGyroscope);
- assertFalse(hasLimitedAxesGyroscopeUncalibrated);
- }
- }
-
@AppModeFull(reason = "Instant apps cannot access body sensors")
public void testBodySensorOperations() {
Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE);
diff --git a/tests/sensor/src/android/hardware/cts/SingleSensorTests.java b/tests/sensor/src/android/hardware/cts/SingleSensorTests.java
index 4d4768a..a782eb6 100644
--- a/tests/sensor/src/android/hardware/cts/SingleSensorTests.java
+++ b/tests/sensor/src/android/hardware/cts/SingleSensorTests.java
@@ -181,7 +181,7 @@
}
public void testAccelerometer_automotive() throws Throwable {
- runSensorTest(Sensor.TYPE_ACCELEROMETER, RATE_25HZ, true);
+ runSensorTest(Sensor.TYPE_ACCELEROMETER, RATE_100HZ, true);
}
public void testAccelUncalibrated_fastest() throws Throwable {
@@ -220,6 +220,10 @@
runSensorTest(Sensor.TYPE_ACCELEROMETER_UNCALIBRATED, RATE_1HZ);
}
+ public void testAccelUncalibrated_automotive() throws Throwable {
+ runSensorTest(Sensor.TYPE_ACCELEROMETER_UNCALIBRATED, RATE_100HZ, true);
+ }
+
public void testMagneticField_fastest() throws Throwable {
runSensorTest(Sensor.TYPE_MAGNETIC_FIELD, SensorManager.SENSOR_DELAY_FASTEST);
}
@@ -625,7 +629,7 @@
}
public void testAccelerometerLimitedAxes_automotive() throws Throwable {
- runSensorTest(Sensor.TYPE_ACCELEROMETER_LIMITED_AXES, RATE_25HZ, true);
+ runSensorTest(Sensor.TYPE_ACCELEROMETER_LIMITED_AXES, RATE_100HZ, true);
}
public void testAccelerometerLimitedAxesUncalibrated_fastest() throws Throwable {
@@ -666,7 +670,7 @@
}
public void testAccelerometerLimitedAxesUncalibrated_automotive() throws Throwable {
- runSensorTest(Sensor.TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED, RATE_25HZ, true);
+ runSensorTest(Sensor.TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED, RATE_100HZ, true);
}
public void testGyroscopeLimitedAxes_fastest() throws Throwable {
diff --git a/tests/sensor/src/android/hardware/cts/helpers/sensorverification/MeanVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/MeanVerification.java
index 489bbcc..c66d2c3 100644
--- a/tests/sensor/src/android/hardware/cts/helpers/sensorverification/MeanVerification.java
+++ b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/MeanVerification.java
@@ -307,6 +307,21 @@
new float[]{0.0f, 0.0f, SensorManager.STANDARD_GRAVITY},
new float[]{1.95f, 1.95f, 1.95f} /* m / s^2 */,
new float[]{1.95f, 1.95f, 1.95f} /* m / s^2 */));
+ defaults.put(Sensor.TYPE_ACCELEROMETER_UNCALIBRATED,
+ new ExpectedValuesAndThresholds(
+ new float[]{0.0f, 0.0f, SensorManager.STANDARD_GRAVITY, 0.0f, 0.0f, 0.0f},
+ new float[]{1.95f,
+ 1.95f,
+ 1.95f,
+ Float.MAX_VALUE,
+ Float.MAX_VALUE,
+ Float.MAX_VALUE},
+ new float[]{1.95f,
+ 1.95f,
+ 1.95f,
+ Float.MAX_VALUE,
+ Float.MAX_VALUE,
+ Float.MAX_VALUE}));
defaults.put(Sensor.TYPE_ACCELEROMETER_LIMITED_AXES,
new ExpectedValuesAndThresholds(
diff --git a/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java b/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
index 14b822b..259e002 100644
--- a/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
@@ -776,6 +776,56 @@
});
}
+ @Test
+ public void testRegisterAndUnregisterDurationScaleListener() {
+ ValueAnimator.DurationScaleChangeListener listener = scale -> {
+ return;
+ };
+ assertTrue("Listener not registered",
+ ValueAnimator.registerDurationScaleChangeListener(listener));
+ assertFalse("Listener was registered again",
+ ValueAnimator.registerDurationScaleChangeListener(listener));
+ assertTrue("Listener not unregistered",
+ ValueAnimator.unregisterDurationScaleChangeListener(listener));
+ assertFalse("Listener was unregistered again",
+ ValueAnimator.unregisterDurationScaleChangeListener(listener));
+ }
+
+ @Test
+ public void testGetDurationScale() {
+ float currentDurationScale = ValueAnimator.getDurationScale();
+ try {
+ ValueAnimator.setDurationScale(0f);
+ assertEquals(0f, ValueAnimator.getDurationScale(), 0.0f);
+ } finally {
+ // restore scale value to avoid messing up future tests
+ ValueAnimator.setDurationScale(currentDurationScale);
+ }
+
+ }
+
+ @Test
+ public void testDurationScaleListenerOnChange() throws InterruptedException {
+ float currentDurationScale = ValueAnimator.getDurationScale();
+
+ ValueAnimator.setDurationScale(1f);
+ final CountDownLatch durationScaleUpdateLatch = new CountDownLatch(1);
+ ValueAnimator.DurationScaleChangeListener listener = scale -> {
+ assertEquals(0f, ValueAnimator.getDurationScale(), 0.0f);
+ durationScaleUpdateLatch.countDown();
+ };
+
+ try {
+ ValueAnimator.registerDurationScaleChangeListener(listener);
+ ValueAnimator.setDurationScale(0f);
+ assertTrue(durationScaleUpdateLatch.await(100, TimeUnit.MILLISECONDS));
+ } finally {
+ ValueAnimator.unregisterDurationScaleChangeListener(listener);
+ // restore scale value to avoid messing up future tests
+ ValueAnimator.setDurationScale(currentDurationScale);
+ }
+ }
+
private ValueAnimator getAnimator() {
Object object = mActivity.view.newBall;
String property = "y";
diff --git a/tests/tests/app/src/android/app/cts/PictureInPictureParamsBuilderTest.java b/tests/tests/app/src/android/app/cts/PictureInPictureParamsBuilderTest.java
index 4b12120..04060fa 100644
--- a/tests/tests/app/src/android/app/cts/PictureInPictureParamsBuilderTest.java
+++ b/tests/tests/app/src/android/app/cts/PictureInPictureParamsBuilderTest.java
@@ -16,6 +16,7 @@
package android.app.cts;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -62,4 +63,36 @@
assertNull(params.getActions());
assertNull(params.getSourceRectHint());
}
+
+ @Test
+ public void testBuilderDefaultCtor() {
+ // Construct the params with default Builder constructor
+ PictureInPictureParams params = new Builder().build();
+
+ // Ensures the PictureInPictureParams constructed has nothing being set
+ assertFalse(params.hasSetAspectRatio());
+ assertFalse(params.hasSetExpandedAspectRatio());
+ assertFalse(params.hasSetActions());
+ assertFalse(params.hasSetCloseAction());
+ assertFalse(params.hasSetTitle());
+ assertFalse(params.hasSetSubtitle());
+ }
+
+ @Test
+ public void testBuilderCopyCtor() {
+ // Construct a PictureInPictureParams with some parameters being set
+ PictureInPictureParams params = new Builder()
+ .setAspectRatio(new Rational(1, 2))
+ .setActions(new ArrayList<>())
+ .setSourceRectHint(new Rect(0, 0, 100, 100))
+ .build();
+
+ // Build a new PictureInPictureParams using the copy constructor
+ PictureInPictureParams newParams = new Builder(params).build();
+
+ // Ensures the two PictureInPictureParams share the same parameters
+ assertEquals(params.getAspectRatioRational(), newParams.getAspectRatioRational());
+ assertEquals(params.getActions(), params.getActions());
+ assertEquals(params.getSourceRectHint(), params.getSourceRectHint());
+ }
}
diff --git a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
index 354ba27..9f2d821 100644
--- a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
+++ b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
@@ -2016,6 +2016,36 @@
is(emptyOrNullString()));
}
+ @Test
+ public void makeUidVisible_throwsException() throws Exception {
+ final int recipientUid = sPm.getPackageUid(
+ QUERIES_NOTHING, PackageManager.PackageInfoFlags.of(0));
+ final int visibleUid = sPm.getPackageUid(
+ TARGET_NO_API, PackageManager.PackageInfoFlags.of(0));
+ assertThrows(SecurityException.class,
+ () -> sPm.makeUidVisible(recipientUid, visibleUid));
+ }
+
+ @Test
+ public void makeUidVisible_queriesNothing_canSeeStub() throws Exception {
+ ensurePackageIsInstalled(TARGET_STUB, TARGET_STUB_APK);
+ try {
+ assertNotVisible(QUERIES_NOTHING, TARGET_STUB);
+
+ final int recipientUid = sPm.getPackageUid(
+ QUERIES_NOTHING, PackageManager.PackageInfoFlags.of(0));
+ final int visibleUid = sPm.getPackageUid(
+ TARGET_STUB, PackageManager.PackageInfoFlags.of(0));
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> sPm.makeUidVisible(recipientUid, visibleUid),
+ Manifest.permission.MAKE_UID_VISIBLE);
+
+ assertVisible(QUERIES_NOTHING, TARGET_STUB);
+ } finally {
+ ensurePackageIsNotInstalled(TARGET_STUB);
+ }
+ }
+
private void assertNotVisible(String sourcePackageName, String targetPackageName)
throws Exception {
if (!sGlobalFeatureEnabled) return;
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
index 48bdf6d..3d067c0 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
@@ -346,8 +346,10 @@
ASSERT_OK(iface->RepeatInterface(empty, &ret));
EXPECT_EQ(empty.get(), ret.get());
- // interfaces are always nullable in AIDL C++, and that behavior was carried
- // over to the NDK backend for consistency
+ // b/210547999
+ // interface writes are always nullable in AIDL C++ (but reads are not
+ // nullable by default). However, the NDK backend follows the Java behavior
+ // and always allows interfaces to be nullable (for reads and writes).
ASSERT_OK(iface->RepeatInterface(nullptr, &ret));
EXPECT_EQ(nullptr, ret.get());
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothAdapterTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothAdapterTest.java
index c5d45a2..15c4f1c 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothAdapterTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothAdapterTest.java
@@ -414,7 +414,7 @@
assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
// Verify return value if Bluetooth is not enabled
- assertNull(mAdapter.getUuids());
+ assertEquals(mAdapter.getUuids().length, 0);
}
@@ -440,7 +440,7 @@
public void test_BluetoothConnectionCallback_disconnectReasonText() {
assertEquals("Reason unknown", BluetoothAdapter.BluetoothConnectionCallback
- .disconnectReasonText(BluetoothStatusCodes.ERROR_UNKNOWN));
+ .disconnectReasonToString(BluetoothStatusCodes.ERROR_UNKNOWN));
}
public void test_registerBluetoothConnectionCallback() {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothCodecsTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothCodecsTest.java
new file mode 100644
index 0000000..10c18a2
--- /dev/null
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothCodecsTest.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.cts;
+
+import android.app.UiAutomation;
+import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothCodecStatus;
+import android.test.AndroidTestCase;
+
+import androidx.test.InstrumentationRegistry;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class BluetoothCodecsTest extends AndroidTestCase {
+ private static final String TAG = BluetoothCodecsTest.class.getSimpleName();
+
+ // Codec configs: A and B are same; C is different
+ private static final BluetoothCodecConfig config_A =
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_44100,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_16,
+ BluetoothCodecConfig.CHANNEL_MODE_STEREO,
+ 1000, 2000, 3000, 4000);
+
+ private static final BluetoothCodecConfig config_B =
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_44100,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_16,
+ BluetoothCodecConfig.CHANNEL_MODE_STEREO,
+ 1000, 2000, 3000, 4000);
+
+ private static final BluetoothCodecConfig config_C =
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_44100,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_16,
+ BluetoothCodecConfig.CHANNEL_MODE_STEREO,
+ 1000, 2000, 3000, 4000);
+
+ // Local capabilities: A and B are same; C is different
+ private static final BluetoothCodecConfig local_capability1_A =
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_44100 |
+ BluetoothCodecConfig.SAMPLE_RATE_48000,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_16,
+ BluetoothCodecConfig.CHANNEL_MODE_STEREO |
+ BluetoothCodecConfig.CHANNEL_MODE_MONO,
+ 1000, 2000, 3000, 4000);
+
+ private static final BluetoothCodecConfig local_capability1_B =
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_44100 |
+ BluetoothCodecConfig.SAMPLE_RATE_48000,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_16,
+ BluetoothCodecConfig.CHANNEL_MODE_STEREO |
+ BluetoothCodecConfig.CHANNEL_MODE_MONO,
+ 1000, 2000, 3000, 4000);
+
+ private static final BluetoothCodecConfig local_capability1_C =
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_44100 |
+ BluetoothCodecConfig.SAMPLE_RATE_48000,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_16,
+ BluetoothCodecConfig.CHANNEL_MODE_STEREO,
+ 1000, 2000, 3000, 4000);
+
+ private static final BluetoothCodecConfig local_capability2_A =
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_44100 |
+ BluetoothCodecConfig.SAMPLE_RATE_48000,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_16,
+ BluetoothCodecConfig.CHANNEL_MODE_STEREO |
+ BluetoothCodecConfig.CHANNEL_MODE_MONO,
+ 1000, 2000, 3000, 4000);
+
+ private static final BluetoothCodecConfig local_capability2_B =
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_44100 |
+ BluetoothCodecConfig.SAMPLE_RATE_48000,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_16,
+ BluetoothCodecConfig.CHANNEL_MODE_STEREO |
+ BluetoothCodecConfig.CHANNEL_MODE_MONO,
+ 1000, 2000, 3000, 4000);
+
+ private static final BluetoothCodecConfig local_capability2_C =
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_44100 |
+ BluetoothCodecConfig.SAMPLE_RATE_48000,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_16,
+ BluetoothCodecConfig.CHANNEL_MODE_STEREO,
+ 1000, 2000, 3000, 4000);
+
+ // Selectable capabilities: A and B are same; C is different
+ private static final BluetoothCodecConfig selectable_capability1_A =
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_44100,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_16,
+ BluetoothCodecConfig.CHANNEL_MODE_STEREO |
+ BluetoothCodecConfig.CHANNEL_MODE_MONO,
+ 1000, 2000, 3000, 4000);
+
+ private static final BluetoothCodecConfig selectable_capability1_B =
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_44100,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_16,
+ BluetoothCodecConfig.CHANNEL_MODE_STEREO |
+ BluetoothCodecConfig.CHANNEL_MODE_MONO,
+ 1000, 2000, 3000, 4000);
+
+ private static final BluetoothCodecConfig selectable_capability1_C =
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_44100,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_16,
+ BluetoothCodecConfig.CHANNEL_MODE_STEREO,
+ 1000, 2000, 3000, 4000);
+
+ private static final BluetoothCodecConfig selectable_capability2_A =
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_44100,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_16,
+ BluetoothCodecConfig.CHANNEL_MODE_STEREO |
+ BluetoothCodecConfig.CHANNEL_MODE_MONO,
+ 1000, 2000, 3000, 4000);
+
+ private static final BluetoothCodecConfig selectable_capability2_B =
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_44100,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_16,
+ BluetoothCodecConfig.CHANNEL_MODE_STEREO |
+ BluetoothCodecConfig.CHANNEL_MODE_MONO,
+ 1000, 2000, 3000, 4000);
+
+ private static final BluetoothCodecConfig selectable_capability2_C =
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_44100,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_16,
+ BluetoothCodecConfig.CHANNEL_MODE_STEREO,
+ 1000, 2000, 3000, 4000);
+
+ private static final List<BluetoothCodecConfig> LOCAL_CAPABILITY_A =
+ new ArrayList() {{
+ add(local_capability1_A);
+ add(local_capability2_A);
+ }};
+
+ private static final List<BluetoothCodecConfig> LOCAL_CAPABILITY_B =
+ new ArrayList() {{
+ add(local_capability1_B);
+ add(local_capability2_B);
+ }};
+
+ private static final List<BluetoothCodecConfig> LOCAL_CAPABILITY_C =
+ new ArrayList() {{
+ add(local_capability1_C);
+ add(local_capability2_C);
+ }};
+
+ private static final List<BluetoothCodecConfig> SELECTABLE_CAPABILITY_A =
+ new ArrayList() {{
+ add(selectable_capability1_A);
+ add(selectable_capability2_A);
+ }};
+
+ private static final List<BluetoothCodecConfig> SELECTABLE_CAPABILITY_B =
+ new ArrayList() {{
+ add(selectable_capability1_B);
+ add(selectable_capability2_B);
+ }};
+
+ private static final List<BluetoothCodecConfig> SELECTABLE_CAPABILITY_C =
+ new ArrayList() {{
+ add(selectable_capability1_C);
+ add(selectable_capability2_C);
+ }};
+
+ private static final BluetoothCodecStatus bcs_A =
+ new BluetoothCodecStatus.Builder()
+ .setCodecConfig(config_A)
+ .setCodecsLocalCapabilities(LOCAL_CAPABILITY_A)
+ .setCodecsSelectableCapabilities(SELECTABLE_CAPABILITY_A)
+ .build();
+ private static final BluetoothCodecStatus bcs_B =
+ new BluetoothCodecStatus.Builder()
+ .setCodecConfig(config_B)
+ .setCodecsLocalCapabilities(LOCAL_CAPABILITY_B)
+ .setCodecsSelectableCapabilities(SELECTABLE_CAPABILITY_B)
+ .build();
+ private static final BluetoothCodecStatus bcs_C =
+ new BluetoothCodecStatus.Builder()
+ .setCodecConfig(config_C)
+ .setCodecsLocalCapabilities(LOCAL_CAPABILITY_C)
+ .setCodecsSelectableCapabilities(SELECTABLE_CAPABILITY_C)
+ .build();
+
+ public void test_BluetoothCodecStatusBuilder() {
+ BluetoothCodecStatus builderConfig = new BluetoothCodecStatus.Builder()
+ .setCodecConfig(config_A)
+ .setCodecsLocalCapabilities(LOCAL_CAPABILITY_B)
+ .setCodecsSelectableCapabilities(SELECTABLE_CAPABILITY_C)
+ .build();
+
+ assertTrue(Objects.equals(builderConfig.getCodecConfig(), config_A));
+ assertTrue(Objects.equals(builderConfig.getCodecsLocalCapabilities(),
+ LOCAL_CAPABILITY_B));
+ assertTrue(Objects.equals(builderConfig.getCodecsSelectableCapabilities(),
+ SELECTABLE_CAPABILITY_C));
+ }
+
+ public void test_BluetoothCodecConfigBuilder() {
+ BluetoothCodecConfig builderConfig = new BluetoothCodecConfig.Builder()
+ .setCodecType(config_A.getCodecType())
+ .setCodecPriority(config_A.getCodecPriority())
+ .setSampleRate(config_A.getSampleRate())
+ .setBitsPerSample(config_A.getBitsPerSample())
+ .setChannelMode(config_A.getChannelMode())
+ .setCodecSpecific1(config_A.getCodecSpecific1())
+ .setCodecSpecific2(config_A.getCodecSpecific2())
+ .setCodecSpecific3(config_A.getCodecSpecific3())
+ .setCodecSpecific4(config_A.getCodecSpecific4())
+ .build();
+
+ assertTrue(Objects.equals(builderConfig, config_A));
+ assertTrue(builderConfig.isMandatoryCodec());
+ }
+
+ public void test_GetCodecConfig() {
+ assertTrue(Objects.equals(bcs_A.getCodecConfig(), config_A));
+ assertTrue(Objects.equals(bcs_A.getCodecConfig(), config_B));
+ assertFalse(Objects.equals(bcs_A.getCodecConfig(), config_C));
+ }
+
+ public void test_CodecsCapabilities() {
+ assertTrue(bcs_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_A));
+ assertTrue(bcs_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_B));
+ assertFalse(bcs_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_C));
+
+ assertTrue(bcs_A.getCodecsSelectableCapabilities()
+ .equals(SELECTABLE_CAPABILITY_A));
+ assertTrue(bcs_A.getCodecsSelectableCapabilities()
+ .equals(SELECTABLE_CAPABILITY_B));
+ assertFalse(bcs_A.getCodecsSelectableCapabilities()
+ .equals(SELECTABLE_CAPABILITY_C));
+ }
+
+ public void test_IsCodecConfigSelectable() {
+ assertFalse(bcs_A.isCodecConfigSelectable(null));
+ assertTrue(bcs_A.isCodecConfigSelectable(selectable_capability1_C));
+ assertTrue(bcs_A.isCodecConfigSelectable(selectable_capability2_C));
+
+ // Not selectable due to multiple channel modes
+ assertFalse(bcs_A.isCodecConfigSelectable(selectable_capability1_A));
+ assertFalse(bcs_A.isCodecConfigSelectable(selectable_capability1_B));
+ assertFalse(bcs_A.isCodecConfigSelectable(selectable_capability2_A));
+ assertFalse(bcs_A.isCodecConfigSelectable(selectable_capability2_B));
+ }
+
+ private static BluetoothCodecConfig buildBluetoothCodecConfig(int sourceCodecType,
+ int codecPriority, int sampleRate, int bitsPerSample, int channelMode,
+ long codecSpecific1, long codecSpecific2, long codecSpecific3, long codecSpecific4) {
+ return new BluetoothCodecConfig.Builder()
+ .setCodecType(sourceCodecType)
+ .setCodecPriority(codecPriority)
+ .setSampleRate(sampleRate)
+ .setBitsPerSample(bitsPerSample)
+ .setChannelMode(channelMode)
+ .setCodecSpecific1(codecSpecific1)
+ .setCodecSpecific2(codecSpecific2)
+ .setCodecSpecific3(codecSpecific3)
+ .setCodecSpecific4(codecSpecific4)
+ .build();
+ }
+}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecConfigMetadataTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecConfigMetadataTest.java
index af30292..0100442 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecConfigMetadataTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecConfigMetadataTest.java
@@ -115,6 +115,21 @@
}
@Test
+ public void testCreateCodecConfigMetadataFromCopy() {
+ if (shouldSkipTest()) {
+ return;
+ }
+ BluetoothLeAudioCodecConfigMetadata codecMetadata =
+ new BluetoothLeAudioCodecConfigMetadata.Builder()
+ .setAudioLocation(TEST_AUDIO_LOCATION_FRONT_LEFT).build();
+ BluetoothLeAudioCodecConfigMetadata codecMetadataCopy =
+ new BluetoothLeAudioCodecConfigMetadata.Builder(codecMetadata).build();
+ assertEquals(codecMetadata, codecMetadataCopy);
+ assertEquals(TEST_AUDIO_LOCATION_FRONT_LEFT, codecMetadataCopy.getAudioLocation());
+ assertArrayEquals(TEST_METADATA_BYTES, codecMetadata.getRawMetadata());
+ }
+
+ @Test
public void testCreateCodecConfigMetadataFromBytes() {
if (shouldSkipTest()) {
return;
@@ -124,8 +139,7 @@
byte[] metadataBytes = codecMetadata.getRawMetadata();
assertNotNull(metadataBytes);
assertArrayEquals(TEST_METADATA_BYTES, metadataBytes);
- // TODO: Implement implicit LTV byte conversion in the API class
- // assertEquals(TEST_AUDIO_LOCATION_FRONT_LEFT, codecMetadata.getAudioLocation());
+ assertEquals(TEST_AUDIO_LOCATION_FRONT_LEFT, codecMetadata.getAudioLocation());
}
private boolean shouldSkipTest() {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioContentMetadataTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioContentMetadataTest.java
index 6c32580..08deed4 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioContentMetadataTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioContentMetadataTest.java
@@ -117,8 +117,22 @@
.setProgramInfo(TEST_PROGRAM_INFO).setLanguage(TEST_LANGUAGE).build();
assertEquals(TEST_PROGRAM_INFO, contentMetadata.getProgramInfo());
assertEquals(TEST_LANGUAGE, contentMetadata.getLanguage());
- // TODO: Implement implicit LTV byte conversion in the API class
- // assertArrayEquals(TEST_METADATA_BYTES, contentMetadata.getRawMetadata());
+ assertArrayEquals(TEST_METADATA_BYTES, contentMetadata.getRawMetadata());
+ }
+
+ @Test
+ public void testCreateCodecConfigMetadataFromCopy() {
+ if (shouldSkipTest()) {
+ return;
+ }
+ BluetoothLeAudioContentMetadata contentMetadata =
+ new BluetoothLeAudioContentMetadata.Builder()
+ .setProgramInfo(TEST_PROGRAM_INFO).setLanguage(TEST_LANGUAGE).build();
+ BluetoothLeAudioContentMetadata contentMetadataCopy =
+ new BluetoothLeAudioContentMetadata.Builder(contentMetadata).build();
+ assertEquals(TEST_PROGRAM_INFO, contentMetadataCopy.getProgramInfo());
+ assertEquals(TEST_LANGUAGE, contentMetadataCopy.getLanguage());
+ assertArrayEquals(TEST_METADATA_BYTES, contentMetadataCopy.getRawMetadata());
}
@Test
@@ -131,9 +145,8 @@
byte[] metadataBytes = contentMetadata.getRawMetadata();
assertNotNull(metadataBytes);
assertArrayEquals(TEST_METADATA_BYTES, metadataBytes);
- // TODO: Implement implicit LTV byte conversion in the API class
- // assertEquals(TEST_PROGRAM_INFO, contentMetadata.getProgramInfo());
- // assertEquals(TEST_LANGUAGE, contentMetadata.getLanguage());
+ assertEquals(TEST_PROGRAM_INFO, contentMetadata.getProgramInfo());
+ assertEquals(TEST_LANGUAGE, contentMetadata.getLanguage());
}
private boolean shouldSkipTest() {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java
index 6b349e7..1c0cb12 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java
@@ -21,6 +21,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeAudio;
+import android.bluetooth.BluetoothLeAudioCodecStatus;
import android.bluetooth.BluetoothLeAudioCodecConfig;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
@@ -35,6 +36,7 @@
import com.android.compatibility.common.util.ApiLevelUtil;
import java.util.List;
+import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@@ -176,47 +178,27 @@
mBluetoothLeAudio.getConnectionPolicy(null));
}
- public void test_setVolume() {
+ public void testRegisterCallback() {
if (!(mHasBluetooth && mIsLeAudioSupported)) return;
assertTrue(waitForProfileConnect());
assertNotNull(mBluetoothLeAudio);
- // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission
- assertThrows(SecurityException.class, () -> mBluetoothLeAudio.setVolume(42));
- }
+ Executor executor = mContext.getMainExecutor();
+ BluetoothLeAudio.Callback callback =
+ new BluetoothLeAudio.Callback() {
+ @Override
+ public void onCodecConfigChanged(int groupId,
+ BluetoothLeAudioCodecStatus status) {}
+ };
- public void testGetCodecStatus() {
- if (!(mHasBluetooth && mIsLeAudioSupported)) return;
-
- assertTrue(waitForProfileConnect());
- assertNotNull(mBluetoothLeAudio);
-
- BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
-
- assertNull(mBluetoothLeAudio.getCodecStatus(testDevice));
- assertThrows(IllegalArgumentException.class, () -> {
- mBluetoothLeAudio.getCodecStatus(null);
- });
- }
-
- public void testSetCodecConfigPreference() {
- if (!(mHasBluetooth && mIsLeAudioSupported)) return;
-
- assertTrue(waitForProfileConnect());
- assertNotNull(mBluetoothLeAudio);
-
- BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
-
- BluetoothLeAudioCodecConfig codecConfig = new BluetoothLeAudioCodecConfig.Builder()
- .setCodecType(BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3)
- .setCodecPriority(0)
- .build();
- mBluetoothLeAudio.setCodecConfigPreference(testDevice, codecConfig);
- assertNull(mBluetoothLeAudio.getCodecStatus(testDevice));
- assertThrows(IllegalArgumentException.class, () -> {
- mBluetoothLeAudio.setCodecConfigPreference(null, null);
- });
+ // Verify parameter
+ assertThrows(NullPointerException.class, () ->
+ mBluetoothLeAudio.registerCallback(null, callback));
+ assertThrows(NullPointerException.class, () ->
+ mBluetoothLeAudio.registerCallback(executor, null));
+ assertThrows(NullPointerException.class, () ->
+ mBluetoothLeAudio.unregisterCallback(null));
}
private boolean waitForProfileConnect() {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastMetadataTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastMetadataTest.java
index 5651320..d0f3118 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastMetadataTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastMetadataTest.java
@@ -19,13 +19,20 @@
import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.bluetooth.BluetoothStatusCodes.FEATURE_SUPPORTED;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeAudioCodecConfigMetadata;
+import android.bluetooth.BluetoothLeAudioContentMetadata;
+import android.bluetooth.BluetoothLeBroadcastChannel;
import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.bluetooth.BluetoothLeBroadcastSubgroup;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Build;
@@ -50,6 +57,17 @@
private static final int TEST_PA_SYNC_INTERVAL = 100;
private static final int TEST_PRESENTATION_DELAY_MS = 345;
+ private static final int TEST_CODEC_ID = 42;
+ private static final BluetoothLeBroadcastChannel[] TEST_CHANNELS = {null};
+
+ // For BluetoothLeAudioCodecConfigMetadata
+ private static final long TEST_AUDIO_LOCATION_FRONT_LEFT = 0x01;
+
+ // For BluetoothLeAudioContentMetadata
+ private static final String TEST_PROGRAM_INFO = "Test";
+ // German language code in ISO 639-3
+ private static final String TEST_LANGUAGE = "deu";
+
private Context mContext;
private boolean mHasBluetooth;
private BluetoothAdapter mAdapter;
@@ -107,25 +125,99 @@
}
BluetoothDevice testDevice =
mAdapter.getRemoteLeDevice(TEST_MAC_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM);
- BluetoothLeBroadcastMetadata.Builder builder = new BluetoothLeBroadcastMetadata.Builder();
- BluetoothLeBroadcastMetadata metadata =
- builder.setEncrypted(false)
+ BluetoothLeBroadcastMetadata.Builder builder = new BluetoothLeBroadcastMetadata.Builder()
+ .setEncrypted(false)
.setSourceDevice(testDevice, BluetoothDevice.ADDRESS_TYPE_RANDOM)
.setSourceAdvertisingSid(TEST_ADVERTISER_SID)
.setBroadcastId(TEST_BROADCAST_ID)
.setBroadcastCode(null)
.setPaSyncInterval(TEST_PA_SYNC_INTERVAL)
- .setPresentationDelayMicros(TEST_PRESENTATION_DELAY_MS)
- .build();
+ .setPresentationDelayMicros(TEST_PRESENTATION_DELAY_MS);
+ // builder expect at least one subgroup
+ assertThrows(IllegalArgumentException.class, builder::build);
+ BluetoothLeBroadcastSubgroup[] subgroups = new BluetoothLeBroadcastSubgroup[] {
+ createBroadcastSubgroup()
+ };
+ for (BluetoothLeBroadcastSubgroup subgroup : subgroups) {
+ builder.addSubgroup(subgroup);
+ }
+ BluetoothLeBroadcastMetadata metadata = builder.build();
+ assertFalse(metadata.isEncrypted());
assertEquals(testDevice, metadata.getSourceDevice());
assertEquals(BluetoothDevice.ADDRESS_TYPE_RANDOM, metadata.getSourceAddressType());
+ assertEquals(TEST_ADVERTISER_SID, metadata.getSourceAdvertisingSid());
assertEquals(TEST_BROADCAST_ID, metadata.getBroadcastId());
assertNull(metadata.getBroadcastCode());
assertEquals(TEST_PA_SYNC_INTERVAL, metadata.getPaSyncInterval());
assertEquals(TEST_PRESENTATION_DELAY_MS, metadata.getPresentationDelayMicros());
+ assertArrayEquals(subgroups,
+ metadata.getSubgroups().toArray(new BluetoothLeBroadcastSubgroup[0]));
+ builder.clearSubgroup();
+ // builder expect at least one subgroup
+ assertThrows(IllegalArgumentException.class, builder::build);
+ }
+
+ @Test
+ public void testCreateMetadataFromCopy() {
+ if (shouldSkipTest()) {
+ return;
+ }
+ BluetoothDevice testDevice =
+ mAdapter.getRemoteLeDevice(TEST_MAC_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM);
+ BluetoothLeBroadcastMetadata.Builder builder = new BluetoothLeBroadcastMetadata.Builder()
+ .setEncrypted(false)
+ .setSourceDevice(testDevice, BluetoothDevice.ADDRESS_TYPE_RANDOM)
+ .setSourceAdvertisingSid(TEST_ADVERTISER_SID)
+ .setBroadcastId(TEST_BROADCAST_ID)
+ .setBroadcastCode(null)
+ .setPaSyncInterval(TEST_PA_SYNC_INTERVAL)
+ .setPresentationDelayMicros(TEST_PRESENTATION_DELAY_MS);
+ // builder expect at least one subgroup
+ assertThrows(IllegalArgumentException.class, builder::build);
+ BluetoothLeBroadcastSubgroup[] subgroups = new BluetoothLeBroadcastSubgroup[] {
+ createBroadcastSubgroup()
+ };
+ for (BluetoothLeBroadcastSubgroup subgroup : subgroups) {
+ builder.addSubgroup(subgroup);
+ }
+ BluetoothLeBroadcastMetadata metadata = builder.build();
+ BluetoothLeBroadcastMetadata metadataCopy =
+ new BluetoothLeBroadcastMetadata.Builder(metadata).build();
+ assertFalse(metadataCopy.isEncrypted());
+ assertEquals(testDevice, metadataCopy.getSourceDevice());
+ assertEquals(BluetoothDevice.ADDRESS_TYPE_RANDOM, metadataCopy.getSourceAddressType());
+ assertEquals(TEST_ADVERTISER_SID, metadataCopy.getSourceAdvertisingSid());
+ assertEquals(TEST_BROADCAST_ID, metadataCopy.getBroadcastId());
+ assertNull(metadataCopy.getBroadcastCode());
+ assertEquals(TEST_PA_SYNC_INTERVAL, metadataCopy.getPaSyncInterval());
+ assertEquals(TEST_PRESENTATION_DELAY_MS, metadataCopy.getPresentationDelayMicros());
+ assertArrayEquals(subgroups,
+ metadataCopy.getSubgroups().toArray(new BluetoothLeBroadcastSubgroup[0]));
+ builder.clearSubgroup();
+ // builder expect at least one subgroup
+ assertThrows(IllegalArgumentException.class, builder::build);
}
private boolean shouldSkipTest() {
return !mHasBluetooth || (!mIsBroadcastSourceSupported && !mIsBroadcastAssistantSupported);
}
+
+ static BluetoothLeBroadcastSubgroup createBroadcastSubgroup() {
+ BluetoothLeAudioCodecConfigMetadata codecMetadata =
+ new BluetoothLeAudioCodecConfigMetadata.Builder()
+ .setAudioLocation(TEST_AUDIO_LOCATION_FRONT_LEFT).build();
+ BluetoothLeAudioContentMetadata contentMetadata =
+ new BluetoothLeAudioContentMetadata.Builder()
+ .setProgramInfo(TEST_PROGRAM_INFO).setLanguage(TEST_LANGUAGE).build();
+ BluetoothLeBroadcastSubgroup.Builder builder = new BluetoothLeBroadcastSubgroup.Builder()
+ .setCodecId(TEST_CODEC_ID)
+ .setCodecSpecificConfig(codecMetadata)
+ .setContentMetadata(contentMetadata)
+ .setNoChannelPreference(true);
+ for (BluetoothLeBroadcastChannel channel : TEST_CHANNELS) {
+ builder.addChannel(channel);
+ }
+ return builder.build();
+ }
+
}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastSubgroupTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastSubgroupTest.java
index 3ad73c7..ea72dcd 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastSubgroupTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastSubgroupTest.java
@@ -21,9 +21,12 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothLeAudioCodecConfigMetadata;
+import android.bluetooth.BluetoothLeAudioContentMetadata;
import android.bluetooth.BluetoothLeBroadcastChannel;
import android.bluetooth.BluetoothLeBroadcastSubgroup;
import android.bluetooth.BluetoothProfile;
@@ -47,6 +50,14 @@
private static final int TEST_CODEC_ID = 42;
private static final BluetoothLeBroadcastChannel[] TEST_CHANNELS = {null};
+ // For BluetoothLeAudioCodecConfigMetadata
+ private static final long TEST_AUDIO_LOCATION_FRONT_LEFT = 0x01;
+
+ // For BluetoothLeAudioContentMetadata
+ private static final String TEST_PROGRAM_INFO = "Test";
+ // German language code in ISO 639-3
+ private static final String TEST_LANGUAGE = "deu";
+
private Context mContext;
private boolean mHasBluetooth;
private BluetoothAdapter mAdapter;
@@ -102,18 +113,63 @@
if (shouldSkipTest()) {
return;
}
+ BluetoothLeAudioCodecConfigMetadata codecMetadata =
+ new BluetoothLeAudioCodecConfigMetadata.Builder()
+ .setAudioLocation(TEST_AUDIO_LOCATION_FRONT_LEFT).build();
+ BluetoothLeAudioContentMetadata contentMetadata =
+ new BluetoothLeAudioContentMetadata.Builder()
+ .setProgramInfo(TEST_PROGRAM_INFO).setLanguage(TEST_LANGUAGE).build();
BluetoothLeBroadcastSubgroup.Builder builder = new BluetoothLeBroadcastSubgroup.Builder()
.setCodecId(TEST_CODEC_ID)
- .setCodecSpecificConfig(null)
- .setContentMetadata(null)
+ .setCodecSpecificConfig(codecMetadata)
+ .setContentMetadata(contentMetadata)
.setNoChannelPreference(true);
for (BluetoothLeBroadcastChannel channel : TEST_CHANNELS) {
builder.addChannel(channel);
}
BluetoothLeBroadcastSubgroup subgroup = builder.build();
assertEquals(TEST_CODEC_ID, subgroup.getCodecId());
+ assertEquals(codecMetadata, subgroup.getCodecSpecificConfig());
+ assertEquals(contentMetadata, subgroup.getContentMetadata());
+ assertTrue(subgroup.isNoChannelPreference());
assertArrayEquals(TEST_CHANNELS,
subgroup.getChannels().toArray(new BluetoothLeBroadcastChannel[0]));
+ builder.clearChannel();
+ // builder expect at least one channel
+ assertThrows(IllegalArgumentException.class, builder::build);
+ }
+
+ @Test
+ public void testCreateBroadcastSubgroupFromCopy() {
+ if (shouldSkipTest()) {
+ return;
+ }
+ BluetoothLeAudioCodecConfigMetadata codecMetadata =
+ new BluetoothLeAudioCodecConfigMetadata.Builder()
+ .setAudioLocation(TEST_AUDIO_LOCATION_FRONT_LEFT).build();
+ BluetoothLeAudioContentMetadata contentMetadata =
+ new BluetoothLeAudioContentMetadata.Builder()
+ .setProgramInfo(TEST_PROGRAM_INFO).setLanguage(TEST_LANGUAGE).build();
+ BluetoothLeBroadcastSubgroup.Builder builder = new BluetoothLeBroadcastSubgroup.Builder()
+ .setCodecId(TEST_CODEC_ID)
+ .setCodecSpecificConfig(codecMetadata)
+ .setContentMetadata(contentMetadata)
+ .setNoChannelPreference(true);
+ for (BluetoothLeBroadcastChannel channel : TEST_CHANNELS) {
+ builder.addChannel(channel);
+ }
+ BluetoothLeBroadcastSubgroup subgroup = builder.build();
+ BluetoothLeBroadcastSubgroup subgroupCopy =
+ new BluetoothLeBroadcastSubgroup.Builder(subgroup).build();
+ assertEquals(TEST_CODEC_ID, subgroupCopy.getCodecId());
+ assertEquals(codecMetadata, subgroupCopy.getCodecSpecificConfig());
+ assertEquals(contentMetadata, subgroupCopy.getContentMetadata());
+ assertTrue(subgroupCopy.isNoChannelPreference());
+ assertArrayEquals(TEST_CHANNELS,
+ subgroupCopy.getChannels().toArray(new BluetoothLeBroadcastChannel[0]));
+ builder.clearChannel();
+ // builder expect at least one channel
+ assertThrows(IllegalArgumentException.class, builder::build);
}
private boolean shouldSkipTest() {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothServiceManagerTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothServiceManagerTest.java
new file mode 100644
index 0000000..f81a29c
--- /dev/null
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothServiceManagerTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.cts;
+
+import static org.junit.Assert.assertThrows;
+
+import android.content.pm.PackageManager;
+import android.os.BluetoothServiceManager;
+import android.os.BluetoothServiceManager.ServiceNotFoundException;
+import android.os.BluetoothServiceManager.ServiceRegisterer;
+import android.os.IBinder;
+import android.test.AndroidTestCase;
+
+public class BluetoothServiceManagerTest extends AndroidTestCase {
+
+ private boolean mHasBluetooth;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mHasBluetooth = getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_BLUETOOTH);
+ }
+
+ public void test_ServiceRegisterer() {
+ if (!mHasBluetooth) {
+ return;
+ }
+ BluetoothServiceManager serviceManager = new BluetoothServiceManager();
+ ServiceRegisterer serviceRegisterer =
+ serviceManager.getBluetoothManagerServiceRegisterer();
+
+ assertThrows(SecurityException.class, () ->
+ serviceRegisterer.register(serviceRegisterer.get()));
+
+ IBinder bluetoothServiceBinder = serviceRegisterer.get();
+ assertNotNull(bluetoothServiceBinder);
+
+ bluetoothServiceBinder = serviceRegisterer.tryGet();
+ assertNotNull(bluetoothServiceBinder);
+
+ try {
+ bluetoothServiceBinder = serviceRegisterer.getOrThrow();
+ assertNotNull(bluetoothServiceBinder);
+ } catch (ServiceNotFoundException exception) {
+ fail("ServiceNotFoundException should not be thrown");
+ }
+ }
+}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/ScanResultTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/ScanResultTest.java
index f323712..71a61b9 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/ScanResultTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/ScanResultTest.java
@@ -72,4 +72,39 @@
TIMESTAMP_NANOS);
assertEquals(0, result.describeContents());
}
+
+ @SmallTest
+ public void testConstructor() {
+ if (!mContext.getPackageManager().
+ hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) return;
+
+ BluetoothDevice device =
+ BluetoothAdapter.getDefaultAdapter().getRemoteDevice(DEVICE_ADDRESS);
+ int eventType = 0xAAAA;
+ int primaryPhy = 0xAAAB;
+ int secondaryPhy = 0xAABA;
+ int advertisingSid = 0xAABB;
+ int txPower = 0xABAA;
+ int rssi = 0xABAB;
+ int periodicAdvertisingInterval = 0xABBA;
+ long timestampNanos = 0xABBB;
+ ScanResult result = new ScanResult(device, eventType, primaryPhy, secondaryPhy,
+ advertisingSid, txPower, rssi, periodicAdvertisingInterval, null, timestampNanos);
+ assertEquals(result.getDevice(), device);
+ assertNull(result.getScanRecord());
+ assertEquals(result.getRssi(), rssi);
+ assertEquals(result.getTimestampNanos(), timestampNanos);
+ assertEquals(result.getDataStatus(), 0x01);
+ assertEquals(result.getPrimaryPhy(), primaryPhy);
+ assertEquals(result.getSecondaryPhy(), secondaryPhy);
+ assertEquals(result.getAdvertisingSid(), advertisingSid);
+ assertEquals(result.getTxPower(), txPower);
+ assertEquals(result.getPeriodicAdvertisingInterval(), periodicAdvertisingInterval);
+
+ // specific value of event type for isLegacy and isConnectable to be true
+ ScanResult result2 = new ScanResult(device, 0x11, primaryPhy, secondaryPhy,
+ advertisingSid, txPower, rssi, periodicAdvertisingInterval, null, timestampNanos);
+ assertTrue(result2.isLegacy());
+ assertTrue(result2.isConnectable());
+ }
}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/ScanSettingsTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/ScanSettingsTest.java
index 7033c3c..a1b928f 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/ScanSettingsTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/ScanSettingsTest.java
@@ -16,6 +16,8 @@
package android.bluetooth.cts;
+import static org.junit.Assert.assertThrows;
+
import android.bluetooth.le.ScanSettings;
import android.os.Parcel;
import android.test.AndroidTestCase;
@@ -33,9 +35,81 @@
assertEquals(ScanSettings.SCAN_MODE_LOW_POWER, settings.getScanMode());
assertEquals(0, settings.getScanResultType());
assertEquals(0, settings.getReportDelayMillis());
+ assertEquals(true, settings.getLegacy());
+ assertEquals(ScanSettings.PHY_LE_ALL_SUPPORTED, settings.getPhy());
}
@SmallTest
+ public void testBuilderSettings() {
+ ScanSettings.Builder builder = new ScanSettings.Builder();
+
+ // setScanMode boundary check
+ assertThrows("Check boundary of ScanSettings.Builder.setScanMode argument",
+ IllegalArgumentException.class,
+ () -> builder.setScanMode(ScanSettings.SCAN_MODE_OPPORTUNISTIC - 1));
+ assertThrows("Check boundary of ScanSettings.Builder.setScanMode argument",
+ IllegalArgumentException.class,
+ () -> builder.setScanMode(6)); // 6 = ScanSettings.SCAN_MODE_SCREEN_OFF_BALANCED + 1
+
+ // setCallbackType boundary check
+ assertThrows("Check boundary of ScanSettings.Builder.setCallbackType argument",
+ IllegalArgumentException.class,
+ () -> builder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES - 1));
+ assertThrows("Check boundary of ScanSettings.Builder.setCallbackType argument",
+ IllegalArgumentException.class,
+ () -> builder.setCallbackType(ScanSettings.CALLBACK_TYPE_MATCH_LOST + 1));
+
+ // setScanResultType boundary check
+ assertThrows("Check boundary of ScanSettings.Builder.setScanResultType argument",
+ IllegalArgumentException.class,
+ () -> builder.setScanResultType(ScanSettings.SCAN_RESULT_TYPE_FULL - 1));
+ assertThrows("Check boundary of ScanSettings.Builder.setScanResultType argument",
+ IllegalArgumentException.class,
+ () -> builder.setScanResultType(ScanSettings.SCAN_RESULT_TYPE_ABBREVIATED + 1));
+
+ assertThrows("Check boundary of ScanSettings.Builder.setReportDelay argument",
+ IllegalArgumentException.class,
+ () -> builder.setReportDelay(-1));
+
+ // setNumOfMatches boundary check
+ assertThrows("Check boundary of ScanSettings.Builder.setNumOfMatches argument",
+ IllegalArgumentException.class,
+ () -> builder.setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT - 1));
+ assertThrows("Check boundary of ScanSettings.Builder.setNumOfMatches argument",
+ IllegalArgumentException.class,
+ () -> builder.setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT + 1));
+
+ // setMatchMode boundary check
+ assertThrows("Check boundary of ScanSettings.Builder.setMatchMode argument",
+ IllegalArgumentException.class,
+ () -> builder.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE - 1));
+ assertThrows("Check boundary of ScanSettings.Builder.setMatchMode argument",
+ IllegalArgumentException.class,
+ () -> builder.setMatchMode(ScanSettings.MATCH_MODE_STICKY + 1));
+
+ int cbType = ScanSettings.CALLBACK_TYPE_MATCH_LOST | ScanSettings.CALLBACK_TYPE_FIRST_MATCH;
+
+ ScanSettings settings = builder
+ .setScanMode(ScanSettings.SCAN_MODE_BALANCED)
+ .setCallbackType(cbType)
+ .setScanResultType(ScanSettings.SCAN_RESULT_TYPE_ABBREVIATED)
+ .setReportDelay(0xDEAD)
+ .setNumOfMatches(ScanSettings.MATCH_NUM_FEW_ADVERTISEMENT)
+ .setMatchMode(ScanSettings.MATCH_MODE_STICKY)
+ .setLegacy(false)
+ .setPhy(0xCAFE)
+ .build();
+
+ assertEquals(ScanSettings.SCAN_MODE_BALANCED, settings.getScanMode());
+ assertEquals(cbType, settings.getCallbackType());
+ assertEquals(ScanSettings.SCAN_RESULT_TYPE_ABBREVIATED, settings.getScanResultType());
+ assertEquals(0xDEAD, settings.getReportDelayMillis());
+ assertEquals(false, settings.getLegacy());
+ assertEquals(0xCAFE, settings.getPhy());
+ }
+
+
+ @SmallTest
public void testDescribeContents() {
ScanSettings settings = new ScanSettings.Builder().build();
assertEquals(0, settings.describeContents());
diff --git a/tests/tests/car/src/android/car/cts/CarTelemetryManagerTest.java b/tests/tests/car/src/android/car/cts/CarTelemetryManagerTest.java
index 0c62806..9d18368 100644
--- a/tests/tests/car/src/android/car/cts/CarTelemetryManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarTelemetryManagerTest.java
@@ -26,6 +26,8 @@
import android.car.Car;
import android.car.VehiclePropertyIds;
import android.car.telemetry.CarTelemetryManager;
+import android.car.telemetry.TelemetryProto;
+import android.os.PersistableBundle;
import android.platform.test.annotations.RequiresDevice;
import android.util.ArrayMap;
@@ -34,8 +36,6 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.car.telemetry.TelemetryProto;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -261,11 +261,11 @@
private final Semaphore mSemaphore = new Semaphore(0);
private final Map<String, byte[]> mErrorMap = new ArrayMap<>();
- private final Map<String, byte[]> mReportMap = new ArrayMap<>();
+ private final Map<String, PersistableBundle> mReportMap = new ArrayMap<>();
private final Map<String, Integer> mStatusMap = new ArrayMap<>();
@Override
- public void onResult(@NonNull String metricsConfigName, @Nullable byte[] report,
+ public void onResult(@NonNull String metricsConfigName, @Nullable PersistableBundle report,
@Nullable byte[] error, int status) {
mReportMap.put(metricsConfigName, report);
mErrorMap.put(metricsConfigName, error);
diff --git a/tests/tests/car_builtin/AndroidManifest.xml b/tests/tests/car_builtin/AndroidManifest.xml
index d86153d..40e5e09 100644
--- a/tests/tests/car_builtin/AndroidManifest.xml
+++ b/tests/tests/car_builtin/AndroidManifest.xml
@@ -41,6 +41,22 @@
<service android:name="android.car.cts.builtin.os.SharedMemoryTestService"
android:process=":shdmemservice">
</service>
+
+ <activity android:name="android.car.cts.builtin.app.ActivityManagerHelperTest$ActivityA"
+ android:taskAffinity="android.car.cts.builtin.amTestTask1"
+ android:exported="true">
+ </activity>
+
+ <activity android:name="android.car.cts.builtin.app.ActivityManagerHelperTest$ActivityB"
+ android:taskAffinity="android.car.cts.builtin.amTestTask1"
+ android:exported="true">
+ </activity>
+
+ <activity android:name="android.car.cts.builtin.app.ActivityManagerHelperTest$ActivityC"
+ android:taskAffinity="android.car.cts.builtin.amTestTask2"
+ android:exported="true">
+ </activity>
+
<service android:name="android.car.cts.builtin.os.ServiceManagerTestService"
android:process=":testservice">
</service>
diff --git a/tests/tests/car_builtin/AndroidTest.xml b/tests/tests/car_builtin/AndroidTest.xml
index 1bc7a1f..2ace59c 100644
--- a/tests/tests/car_builtin/AndroidTest.xml
+++ b/tests/tests/car_builtin/AndroidTest.xml
@@ -26,6 +26,7 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true"/>
<option name="test-file-name" value="CtsCarBuiltinApiTestCases.apk"/>
+ <option name="test-file-name" value="CtsCarBuiltinSimpleApp.apk"/>
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="setprop log.tag.CAR.TEST VERBOSE" />
diff --git a/tests/tests/car_builtin/apps/SimpleApp/Android.bp b/tests/tests/car_builtin/apps/SimpleApp/Android.bp
new file mode 100644
index 0000000..9e79dc4
--- /dev/null
+++ b/tests/tests/car_builtin/apps/SimpleApp/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsCarBuiltinSimpleApp",
+ defaults: ["cts_defaults"],
+ sdk_version: "current",
+ srcs: [
+ "src/**/*.java",
+ ],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+ static_libs: [
+ "compatibility-device-util-axt",
+ "truth-prebuilt",
+ "ctstestrunner-axt",
+ ],
+ libs: [
+ "android.test.base",
+ "android.car-test-stubs",
+ ],
+}
diff --git a/tests/tests/car_builtin/apps/SimpleApp/AndroidManifest.xml b/tests/tests/car_builtin/apps/SimpleApp/AndroidManifest.xml
new file mode 100644
index 0000000..1a03ca5
--- /dev/null
+++ b/tests/tests/car_builtin/apps/SimpleApp/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.car.cts.builtin.apps.simple">
+ <application>
+ <activity android:name="android.car.cts.builtin.apps.simple.SimpleActivity"
+ android:exported="true">
+ </activity>
+ </application>
+</manifest>
+
diff --git a/tests/tests/car_builtin/apps/SimpleApp/src/android/car/cts/builtin/apps/simple/SimpleActivity.java b/tests/tests/car_builtin/apps/SimpleApp/src/android/car/cts/builtin/apps/simple/SimpleActivity.java
new file mode 100644
index 0000000..1bf376f
--- /dev/null
+++ b/tests/tests/car_builtin/apps/SimpleApp/src/android/car/cts/builtin/apps/simple/SimpleActivity.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.cts.builtin.apps.simple;
+
+import android.app.Activity;
+
+/**
+ * A very simple activity for testing PackageManagerHelper.
+ */
+public final class SimpleActivity extends Activity {
+}
diff --git a/tests/tests/car_builtin/src/android/car/cts/builtin/activity/ActivityManagerTestActivityBase.java b/tests/tests/car_builtin/src/android/car/cts/builtin/activity/ActivityManagerTestActivityBase.java
new file mode 100644
index 0000000..38df2b8
--- /dev/null
+++ b/tests/tests/car_builtin/src/android/car/cts/builtin/activity/ActivityManagerTestActivityBase.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.cts.builtin.activity;
+
+import android.app.Activity;
+import android.util.Log;
+
+public abstract class ActivityManagerTestActivityBase extends Activity {
+ public static final String TAG = ActivityManagerTestActivityBase.class.getSimpleName();
+
+ private volatile boolean mIsVisible;
+ private volatile boolean mHasFocus;
+
+ public boolean isVisible() {
+ return mIsVisible;
+ }
+
+ public boolean hasFocus() {
+ return mHasFocus;
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ mHasFocus = hasFocus;
+ Log.d(TAG, "hasFocus: " + hasFocus);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mIsVisible = true;
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mIsVisible = false;
+ }
+}
diff --git a/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java b/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java
index bc3fc04..f840863 100644
--- a/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java
+++ b/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java
@@ -16,22 +16,49 @@
package android.car.cts.builtin.app;
-import static com.google.common.truth.Truth.assertThat;
+import static android.car.builtin.app.ActivityManagerHelper.ProcessObserverCallback;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.Instrumentation;
+import android.app.TaskInfo;
import android.car.builtin.app.ActivityManagerHelper;
+import android.car.cts.builtin.activity.ActivityManagerTestActivityBase;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Process;
+import android.os.UserHandle;
+import android.server.wm.ActivityManagerTestBase;
+import android.util.Log;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.SystemUtil;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
@RunWith(AndroidJUnit4.class)
-public final class ActivityManagerHelperTest {
+public final class ActivityManagerHelperTest extends ActivityManagerTestBase {
private static final String TAG = ActivityManagerHelperTest.class.getSimpleName();
+ private static final String PERMISSION_SET_ACTIVITY_WATCHER =
+ "android.permission.SET_ACTIVITY_WATCHER";
private static final String NOT_REQUESTED_PERMISSION_CAR_MILEAGE =
"android.car.permission.CAR_MILEAGE";
private static final String NOT_REQUESTED_PERMISSION_READ_CAR_POWER_POLICY =
@@ -39,8 +66,22 @@
private static final String GRANTED_PERMISSION_INTERACT_ACROSS_USERS =
"android.permission.INTERACT_ACROSS_USERS";
+ private static final String PERMISSION_REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+ private static final String PERMISSION_GET_TASKS = "android.permission.GET_TASKS";
+ private static final String PERMISSION_MANAGE_ACTIVITY_TASKS =
+ "android.permission.MANAGE_ACTIVITY_TASKS";
- private static final int OWNING_UID = -1;
+ private static final String SIMPLE_APP_PACKAGE_NAME = "android.car.cts.builtin.apps.simple";
+ private static final String SIMPLE_ACTIVITY_NAME = "SimpleActivity";
+ private static final String START_SIMPLE_ACTIVITY_COMMAND = "am start -W -n "
+ + SIMPLE_APP_PACKAGE_NAME + "/." + SIMPLE_ACTIVITY_NAME;
+
+ private static final int OWNING_UID = UserHandle.ALL.getIdentifier();
+ private static final int MAX_NUM_TASKS = 1_000;
+ private static final int TIMEOUT_MS = 20_000;
+
+ private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ private final Context mContext = mInstrumentation.getContext();
@Test
public void testCheckComponentPermission() throws Exception {
@@ -54,17 +95,96 @@
@Test
public void testSetFocusedRootTask() throws Exception {
- //TODO(b/201005730): implement the test case to test setFocusedRootTask API.
+ // setup
+ ActivityA task1BottomActivity = launchTestActivity(ActivityA.class);
+ ActivityB task1TopActivity = launchTestActivity(ActivityB.class);
+ ActivityC task2TopActivity = launchTestActivity(ActivityC.class);
+
+ logActivityStack("amTestActivitys ",
+ task1BottomActivity, task1TopActivity, task2TopActivity);
+
+ assertWithMessage("bottom activity is the task root")
+ .that(task1BottomActivity.isTaskRoot()).isTrue();
+ assertWithMessage("task id of the top activity in the task1")
+ .that(task1TopActivity.getTaskId()).isEqualTo(task1BottomActivity.getTaskId());
+ assertWithMessage("task id of the top activity in the task2")
+ .that(task2TopActivity.getTaskId()).isNotEqualTo(task1TopActivity.getTaskId());
+ assertWithMessage("task1 top activity is visible")
+ .that(task1TopActivity.isVisible()).isFalse();
+ assertWithMessage("task2 top activity is visible")
+ .that(task2TopActivity.isVisible()).isTrue();
+
+ // execute
+ try {
+ mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(
+ PERMISSION_MANAGE_ACTIVITY_TASKS);
+
+ ActivityManagerHelper.setFocusedRootTask(task1BottomActivity.getTaskId());
+ } finally {
+ mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
+ }
+
+
+ // assert
+ ComponentName activityName = task1TopActivity.getComponentName();
+ waitAndAssertTopResumedActivity(activityName, DEFAULT_DISPLAY,
+ "Activity must be resumed");
+ assertWithMessage("task1 top activity has focus")
+ .that(task1TopActivity.hasFocus()).isTrue();
+ assertWithMessage("task1 top activity is visible")
+ .that(task1TopActivity.isVisible()).isTrue();
+
+ // teardown
+ task1TopActivity.finish();
+ task1BottomActivity.finish();
+ task2TopActivity.finish();
}
@Test
public void testRemoveTask() throws Exception {
- //TODO(b/201005730): implement the test case to test setRemoveTask API.
+ // setup
+ ActivityC testActivity = launchTestActivity(ActivityC.class);
+ int taskId = testActivity.getTaskId();
+ assertThat(doesTaskExist(taskId)).isTrue();
+
+ // execute
+ try {
+ mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(
+ PERMISSION_REMOVE_TASKS);
+
+ ActivityManagerHelper.removeTask(taskId);
+ } finally {
+ mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
+ }
+
+ // assert
+ PollingCheck.waitFor(TIMEOUT_MS, () -> testActivity.isDestroyed());
+ assertThat(doesTaskExist(taskId)).isFalse();
}
@Test
public void testProcessObserverCallback() throws Exception {
- //TODO(b/201005730): implement the test case to test processObserverCallback API.
+ // setup
+ ProcessObserverCallbackTestImpl callbackImpl = new ProcessObserverCallbackTestImpl();
+ launchSimpleActivity();
+
+ // execute
+ try {
+ mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(
+ PERMISSION_SET_ACTIVITY_WATCHER);
+
+ ActivityManagerHelper.registerProcessObserverCallback(callbackImpl);
+
+ ArrayList<Integer> appTasks = getAppTasks(SIMPLE_APP_PACKAGE_NAME);
+ appTasks.forEach((taskId) -> ActivityManagerHelper.removeTask(taskId));
+
+ // assert
+ assertThat(callbackImpl.isProcessDiedObserved()).isTrue();
+ } finally {
+ // teardown
+ ActivityManagerHelper.unregisterProcessObserverCallback(callbackImpl);
+ mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
+ }
}
private void assertComponentPermissionGranted(String permission) throws Exception {
@@ -78,4 +198,100 @@
Process.myUid(), /* owningUid= */ OWNING_UID, /* exported= */ true))
.isEqualTo(PackageManager.PERMISSION_DENIED);
}
+
+ private static final class ProcessObserverCallbackTestImpl extends ProcessObserverCallback {
+ private final CountDownLatch mLatch = new CountDownLatch(1);
+
+ private int mObservedPid = -1;
+ private int mObservedUid = -1;
+ private boolean mProcessDiedObserved;
+
+ @Override
+ public void onProcessDied(int pid, int uid) {
+ mProcessDiedObserved = true;
+ Log.d(TAG, "ProcessDied: pid " + pid + " uid " + uid);
+ mLatch.countDown();
+ }
+
+ public boolean isProcessDiedObserved() throws Exception {
+ if (!mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ throw new Exception("process died is not observed in " + TIMEOUT_MS + " ms)");
+ }
+ return mProcessDiedObserved;
+ }
+ }
+
+ private void launchSimpleActivity() {
+ SystemUtil.runShellCommand(START_SIMPLE_ACTIVITY_COMMAND);
+ }
+
+ private ArrayList<Integer> getAppTasks(String pkgName) {
+ ActivityManager am = mContext.getSystemService(ActivityManager.class);
+
+ List<ActivityManager.RunningTaskInfo> runningTasks = am.getRunningTasks(MAX_NUM_TASKS);
+ ArrayList<Integer> appTasks = new ArrayList<>();
+ for (ActivityManager.RunningTaskInfo taskInfo : runningTasks) {
+ String taskPackageName = taskInfo.baseActivity.getPackageName();
+ int taskId = taskInfo.taskId;
+ Log.d(TAG, "tasks package name: " + taskPackageName);
+ if (taskPackageName.equals(pkgName)) {
+ Log.d(TAG, "getAppTask(): adding " + SIMPLE_APP_PACKAGE_NAME + " task " + taskId);
+ appTasks.add(taskId);
+ }
+ }
+
+ return appTasks;
+ }
+
+ private <T> T launchTestActivity(Class<T> type) {
+ Intent startIntent = new Intent(mContext, type)
+ .addFlags(FLAG_ACTIVITY_NEW_TASK);
+
+ Activity testActivity = (Activity) mInstrumentation
+ .startActivitySync(startIntent, /* options = */ null);
+
+ ComponentName testActivityName = testActivity.getComponentName();
+ waitAndAssertTopResumedActivity(testActivityName, DEFAULT_DISPLAY,
+ "Activity must be resumed");
+
+ return type.cast(testActivity);
+ }
+
+ // The logging order of the Activities follows the stack order. The first Activity
+ // in the parameter list is logged at last.
+ private static void logActivityStack(String msg, Activity... activityStack) {
+ for (int index = activityStack.length - 1; index >= 0; index--) {
+ String logMsg = String.format("%s\tindex=%d taskId=%d",
+ msg, index, activityStack[index].getTaskId());
+ Log.d(TAG, logMsg);
+ }
+ }
+
+ private boolean doesTaskExist(int taskId) {
+ boolean retVal = false;
+ try {
+ mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(
+ PERMISSION_REMOVE_TASKS);
+ ActivityManager am = mContext.getSystemService(ActivityManager.class);
+ List<ActivityManager.RunningTaskInfo> taskList = am.getRunningTasks(MAX_NUM_TASKS);
+ for (TaskInfo taskInfo : taskList) {
+ if (taskInfo.taskId == taskId) {
+ retVal = true;
+ break;
+ }
+ }
+ } finally {
+ mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
+ }
+ return retVal;
+ }
+
+ public static final class ActivityA extends ActivityManagerTestActivityBase {
+ }
+
+ public static final class ActivityB extends ActivityManagerTestActivityBase {
+ }
+
+ public static final class ActivityC extends ActivityManagerTestActivityBase {
+ }
}
diff --git a/tests/tests/car_builtin/src/android/car/cts/builtin/content/pm/PackageManagerHelperTest.java b/tests/tests/car_builtin/src/android/car/cts/builtin/content/pm/PackageManagerHelperTest.java
index 2c2e3f1..9b30f5b 100644
--- a/tests/tests/car_builtin/src/android/car/cts/builtin/content/pm/PackageManagerHelperTest.java
+++ b/tests/tests/car_builtin/src/android/car/cts/builtin/content/pm/PackageManagerHelperTest.java
@@ -23,14 +23,18 @@
import android.car.builtin.content.pm.PackageManagerHelper;
import android.car.cts.builtin.R;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
+import android.os.Process;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Log;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -39,33 +43,37 @@
import org.junit.runner.RunWith;
import java.util.Arrays;
+import java.util.function.ToIntFunction;
@RunWith(AndroidJUnit4.class)
public final class PackageManagerHelperTest {
private static final String TAG = PackageManagerHelperTest.class.getSimpleName();
private static final String ANDROID_CAR_PKG = "com.android.car";
+ private static final String ANDROID_CAR_SHELL_PKG = "com.android.shell";
+ private static final String ANDROID_CAR_SHELL_PKG_SHARED = "shared:android.uid.shell";
private static final String CAR_BUILTIN_CTS_PKG = "android.car.cts.builtin";
+ private static final String[] CAR_BUILTIN_CTS_SERVICE_NAMES = {
+ "android.car.cts.builtin.os.SharedMemoryTestService",
+ "android.car.cts.builtin.os.ServiceManagerTestService"
+ };
private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
private final PackageManager mPackageManager = mContext.getPackageManager();
@Test
public void testGetPackageInfoAsUser() throws Exception {
- // setup
String expectedActivityName = "android.car.cts.builtin.activity.SimpleActivity";
int flags = PackageManager.GET_ACTIVITIES | PackageManager.GET_INSTRUMENTATION
| PackageManager.GET_SERVICES;
int curUser = UserHandle.myUserId();
- // execution
PackageInfo pkgInfoUser = PackageManagerHelper.getPackageInfoAsUser(mPackageManager,
CAR_BUILTIN_CTS_PKG, flags, curUser);
ApplicationInfo appInfo = pkgInfoUser.applicationInfo;
ActivityInfo[] activities = pkgInfoUser.activities;
ServiceInfo[] services = pkgInfoUser.services;
- // assertion
assertThat(appInfo).isNotNull();
assertThat(appInfo.descriptionRes).isEqualTo(R.string.app_description);
assertThat(activities).isNotNull();
@@ -75,13 +83,11 @@
@Test
public void testAppTypeChecking() throws Exception {
- // setup
ApplicationInfo systemApp = mPackageManager
.getApplicationInfo(ANDROID_CAR_PKG, /* flags= */ 0);
ApplicationInfo ctsApp = mPackageManager
.getApplicationInfo(CAR_BUILTIN_CTS_PKG, /* flags= */ 0);
- // execution and assertion
assertThat(PackageManagerHelper.isSystemApp(systemApp)).isTrue();
assertThat(PackageManagerHelper.isUpdatedSystemApp(systemApp)).isFalse();
assertThat(PackageManagerHelper.isSystemExtApp(systemApp)).isFalse();
@@ -101,26 +107,73 @@
@Test
public void testGetSystemUiPackageName() throws Exception {
- // TODO (b/201822684): implement this test case to test getSystemUiPackageName()
- // builtin API
+ String systemuiPackageName = PackageManagerHelper.getSystemUiPackageName(mContext);
+ // The default SystemUI package name is com.android.systemui. But OEMs can override
+ // it via com.android.internal.R.string.config_systemUIServiceComponent.So, it can
+ // not assert with respect to a specific (constant) value.
+ Log.d(TAG, "System UI package name=" + systemuiPackageName);
+ assertThat(systemuiPackageName).isNotNull();
}
@Test
public void testGetNamesForUids() throws Exception {
- // TODO (b/201822684): implement this test case to test getNamesForUids()
- // builtin API
+ String[] initPackageNames = {ANDROID_CAR_SHELL_PKG, CAR_BUILTIN_CTS_PKG};
+ // The CarShell has package name as com.android.shell but it also has sharedUserId as
+ // android.uid.shell. Therefore, the return from Android framework should be
+ // shared:com.android.shell instead of com.android.shell
+ String[][] expectedPackageNames = {
+ {ANDROID_CAR_SHELL_PKG_SHARED, CAR_BUILTIN_CTS_PKG},
+ {ANDROID_CAR_SHELL_PKG_SHARED},
+ {CAR_BUILTIN_CTS_PKG}
+ };
+
+ int[] packageUids = convertPackageNamesToUids(initPackageNames);
+ int[][] packageUidsList = {
+ packageUids,
+ {packageUids[0]},
+ {packageUids[1]}
+ };
+
+ for (int index = 0; index < expectedPackageNames.length; index++) {
+ String[] packageNames = PackageManagerHelper
+ .getNamesForUids(mPackageManager, packageUidsList[index]);
+ assertThat(packageNames).isEqualTo(expectedPackageNames[index]);
+ }
}
@Test
public void testGetPackageUidAsUser() throws Exception {
- // TODO (b/201822684): implement this test case to test getPackageUidAsUser()
- // builtin API
+ int userId = UserHandle.SYSTEM.getIdentifier();
+ int expectedUid = UserHandle.SYSTEM.getUid(Process.SYSTEM_UID);
+
+ // com.android.car package has the shared SYSTEM_UID
+ int actualUid = PackageManagerHelper
+ .getPackageUidAsUser(mPackageManager, ANDROID_CAR_PKG, userId);
+
+ assertThat(actualUid).isEqualTo(expectedUid);
}
@Test
public void testGetComponentName() throws Exception {
- // TODO (b/201822684): implement this test case to test getComponentName()
- // builtin API
+ int flags = PackageManager.GET_ACTIVITIES | PackageManager.GET_INSTRUMENTATION
+ | PackageManager.GET_SERVICES;
+ int curUser = UserHandle.myUserId();
+ PackageInfo pkgInfoUser = PackageManagerHelper.getPackageInfoAsUser(mPackageManager,
+ CAR_BUILTIN_CTS_PKG, flags, curUser);
+ ServiceInfo[] serviceInfos = pkgInfoUser.services;
+
+ assertThat(serviceInfos).isNotNull();
+ ArraySet<String> serviceClassSet = new ArraySet<>();
+ for (ServiceInfo info : serviceInfos) {
+ ComponentName componentName = PackageManagerHelper.getComponentName(info);
+ Log.d(TAG, "class name: " + componentName.flattenToString());
+ assertThat(componentName).isNotNull();
+ assertThat(componentName.getPackageName()).isEqualTo(CAR_BUILTIN_CTS_PKG);
+ serviceClassSet.add(componentName.getClassName());
+ }
+
+ assertThat(serviceClassSet.containsAll(Arrays.asList(CAR_BUILTIN_CTS_SERVICE_NAMES)))
+ .isTrue();
}
@Test
@@ -141,4 +194,17 @@
private boolean hasActivity(String activityName, ActivityInfo[] activities) {
return Arrays.stream(activities).anyMatch(a -> activityName.equals(a.name));
}
+
+ private int[] convertPackageNamesToUids(String[] packageNames) {
+ ToIntFunction<String> packageNameToUid = (pkgName) -> {
+ int uid = Process.INVALID_UID;
+ try {
+ uid = mPackageManager.getPackageUid(pkgName, /* flags= */0);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.wtf(TAG, pkgName + " does not exist", e);
+ }
+ return uid;
+ };
+ return Arrays.stream(packageNames).mapToInt(packageNameToUid).toArray();
+ }
}
diff --git a/tests/tests/car_builtin/src/android/car/cts/builtin/util/EventLogHelperTest.java b/tests/tests/car_builtin/src/android/car/cts/builtin/util/EventLogHelperTest.java
index 7740462..62b7d83 100644
--- a/tests/tests/car_builtin/src/android/car/cts/builtin/util/EventLogHelperTest.java
+++ b/tests/tests/car_builtin/src/android/car/cts/builtin/util/EventLogHelperTest.java
@@ -16,6 +16,11 @@
package android.car.cts.builtin.util;
+import static android.car.cts.builtin.util.LogcatHelper.Buffer.EVENTS;
+import static android.car.cts.builtin.util.LogcatHelper.Level.INFO;
+import static android.car.cts.builtin.util.LogcatHelper.assertLogcatMessage;
+import static android.car.cts.builtin.util.LogcatHelper.clearLog;
+
import android.car.builtin.util.EventLogHelper;
import org.junit.Before;
@@ -24,369 +29,367 @@
public final class EventLogHelperTest {
private static final int TIMEOUT_MS = 10_000;
- // All Eventlogs would be logged to event buffer.
- private static final LogcatHelper.Buffer BUFFER = LogcatHelper.Buffer.EVENTS;
@Before
public void setup() {
- LogcatHelper.clearLog();
+ clearLog();
}
@Test
public void testWriteCarHelperStart() {
EventLogHelper.writeCarHelperStart();
- assertLogMessage("I car_helper_start:");
+ assertLogMessage("car_helper_start");
}
@Test
public void testWriteCarHelperBootPhase() {
EventLogHelper.writeCarHelperBootPhase(1);
- assertLogMessage("I car_helper_boot_phase: 1");
+ assertLogMessage("car_helper_boot_phase", "1");
}
@Test
public void testWriteCarHelperUserStarting() {
EventLogHelper.writeCarHelperUserStarting(100);
- assertLogMessage("I car_helper_user_starting: 100");
+ assertLogMessage("car_helper_user_starting", "100");
}
@Test
public void testWriteCarHelperUserSwitching() {
EventLogHelper.writeCarHelperUserSwitching(100, 101);
- assertLogMessage("I car_helper_user_switching: [100,101]");
+ assertLogMessage("car_helper_user_switching", "[100,101]");
}
@Test
public void testWriteCarHelperUserUnlocking() {
EventLogHelper.writeCarHelperUserUnlocking(100);
- assertLogMessage("I car_helper_user_unlocking: 100");
+ assertLogMessage("car_helper_user_unlocking", "100");
}
@Test
public void testWriteCarHelperUserUnlocked() {
EventLogHelper.writeCarHelperUserUnlocked(100);
- assertLogMessage("I car_helper_user_unlocked: 100");
+ assertLogMessage("car_helper_user_unlocked", "100");
}
@Test
public void testWriteCarHelperUserStopping() {
EventLogHelper.writeCarHelperUserStopping(100);
- assertLogMessage("I car_helper_user_stopping: 100");
+ assertLogMessage("car_helper_user_stopping", "100");
}
@Test
public void testWriteCarHelperUserStopped() {
EventLogHelper.writeCarHelperUserStopped(100);
- assertLogMessage("I car_helper_user_stopped: 100");
+ assertLogMessage("car_helper_user_stopped", "100");
}
@Test
public void testWriteCarHelperServiceConnected() {
EventLogHelper.writeCarHelperServiceConnected();
- assertLogMessage("I car_helper_svc_connected");
+ assertLogMessage("car_helper_svc_connected");
}
@Test
public void testWriteCarServiceInit() {
EventLogHelper.writeCarServiceInit(101);
- assertLogMessage("I car_service_init: 101");
+ assertLogMessage("car_service_init", "101");
}
@Test
public void testWriteCarServiceVhalReconnected() {
EventLogHelper.writeCarServiceVhalReconnected(101);
- assertLogMessage("I car_service_vhal_reconnected: 101");
+ assertLogMessage("car_service_vhal_reconnected", "101");
}
@Test
public void testWriteCarServiceSetCarServiceHelper() {
EventLogHelper.writeCarServiceSetCarServiceHelper(101);
- assertLogMessage("I car_service_set_car_service_helper: 101");
+ assertLogMessage("car_service_set_car_service_helper", "101");
}
@Test
public void testWriteCarServiceOnUserLifecycle() {
EventLogHelper.writeCarServiceOnUserLifecycle(1, 2, 3);
- assertLogMessage("I car_service_on_user_lifecycle: [1,2,3]");
+ assertLogMessage("car_service_on_user_lifecycle", "[1,2,3]");
}
@Test
public void testWriteCarServiceCreate() {
EventLogHelper.writeCarServiceCreate(true);
- assertLogMessage("I car_service_create: 1");
+ assertLogMessage("car_service_create", "1");
}
@Test
public void testWriteCarServiceConnected() {
EventLogHelper.writeCarServiceConnected("testString");
- assertLogMessage("I car_service_connected: testString");
+ assertLogMessage("car_service_connected", "testString");
}
@Test
public void testWriteCarServiceDestroy() {
EventLogHelper.writeCarServiceDestroy(true);
- assertLogMessage("I car_service_destroy: 1");
+ assertLogMessage("car_service_destroy", "1");
}
@Test
public void testWriteCarServiceVhalDied() {
EventLogHelper.writeCarServiceVhalDied(101);
- assertLogMessage("I car_service_vhal_died: 101");
+ assertLogMessage("car_service_vhal_died", "101");
}
@Test
public void testWriteCarServiceInitBootUser() {
EventLogHelper.writeCarServiceInitBootUser();
- assertLogMessage("I car_service_init_boot_user");
+ assertLogMessage("car_service_init_boot_user");
}
@Test
public void testWriteCarServiceOnUserRemoved() {
EventLogHelper.writeCarServiceOnUserRemoved(101);
- assertLogMessage("I car_service_on_user_removed: 101");
+ assertLogMessage("car_service_on_user_removed", "101");
}
@Test
public void testWriteCarUserServiceInitialUserInfoReq() {
EventLogHelper.writeCarUserServiceInitialUserInfoReq(1, 2, 3, 4, 5);
- assertLogMessage("I car_user_svc_initial_user_info_req: [1,2,3,4,5]");
+ assertLogMessage("car_user_svc_initial_user_info_req", "[1,2,3,4,5]");
}
@Test
public void testWriteCarUserServiceInitialUserInfoResp() {
EventLogHelper.writeCarUserServiceInitialUserInfoResp(1, 2, 3, 4, "string1", "string2");
- assertLogMessage("I car_user_svc_initial_user_info_resp: [1,2,3,4,string1,string2]");
+ assertLogMessage("car_user_svc_initial_user_info_resp", "[1,2,3,4,string1,string2]");
}
@Test
public void testWriteCarUserServiceSetInitialUser() {
EventLogHelper.writeCarUserServiceSetInitialUser(101);
- assertLogMessage("I car_user_svc_set_initial_user: 101");
+ assertLogMessage("car_user_svc_set_initial_user", "101");
}
@Test
public void testWriteCarUserServiceSetLifecycleListener() {
EventLogHelper.writeCarUserServiceSetLifecycleListener(101, "string1");
- assertLogMessage("I car_user_svc_set_lifecycle_listener: [101,string1]");
+ assertLogMessage("car_user_svc_set_lifecycle_listener", "[101,string1]");
}
@Test
public void testWriteCarUserServiceResetLifecycleListener() {
EventLogHelper.writeCarUserServiceResetLifecycleListener(101, "string1");
- assertLogMessage("I car_user_svc_reset_lifecycle_listener: [101,string1]");
+ assertLogMessage("car_user_svc_reset_lifecycle_listener", "[101,string1]");
}
@Test
public void testWriteCarUserServiceSwitchUserReq() {
EventLogHelper.writeCarUserServiceSwitchUserReq(101, 102);
- assertLogMessage("I car_user_svc_switch_user_req: [101,102]");
+ assertLogMessage("car_user_svc_switch_user_req", "[101,102]");
}
@Test
public void testWriteCarUserServiceSwitchUserResp() {
EventLogHelper.writeCarUserServiceSwitchUserResp(101, 102, "string");
- assertLogMessage("I car_user_svc_switch_user_resp: [101,102,string]");
+ assertLogMessage("car_user_svc_switch_user_resp", "[101,102,string]");
}
@Test
public void testWriteCarUserServicePostSwitchUserReq() {
EventLogHelper.writeCarUserServicePostSwitchUserReq(101, 102);
- assertLogMessage("I car_user_svc_post_switch_user_req: [101,102]");
+ assertLogMessage("car_user_svc_post_switch_user_req", "[101,102]");
}
@Test
public void testWriteCarUserServiceGetUserAuthReq() {
EventLogHelper.writeCarUserServiceGetUserAuthReq(101, 102, 103);
- assertLogMessage("I car_user_svc_get_user_auth_req: [101,102,103]");
+ assertLogMessage("car_user_svc_get_user_auth_req", "[101,102,103]");
}
@Test
public void testWriteCarUserServiceLogoutUserReq() {
EventLogHelper.writeCarUserServiceLogoutUserReq(101, 102);
- assertLogMessage("I car_user_svc_logout_user_req: [101,102]");
+ assertLogMessage("car_user_svc_logout_user_req", "[101,102]");
}
@Test
public void testWriteCarUserServiceLogoutUserResp() {
EventLogHelper.writeCarUserServiceLogoutUserResp(101, 102, "string");
- assertLogMessage("I car_user_svc_logout_user_resp: [101,102,string]");
+ assertLogMessage("car_user_svc_logout_user_resp", "[101,102,string]");
}
@Test
public void testWriteCarUserServiceGetUserAuthResp() {
EventLogHelper.writeCarUserServiceGetUserAuthResp(101);
- assertLogMessage("I car_user_svc_get_user_auth_resp: 101");
+ assertLogMessage("car_user_svc_get_user_auth_resp", "101");
}
@Test
public void testWriteCarUserServiceSwitchUserUiReq() {
EventLogHelper.writeCarUserServiceSwitchUserUiReq(101);
- assertLogMessage("I car_user_svc_switch_user_ui_req: 101");
+ assertLogMessage("car_user_svc_switch_user_ui_req", "101");
}
@Test
public void testWriteCarUserServiceSwitchUserFromHalReq() {
EventLogHelper.writeCarUserServiceSwitchUserFromHalReq(101, 102);
- assertLogMessage("I car_user_svc_switch_user_from_hal_req: [101,102]");
+ assertLogMessage("car_user_svc_switch_user_from_hal_req", "[101,102]");
}
@Test
public void testWriteCarUserServiceSetUserAuthReq() {
EventLogHelper.writeCarUserServiceSetUserAuthReq(101, 102, 103);
- assertLogMessage("I car_user_svc_set_user_auth_req: [101,102,103]");
+ assertLogMessage("car_user_svc_set_user_auth_req", "[101,102,103]");
}
@Test
public void testWriteCarUserServiceSetUserAuthResp() {
EventLogHelper.writeCarUserServiceSetUserAuthResp(101, "string");
- assertLogMessage("I car_user_svc_set_user_auth_resp: [101,string]");
+ assertLogMessage("car_user_svc_set_user_auth_resp", "[101,string]");
}
@Test
public void testWriteCarUserServiceCreateUserReq() {
EventLogHelper.writeCarUserServiceCreateUserReq("string1", "string2", 101, 102, 103);
- assertLogMessage("I car_user_svc_create_user_req: [string1,string2,101,102,103]");
+ assertLogMessage("car_user_svc_create_user_req", "[string1,string2,101,102,103]");
}
@Test
public void testWriteCarUserServiceCreateUserResp() {
EventLogHelper.writeCarUserServiceCreateUserResp(101, 102, "string");
- assertLogMessage("I car_user_svc_create_user_resp: [101,102,string]");
+ assertLogMessage("car_user_svc_create_user_resp", "[101,102,string]");
}
@Test
public void testWriteCarUserServiceCreateUserUserCreated() {
EventLogHelper.writeCarUserServiceCreateUserUserCreated(101, "string1", "string2", 102);
- assertLogMessage("I car_user_svc_create_user_user_created: [101,string1,string2,102]");
+ assertLogMessage("car_user_svc_create_user_user_created", "[101,string1,string2,102]");
}
@Test
public void testWriteCarUserServiceCreateUserUserRemoved() {
EventLogHelper.writeCarUserServiceCreateUserUserRemoved(101, "string");
- assertLogMessage("I car_user_svc_create_user_user_removed: [101,string]");
+ assertLogMessage("car_user_svc_create_user_user_removed", "[101,string]");
}
@Test
public void testWriteCarUserServiceRemoveUserReq() {
EventLogHelper.writeCarUserServiceRemoveUserReq(101, 102);
- assertLogMessage("I car_user_svc_remove_user_req: [101,102]");
+ assertLogMessage("car_user_svc_remove_user_req", "[101,102]");
}
@Test
public void testWriteCarUserServiceRemoveUserResp() {
EventLogHelper.writeCarUserServiceRemoveUserResp(101, 102);
- assertLogMessage("I car_user_svc_remove_user_resp: [101,102]");
+ assertLogMessage("car_user_svc_remove_user_resp", "[101,102]");
}
@Test
public void testWriteCarUserServiceNotifyAppLifecycleListener() {
EventLogHelper.writeCarUserServiceNotifyAppLifecycleListener(101, "string", 102, 103, 104);
- assertLogMessage("I car_user_svc_notify_app_lifecycle_listener: [101,string,102,103,104]");
+ assertLogMessage("car_user_svc_notify_app_lifecycle_listener", "[101,string,102,103,104]");
}
@Test
public void testWriteCarUserServiceNotifyInternalLifecycleListener() {
EventLogHelper.writeCarUserServiceNotifyInternalLifecycleListener("string", 102, 103, 104);
- assertLogMessage("I car_user_svc_notify_internal_lifecycle_listener: [string,102,103,104]");
+ assertLogMessage("car_user_svc_notify_internal_lifecycle_listener", "[string,102,103,104]");
}
@Test
public void testWriteCarUserServicePreCreationRequested() {
EventLogHelper.writeCarUserServicePreCreationRequested(101, 102);
- assertLogMessage("I car_user_svc_pre_creation_requested: [101,102]");
+ assertLogMessage("car_user_svc_pre_creation_requested", "[101,102]");
}
@Test
public void testWriteCarUserServicePreCreationStatus() {
EventLogHelper.writeCarUserServicePreCreationStatus(101, 102, 103, 104, 105, 106, 107);
- assertLogMessage("I car_user_svc_pre_creation_status: [101,102,103,104,105,106,107]");
+ assertLogMessage("car_user_svc_pre_creation_status", "[101,102,103,104,105,106,107]");
}
@Test
public void testWriteCarUserServiceStartUserInBackgroundReq() {
EventLogHelper.writeCarUserServiceStartUserInBackgroundReq(101);
- assertLogMessage("I car_user_svc_start_user_in_background_req: 101");
+ assertLogMessage("car_user_svc_start_user_in_background_req", "101");
}
@Test
public void testWriteCarUserServiceStartUserInBackgroundResp() {
EventLogHelper.writeCarUserServiceStartUserInBackgroundResp(101, 102);
- assertLogMessage("I car_user_svc_start_user_in_background_resp: [101,102]");
+ assertLogMessage("car_user_svc_start_user_in_background_resp", "[101,102]");
}
@Test
public void testWriteCarUserServiceStopUserReq() {
EventLogHelper.writeCarUserServiceStopUserReq(101);
- assertLogMessage("I car_user_svc_stop_user_req: 101");
+ assertLogMessage("car_user_svc_stop_user_req", "101");
}
@Test
public void testWriteCarUserServiceStopUserResp() {
EventLogHelper.writeCarUserServiceStopUserResp(101, 102);
- assertLogMessage("I car_user_svc_stop_user_resp: [101,102]");
+ assertLogMessage("car_user_svc_stop_user_resp", "[101,102]");
}
@Test
public void testWriteCarUserServiceInitialUserInfoReqComplete() {
EventLogHelper.writeCarUserServiceInitialUserInfoReqComplete(101);
- assertLogMessage("I car_user_svc_initial_user_info_req_complete: 101");
+ assertLogMessage("car_user_svc_initial_user_info_req_complete", "101");
}
@Test
public void testWriteCarUserHalInitialUserInfoReq() {
EventLogHelper.writeCarUserHalInitialUserInfoReq(101, 102, 103);
- assertLogMessage("I car_user_hal_initial_user_info_req: [101,102,103]");
+ assertLogMessage("car_user_hal_initial_user_info_req", "[101,102,103]");
}
@Test
@@ -394,29 +397,29 @@
EventLogHelper.writeCarUserHalInitialUserInfoResp(101, 102, 103, 104, 105, "string1",
"string2");
- assertLogMessage(
- "I car_user_hal_initial_user_info_resp: [101,102,103,104,105,string1,string2]");
+ assertLogMessage("car_user_hal_initial_user_info_resp",
+ "[101,102,103,104,105,string1,string2]");
}
@Test
public void testWriteCarUserHalSwitchUserReq() {
EventLogHelper.writeCarUserHalSwitchUserReq(101, 102, 103, 104);
- assertLogMessage("I car_user_hal_switch_user_req: [101,102,103,104]");
+ assertLogMessage("car_user_hal_switch_user_req", "[101,102,103,104]");
}
@Test
public void testWriteCarUserHalSwitchUserResp() {
EventLogHelper.writeCarUserHalSwitchUserResp(101, 102, 103, "string");
- assertLogMessage("I car_user_hal_switch_user_resp: [101,102,103,string]");
+ assertLogMessage("car_user_hal_switch_user_resp", "[101,102,103,string]");
}
@Test
public void testWriteCarUserHalPostSwitchUserReq() {
EventLogHelper.writeCarUserHalPostSwitchUserReq(101, 102, 103);
- assertLogMessage("I car_user_hal_post_switch_user_req: [101,102,103]");
+ assertLogMessage("car_user_hal_post_switch_user_req", "[101,102,103]");
}
@Test
@@ -426,7 +429,7 @@
};
EventLogHelper.writeCarUserHalGetUserAuthReq(objectArray);
- assertLogMessage("I car_user_hal_get_user_auth_req: [101,102,103,string,104]");
+ assertLogMessage("car_user_hal_get_user_auth_req", "[101,102,103,string,104]");
}
@Test
@@ -436,14 +439,14 @@
};
EventLogHelper.writeCarUserHalGetUserAuthResp(objectArray);
- assertLogMessage("I car_user_hal_get_user_auth_resp: [101,102,103,string,104]");
+ assertLogMessage("car_user_hal_get_user_auth_resp", "[101,102,103,string,104]");
}
@Test
public void testWriteCarUserHalLegacySwitchUserReq() {
EventLogHelper.writeCarUserHalLegacySwitchUserReq(101, 102, 103);
- assertLogMessage("I car_user_hal_legacy_switch_user_req: [101,102,103]");
+ assertLogMessage("car_user_hal_legacy_switch_user_req", "[101,102,103]");
}
@Test
@@ -453,7 +456,7 @@
};
EventLogHelper.writeCarUserHalSetUserAuthReq(objectArray);
- assertLogMessage("I car_user_hal_set_user_auth_req: [101,102,103,string,104]");
+ assertLogMessage("car_user_hal_set_user_auth_req", "[101,102,103,string,104]");
}
@Test
@@ -463,84 +466,84 @@
};
EventLogHelper.writeCarUserHalSetUserAuthResp(objectArray);
- assertLogMessage("I car_user_hal_set_user_auth_resp: [101,102,103,string,104]");
+ assertLogMessage("car_user_hal_set_user_auth_resp", "[101,102,103,string,104]");
}
@Test
public void testWriteCarUserHalOemSwitchUserReq() {
EventLogHelper.writeCarUserHalOemSwitchUserReq(101, 102);
- assertLogMessage("I car_user_hal_oem_switch_user_req: [101,102]");
+ assertLogMessage("car_user_hal_oem_switch_user_req", "[101,102]");
}
@Test
public void testWriteCarUserHalCreateUserReq() {
EventLogHelper.writeCarUserHalCreateUserReq(101, "string", 102, 103);
- assertLogMessage("I car_user_hal_create_user_req: [101,string,102,103]");
+ assertLogMessage("car_user_hal_create_user_req", "[101,string,102,103]");
}
@Test
public void testWriteCarUserHalCreateUserResp() {
EventLogHelper.writeCarUserHalCreateUserResp(101, 102, 103, "string");
- assertLogMessage("I car_user_hal_create_user_resp: [101,102,103,string]");
+ assertLogMessage("car_user_hal_create_user_resp", "[101,102,103,string]");
}
@Test
public void testWriteCarUserHalRemoveUserReq() {
EventLogHelper.writeCarUserHalRemoveUserReq(101, 102);
- assertLogMessage("I car_user_hal_remove_user_req: [101,102]");
+ assertLogMessage("car_user_hal_remove_user_req", "[101,102]");
}
@Test
public void testWriteCarUserManagerAddListener() {
EventLogHelper.writeCarUserManagerAddListener(101, "string", true);
- assertLogMessage("I car_user_mgr_add_listener: [101,string,1]");
+ assertLogMessage("car_user_mgr_add_listener", "[101,string,1]");
}
@Test
public void testWriteCarUserManagerRemoveListener() {
EventLogHelper.writeCarUserManagerRemoveListener(101, "string");
- assertLogMessage("I car_user_mgr_remove_listener: [101,string]");
+ assertLogMessage("car_user_mgr_remove_listener", "[101,string]");
}
@Test
public void testWriteCarUserManagerDisconnected() {
EventLogHelper.writeCarUserManagerDisconnected(101);
- assertLogMessage("I car_user_mgr_disconnected: 101");
+ assertLogMessage("car_user_mgr_disconnected", "101");
}
@Test
public void testWriteCarUserManagerSwitchUserReq() {
EventLogHelper.writeCarUserManagerSwitchUserReq(101, 102);
- assertLogMessage("I car_user_mgr_switch_user_req: [101,102]");
+ assertLogMessage("car_user_mgr_switch_user_req", "[101,102]");
}
@Test
public void testWriteCarUserManagerSwitchUserResp() {
EventLogHelper.writeCarUserManagerSwitchUserResp(101, 102, "string");
- assertLogMessage("I car_user_mgr_switch_user_resp: [101,102,string]");
+ assertLogMessage("car_user_mgr_switch_user_resp", "[101,102,string]");
}
@Test
public void testWriteCarUserManagerLogoutUserReq() {
EventLogHelper.writeCarUserManagerLogoutUserReq(42108);
- assertLogMessage("I car_user_mgr_logout_user_req: [42108]");
+ assertLogMessage("car_user_mgr_logout_user_req", "42108");
}
@Test
public void testWriteCarUserManagerLogoutUserResp() {
EventLogHelper.writeCarUserManagerLogoutUserResp(42108, 1, "D'OH!");
- assertLogMessage("I car_user_mgr_logout_user_resp: [42108,1,D'OH!]");
+ assertLogMessage("car_user_mgr_logout_user_resp", "[42108,1,D'OH!]");
}
@Test
@@ -550,7 +553,7 @@
};
EventLogHelper.writeCarUserManagerGetUserAuthReq(objectArray);
- assertLogMessage("I car_user_mgr_get_user_auth_req: [101,102,103,string,104]");
+ assertLogMessage("car_user_mgr_get_user_auth_req", "[101,102,103,string,104]");
}
@Test
@@ -560,7 +563,7 @@
};
EventLogHelper.writeCarUserManagerGetUserAuthResp(objectArray);
- assertLogMessage("I car_user_mgr_get_user_auth_resp: [101,102,103,string,104]");
+ assertLogMessage("car_user_mgr_get_user_auth_resp", "[101,102,103,string,104]");
}
@Test
@@ -570,7 +573,7 @@
};
EventLogHelper.writeCarUserManagerSetUserAuthReq(objectArray);
- assertLogMessage("I car_user_mgr_set_user_auth_req: [101,102,103,string,104]");
+ assertLogMessage("car_user_mgr_set_user_auth_req", "[101,102,103,string,104]");
}
@Test
@@ -580,136 +583,140 @@
};
EventLogHelper.writeCarUserManagerSetUserAuthResp(objectArray);
- assertLogMessage("I car_user_mgr_set_user_auth_resp: [101,102,103,string,104]");
+ assertLogMessage("car_user_mgr_set_user_auth_resp", "[101,102,103,string,104]");
}
@Test
public void testWriteCarUserManagerCreateUserReq() {
EventLogHelper.writeCarUserManagerCreateUserReq(101, "string1", "string2", 102);
- assertLogMessage("I car_user_mgr_create_user_req: [101,string1,string2,102]");
+ assertLogMessage("car_user_mgr_create_user_req", "[101,string1,string2,102]");
}
@Test
public void testWriteCarUserManagerCreateUserResp() {
EventLogHelper.writeCarUserManagerCreateUserResp(101, 102, "string");
- assertLogMessage("I car_user_mgr_create_user_resp: [101,102,string]");
+ assertLogMessage("car_user_mgr_create_user_resp", "[101,102,string]");
}
@Test
public void testWriteCarUserManagerRemoveUserReq() {
EventLogHelper.writeCarUserManagerRemoveUserReq(101, 102);
- assertLogMessage("I car_user_mgr_remove_user_req: [101,102]");
+ assertLogMessage("car_user_mgr_remove_user_req", "[101,102]");
}
@Test
public void testWriteCarUserManagerRemoveUserResp() {
EventLogHelper.writeCarUserManagerRemoveUserResp(101, 102);
- assertLogMessage("I car_user_mgr_remove_user_resp: [101,102]");
+ assertLogMessage("car_user_mgr_remove_user_resp", "[101,102]");
}
@Test
public void testWriteCarUserManagerNotifyLifecycleListener() {
EventLogHelper.writeCarUserManagerNotifyLifecycleListener(101, 102, 103, 104);
- assertLogMessage("I car_user_mgr_notify_lifecycle_listener: [101,102,103,104]");
+ assertLogMessage("car_user_mgr_notify_lifecycle_listener", "[101,102,103,104]");
}
@Test
public void testWriteCarUserManagerPreCreateUserReq() {
EventLogHelper.writeCarUserManagerPreCreateUserReq(101);
- assertLogMessage("I car_user_mgr_pre_create_user_req: 101");
+ assertLogMessage("car_user_mgr_pre_create_user_req", "101");
}
@Test
public void testWriteCarDevicePolicyManagerRemoveUserReq() {
EventLogHelper.writeCarDevicePolicyManagerRemoveUserReq(101, 102);
- assertLogMessage("I car_dp_mgr_remove_user_req: [101,102]");
+ assertLogMessage("car_dp_mgr_remove_user_req", "[101,102]");
}
@Test
public void testWriteCarDevicePolicyManagerRemoveUserResp() {
EventLogHelper.writeCarDevicePolicyManagerRemoveUserResp(101, 102);
- assertLogMessage("I car_dp_mgr_remove_user_resp: [101,102]");
+ assertLogMessage("car_dp_mgr_remove_user_resp", "[101,102]");
}
@Test
public void testWriteCarDevicePolicyManagerCreateUserReq() {
EventLogHelper.writeCarDevicePolicyManagerCreateUserReq(101, "string", 102);
- assertLogMessage("I car_dp_mgr_create_user_req: [101,string,102]");
+ assertLogMessage("car_dp_mgr_create_user_req", "[101,string,102]");
}
@Test
public void testWriteCarDevicePolicyManagerCreateUserResp() {
EventLogHelper.writeCarDevicePolicyManagerCreateUserResp(101, 102);
- assertLogMessage("I car_dp_mgr_create_user_resp: [101,102]");
+ assertLogMessage("car_dp_mgr_create_user_resp", "[101,102]");
}
@Test
public void testWriteCarDevicePolicyManagerStartUserInBackgroundReq() {
EventLogHelper.writeCarDevicePolicyManagerStartUserInBackgroundReq(101, 102);
- assertLogMessage("I car_dp_mgr_start_user_in_background_req: [101,102]");
+ assertLogMessage("car_dp_mgr_start_user_in_background_req", "[101,102]");
}
@Test
public void testWriteCarDevicePolicyManagerStartUserInBackgroundResp() {
EventLogHelper.writeCarDevicePolicyManagerStartUserInBackgroundResp(101, 102);
- assertLogMessage("I car_dp_mgr_start_user_in_background_resp: [101,102]");
+ assertLogMessage("car_dp_mgr_start_user_in_background_resp", "[101,102]");
}
@Test
public void testWriteCarDevicePolicyManagerStopUserReq() {
EventLogHelper.writeCarDevicePolicyManagerStopUserReq(101, 102);
- assertLogMessage("I car_dp_mgr_stop_user_req: [101,102]");
+ assertLogMessage("car_dp_mgr_stop_user_req", "[101,102]");
}
@Test
public void testWriteCarDevicePolicyManagerStopUserResp() {
EventLogHelper.writeCarDevicePolicyManagerStopUserResp(101, 102);
- assertLogMessage("I car_dp_mgr_stop_user_resp: [101,102]");
+ assertLogMessage("car_dp_mgr_stop_user_resp", "[101,102]");
}
@Test
public void testWritePowerPolicyChange() {
EventLogHelper.writePowerPolicyChange("string");
- assertLogMessage("I car_pwr_mgr_pwr_policy_change: string");
+ assertLogMessage("car_pwr_mgr_pwr_policy_change", "string");
}
@Test
public void testWriteCarPowerManagerStateChange() {
EventLogHelper.writeCarPowerManagerStateChange(101);
- assertLogMessage("I car_pwr_mgr_state_change: 101");
+ assertLogMessage("car_pwr_mgr_state_change", "101");
}
@Test
public void testWriteCarPowerManagerStateRequest() {
EventLogHelper.writeCarPowerManagerStateRequest(101, 102);
- assertLogMessage("I car_pwr_mgr_state_req: [101,102]");
+ assertLogMessage("car_pwr_mgr_state_req", "[101,102]");
}
@Test
public void testWriteGarageModeEvent() {
EventLogHelper.writeGarageModeEvent(101);
- assertLogMessage("I car_pwr_mgr_garage_mode: 101");
+ assertLogMessage("car_pwr_mgr_garage_mode", "101");
}
- private void assertLogMessage(String match) {
- LogcatHelper.assertLogcatMessage(match, BUFFER, TIMEOUT_MS);
+ private void assertLogMessage(String event, String values) {
+ assertLogcatMessage(EVENTS, INFO, event, values, TIMEOUT_MS);
+ }
+
+ private void assertLogMessage(String event) {
+ assertLogMessage(event, /* values=*/ "");
}
}
diff --git a/tests/tests/car_builtin/src/android/car/cts/builtin/util/LogcatHelper.java b/tests/tests/car_builtin/src/android/car/cts/builtin/util/LogcatHelper.java
index f067980..4293f20 100644
--- a/tests/tests/car_builtin/src/android/car/cts/builtin/util/LogcatHelper.java
+++ b/tests/tests/car_builtin/src/android/car/cts/builtin/util/LogcatHelper.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.fail;
import android.app.UiAutomation;
+import android.car.cts.builtin.util.LogcatHelper.Level;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.util.Log;
@@ -39,6 +40,8 @@
private static final boolean VERBOSE = false;
+ private static final int DEFAULT_TIMEOUT_MS = 60_000;
+
private LogcatHelper() {}
/**
@@ -49,31 +52,52 @@
}
/**
- * Asserts if a message appears in logcat messages within given timeout. All logcat buffers are
- * searched.
- *
- * @param match to find in the logcat messages
- * @param timeout for waiting the message
+ * Logcat levels to search.
*/
- public static void assertLogcatMessage(String match, int timeout) {
- assertLogcatMessage(match, Buffer.ALL, timeout);
+ public enum Level {
+ VERBOSE("V"), DEBUG("D"), INFO("I"), WARN("W"), ERROR("E"), ASSERT("A");
+
+ private String mValue;
+
+ public String getValue() {
+ return mValue;
+ }
+
+ Level(String v) {
+ mValue = v;
+ }
}
/**
- * Asserts if a message appears in logcat messages within given timeout in the given buffer.
+ * Asserts that a message appears on {@code logcat}, using a default timeout.
*
- * @param match to find in the logcat messages
- * @param buffer is logcat buffer to search
+ * @param buffer logcat buffer to search
+ * @param level expected log level
+ * @parma tag expected log tag
+ * @param message substring of the expected message
* @param timeout for waiting the message
*/
- public static void assertLogcatMessage(String match, Buffer buffer, int timeout) {
+ public static void assertLogcatMessage(Buffer buffer, Level level, String tag, String message) {
+ assertLogcatMessage(buffer, level, tag, message, DEFAULT_TIMEOUT_MS);
+ }
+
+ /**
+ * Asserts that a message appears on {@code logcat}.
+ *
+ * @param buffer logcat buffer to search
+ * @param level expected log level
+ * @parma tag expected log tag
+ * @param message substring of the expected message
+ * @param timeout for waiting the message
+ */
+ public static void assertLogcatMessage(Buffer buffer, Level level, String tag, String message,
+ int timeout) {
+ String match = String.format("%s %s: %s", level.mValue, tag, message);
long startTime = SystemClock.elapsedRealtime();
UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
String command = "logcat -b " + buffer.name().toLowerCase();
ParcelFileDescriptor output = automation.executeShellCommand(command);
- if (VERBOSE) {
- Log.v(TAG, "ran '" + command + "'; will now look for '" + match + "'");
- }
+ Log.d(TAG, "ran '" + command + "'; will now look for '" + match + "'");
FileDescriptor fd = output.getFileDescriptor();
FileInputStream fileInputStream = new FileInputStream(fd);
try (BufferedReader bufferedReader = new BufferedReader(
@@ -84,9 +108,7 @@
Log.v(TAG, "Checking line '" + line + "'");
}
if (line.contains(match)) {
- if (VERBOSE) {
- Log.v(TAG, "Found match, returning");
- }
+ Log.d(TAG, "Found match on line '" + line + "', returning");
return;
}
if ((SystemClock.elapsedRealtime() - startTime) > timeout) {
@@ -99,13 +121,17 @@
}
/**
- * Asserts if a message does not appears in logcat messages within given timeout. If the message
- * appears, then assertion will fail.
+ * Asserts that a message DOESN'T appears on {@code logcat}.
*
- * @param match to find in the logcat messages
+ * @param buffer is logcat buffer to search
+ * @param level expected log level
+ * @parma tag expected log tag
+ * @param message substring of the message that shouldn't appeard
* @param timeout for waiting the message
*/
- public static void assertNoLogcatMessage(String match, int timeout) throws Exception {
+ public static void assertNoLogcatMessage(Buffer buffer, Level level, String tag, String message,
+ int timeout) throws Exception {
+ String match = String.format("%s %s: %s", level.mValue, tag, message);
long startTime = SystemClock.elapsedRealtime();
UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
ParcelFileDescriptor output = automation.executeShellCommand("logcat -b all");
@@ -131,6 +157,16 @@
* Clears all logs.
*/
public static void clearLog() {
+ if (VERBOSE) {
+ Log.d(TAG, "Clearing logcat logs");
+ }
SystemUtil.runShellCommand("logcat -b all -c");
}
+
+ /**
+ * Sets the log level of the given tag.
+ */
+ public static void setLogLevel(String tag, Level level) {
+ SystemUtil.runShellCommand("setprop log.tag." + tag + " " + level.getValue());
+ }
}
diff --git a/tests/tests/car_builtin/src/android/car/cts/builtin/util/SlogfTest.java b/tests/tests/car_builtin/src/android/car/cts/builtin/util/SlogfTest.java
index 83f630d..1740eb5 100644
--- a/tests/tests/car_builtin/src/android/car/cts/builtin/util/SlogfTest.java
+++ b/tests/tests/car_builtin/src/android/car/cts/builtin/util/SlogfTest.java
@@ -16,28 +16,27 @@
package android.car.cts.builtin.util;
-import static android.car.cts.builtin.util.SlogfTest.Level.ASSERT;
-import static android.car.cts.builtin.util.SlogfTest.Level.DEBUG;
-import static android.car.cts.builtin.util.SlogfTest.Level.ERROR;
-import static android.car.cts.builtin.util.SlogfTest.Level.INFO;
-import static android.car.cts.builtin.util.SlogfTest.Level.VERBOSE;
-import static android.car.cts.builtin.util.SlogfTest.Level.WARN;
+import static android.car.cts.builtin.util.LogcatHelper.Level.ASSERT;
+import static android.car.cts.builtin.util.LogcatHelper.Level.DEBUG;
+import static android.car.cts.builtin.util.LogcatHelper.Level.ERROR;
+import static android.car.cts.builtin.util.LogcatHelper.Level.INFO;
+import static android.car.cts.builtin.util.LogcatHelper.Level.VERBOSE;
+import static android.car.cts.builtin.util.LogcatHelper.Level.WARN;
+import static android.car.cts.builtin.util.LogcatHelper.clearLog;
import static com.google.common.truth.Truth.assertThat;
import android.car.builtin.util.Slogf;
+import android.car.cts.builtin.util.LogcatHelper.Level;
import android.util.Log;
-import com.android.compatibility.common.util.SystemUtil;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public final class SlogfTest {
private static final String TAG = SlogfTest.class.getSimpleName();
- // Comes from Slogf.CAR_TEST_TAG;
- private static final String CAR_TEST_TAG = "CAR.TEST";
+
private static final int TIMEOUT_MS = 10_000;
// All Slogf would be logged to system buffer.
private static final LogcatHelper.Buffer BUFFER = LogcatHelper.Buffer.SYSTEM;
@@ -51,20 +50,6 @@
private static final String FORMATTED_MSG = "This message is a format with two args %s and %s.";
private static final String EXCEPTION_MSG = "This message should exist in logcat.";
- enum Level {
- VERBOSE("V"), DEBUG("D"), INFO("I"), WARN("W"), ERROR("E"), ASSERT("A");
-
- private String mValue;
-
- public String getValue() {
- return mValue;
- }
-
- Level(String v) {
- mValue = v;
- }
- }
-
@Before
public void setup() {
setLogLevel(VERBOSE);
@@ -389,15 +374,24 @@
@Test
public void testIsLoggableFalse() throws Exception {
setLogLevel(ERROR);
+ setCarTestTagLogLevel(ASSERT);
assertThat(Slogf.isLoggable(TAG, Log.VERBOSE)).isFalse();
}
@Test
+ public void testIsLoggableFalse_withCarTestTagEnabled() throws Exception {
+ setLogLevel(ERROR);
+ setCarTestTagLogLevel(VERBOSE);
+
+ assertThat(Slogf.isLoggable(TAG, Log.VERBOSE)).isTrue();
+ }
+
+ @Test
public void testSlogfIsfLoggableWorksSameAsLogIsLoggable() throws Exception {
setLogLevel(INFO);
// Emulate the tag as if it's not in the car tests.
- setLogLevel(CAR_TEST_TAG, ASSERT);
+ setCarTestTagLogLevel(ASSERT);
assertThat(Log.isLoggable(TAG, Log.DEBUG)).isFalse();
assertThat(Slogf.isLoggable(TAG, Log.DEBUG)).isFalse();
@@ -414,29 +408,24 @@
assertThat(Slogf.isLoggable(TAG, Log.DEBUG)).isTrue();
}
- private void clearLog() {
- LogcatHelper.clearLog();
- }
-
private void setLogLevel(Level level) {
- setLogLevel(TAG, level);
+ LogcatHelper.setLogLevel(TAG, level);
}
- private void setLogLevel(String tag, Level level) {
- SystemUtil.runShellCommand("setprop log.tag." + tag + " " + level.getValue());
+ private void setCarTestTagLogLevel(Level level) {
+ // CAR.TEST Comes from Slogf.CAR_TEST_TAG;
+ LogcatHelper.setLogLevel("CAR.TEST", level);
}
private void assertNoLogcatMessage(Level level, String format, Object... args)
throws Exception {
- String match = String.format(LOGCAT_LINE_FORMAT, level.getValue(), TAG,
- String.format(format, args));
- LogcatHelper.assertNoLogcatMessage(match, NOT_LOGGED_WAIT_TIME_MS);
+ String message = String.format(format, args);
+ LogcatHelper.assertNoLogcatMessage(BUFFER, level, TAG, message, NOT_LOGGED_WAIT_TIME_MS);
}
private void assertLogcatMessage(Level level, String format, Object... args) {
- String match = String.format(LOGCAT_LINE_FORMAT, level.getValue(), TAG,
- String.format(format, args));
- LogcatHelper.assertLogcatMessage(match, BUFFER, TIMEOUT_MS);
+ String message = String.format(format, args);
+ LogcatHelper.assertLogcatMessage(BUFFER, level, TAG, message, TIMEOUT_MS);
}
private void assertLogcatStackTrace(Level level, Throwable throwable) {
diff --git a/tests/tests/car_builtin/src/android/car/cts/builtin/util/TimeUtilsTest.java b/tests/tests/car_builtin/src/android/car/cts/builtin/util/TimeUtilsTest.java
index 92393d3..099b5ad 100644
--- a/tests/tests/car_builtin/src/android/car/cts/builtin/util/TimeUtilsTest.java
+++ b/tests/tests/car_builtin/src/android/car/cts/builtin/util/TimeUtilsTest.java
@@ -16,16 +16,26 @@
package android.car.cts.builtin.util;
+import static android.car.cts.builtin.util.LogcatHelper.Buffer.MAIN;
+import static android.car.cts.builtin.util.LogcatHelper.Level.INFO;
+import static android.car.cts.builtin.util.LogcatHelper.assertLogcatMessage;
+import static android.car.cts.builtin.util.LogcatHelper.clearLog;
+
import android.car.builtin.util.TimeUtils;
+import org.junit.Before;
import org.junit.Test;
import java.io.PrintWriter;
public final class TimeUtilsTest {
- private PrintWriter mWriter = new PrintWriter(System.out);
- private static final int TIMEOUT_MS = 60_000;
+ private final PrintWriter mWriter = new PrintWriter(System.out);
+
+ @Before
+ public void clearLogcat() {
+ clearLog();
+ }
@Test
public void testDumpTime() {
@@ -33,7 +43,7 @@
mWriter.flush();
// Time utils change long into date-time format.
- LogcatHelper.assertLogcatMessage("System.out: 1970-01-01 00:00:00.179", TIMEOUT_MS);
+ assertLogMessage("1970-01-01 00:00:00.179");
}
@Test
@@ -42,6 +52,10 @@
mWriter.flush();
// Time utils change long into human readable text.
- LogcatHelper.assertLogcatMessage("System.out: +789ms", TIMEOUT_MS);
+ assertLogMessage("+789ms");
+ }
+
+ private void assertLogMessage(String message) {
+ assertLogcatMessage(MAIN, INFO, "System.out", message);
}
}
diff --git a/tests/tests/car_builtin/src/android/car/cts/builtin/util/TimingsTraceLogTest.java b/tests/tests/car_builtin/src/android/car/cts/builtin/util/TimingsTraceLogTest.java
index 0fec391..0b74a16 100644
--- a/tests/tests/car_builtin/src/android/car/cts/builtin/util/TimingsTraceLogTest.java
+++ b/tests/tests/car_builtin/src/android/car/cts/builtin/util/TimingsTraceLogTest.java
@@ -16,17 +16,25 @@
package android.car.cts.builtin.util;
+import static android.car.cts.builtin.util.LogcatHelper.Buffer.SYSTEM;
+import static android.car.cts.builtin.util.LogcatHelper.Level.DEBUG;
import static android.car.cts.builtin.util.LogcatHelper.assertLogcatMessage;
+import static android.car.cts.builtin.util.LogcatHelper.clearLog;
import android.car.builtin.os.TraceHelper;
import android.car.builtin.util.TimingsTraceLog;
+import org.junit.Before;
import org.junit.Test;
public final class TimingsTraceLogTest {
private static final String TAG = TimingsTraceLogTest.class.getSimpleName();
- private static final int TIMEOUT_MS = 60_000;
+
+ @Before
+ public void clearLogcat() {
+ clearLog();
+ }
@Test
public void testTimingsTraceLog() {
@@ -35,8 +43,7 @@
timingsTraceLog.traceBegin("testTimingsTraceLog");
timingsTraceLog.traceEnd();
- assertLogcatMessage("TimingsTraceLogTest: testTimingsTraceLog took to complete",
- TIMEOUT_MS);
+ assertLogMessage("testTimingsTraceLog took to complete");
}
@Test
@@ -45,8 +52,10 @@
new TimingsTraceLog(TAG, TraceHelper.TRACE_TAG_CAR_SERVICE);
timingsTraceLog.logDuration("testTimingsTraceLogDuration", 159);
- assertLogcatMessage(
- "TimingsTraceLogTest: testTimingsTraceLogDuration took to complete: 159ms",
- TIMEOUT_MS);
+ assertLogMessage("testTimingsTraceLogDuration took to complete: 159ms");
+ }
+
+ private void assertLogMessage(String message) {
+ assertLogcatMessage(SYSTEM, DEBUG, TAG, message);
}
}
diff --git a/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/CompanionDeviceManagerUi.kt b/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/CompanionDeviceManagerUi.kt
index e144dc8..8b8ead8 100644
--- a/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/CompanionDeviceManagerUi.kt
+++ b/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/CompanionDeviceManagerUi.kt
@@ -52,6 +52,9 @@
fun clickNegativeButton() = click(NEGATIVE_BUTTON, "Negative button")
+ fun clickNegativeButtonMultipleDevices() = click(
+ NEGATIVE_BUTTON_MULTIPLE_DEVICES, "Negative button for multiple devices")
+
private fun click(selector: BySelector, description: String) = ui.waitShortAndFind(
Until.findObject(selector), "$description is not found")
.click()
@@ -66,6 +69,8 @@
By.pkg(PACKAGE_NAME).clazz(".Button").clickable(true)
private val POSITIVE_BUTTON = By.copy(CLICKABLE_BUTTON).res(PACKAGE_NAME, "btn_positive")
private val NEGATIVE_BUTTON = By.copy(CLICKABLE_BUTTON).res(PACKAGE_NAME, "btn_negative")
+ private val NEGATIVE_BUTTON_MULTIPLE_DEVICES = By.copy(CLICKABLE_BUTTON)
+ .res(PACKAGE_NAME, "btn_negative_multiple_devices")
private val DEVICE_LIST = By.pkg(PACKAGE_NAME)
.clazz("androidx.recyclerview.widget.RecyclerView")
diff --git a/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/UiAutomationTestBase.kt b/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/UiAutomationTestBase.kt
index 05e9e31a..db46b68 100644
--- a/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/UiAutomationTestBase.kt
+++ b/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/UiAutomationTestBase.kt
@@ -89,7 +89,11 @@
displayName: String? = null
) = test_cancelled(singleDevice, selfManaged, displayName) {
// User "rejects" the request.
- confirmationUi.clickNegativeButton()
+ if (singleDevice || selfManaged) {
+ confirmationUi.clickNegativeButton()
+ } else {
+ confirmationUi.clickNegativeButtonMultipleDevices()
+ }
}
protected fun test_userDismissed(
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandMultiUserTest.kt b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandMultiUserTest.kt
new file mode 100644
index 0000000..d47696e
--- /dev/null
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandMultiUserTest.kt
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.cts
+
+import android.Manifest
+import android.app.UiAutomation
+import android.content.Context
+import android.content.Context.RECEIVER_EXPORTED
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.PackageManager
+import android.content.pm.cts.PackageManagerShellCommandTest.FullyRemovedBroadcastReceiver
+import android.content.pm.cts.util.AbandonAllPackageSessionsRule
+import androidx.test.InstrumentationRegistry
+import com.android.bedstead.harrier.BedsteadJUnit4
+import com.android.bedstead.harrier.DeviceState
+import com.android.bedstead.harrier.annotations.EnsureHasSecondaryUser
+import com.android.bedstead.harrier.annotations.StringTestParameter
+import com.android.bedstead.nene.permissions.CommonPermissions.INTERACT_ACROSS_USERS
+import com.android.bedstead.nene.permissions.CommonPermissions.INTERACT_ACROSS_USERS_FULL
+import com.android.bedstead.nene.users.UserReference
+import com.android.compatibility.common.util.SystemUtil
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotEquals
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.ClassRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.io.File
+
+@EnsureHasSecondaryUser
+@RunWith(BedsteadJUnit4::class)
+class PackageManagerShellCommandMultiUserTest {
+
+ companion object {
+
+ private const val TEST_APP_PACKAGE = PackageManagerShellCommandTest.TEST_APP_PACKAGE
+ private const val TEST_HW5 = PackageManagerShellCommandTest.TEST_HW5
+
+ @JvmField
+ @ClassRule
+ @Rule
+ val deviceState = DeviceState()
+
+ @JvmField
+ @ClassRule
+ var mAbandonSessionsRule = AbandonAllPackageSessionsRule()
+
+ private val context: Context = InstrumentationRegistry.getContext()
+ private val uiAutomation: UiAutomation =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ }
+
+ private lateinit var primaryUser: UserReference
+ private lateinit var secondaryUser: UserReference
+
+ @Before
+ fun cacheUsers() {
+ primaryUser = deviceState.primaryUser()
+ secondaryUser = deviceState.secondaryUser()
+ }
+
+ private var mPackageVerifier: String? = null
+ private var mStreamingVerificationTimeoutMs =
+ PackageManagerShellCommandTest.DEFAULT_STREAMING_VERIFICATION_TIMEOUT
+
+ @Before
+ fun setup() {
+ uninstallPackageSilently(TEST_APP_PACKAGE)
+ assertFalse(PackageManagerShellCommandTest.isAppInstalled(TEST_APP_PACKAGE))
+ mPackageVerifier =
+ SystemUtil.runShellCommand("settings get global verifier_verify_adb_installs")
+ // Disable the package verifier for non-incremental installations to avoid the dialog
+ // when installing an app.
+ SystemUtil.runShellCommand("settings put global verifier_verify_adb_installs 0")
+ mStreamingVerificationTimeoutMs = SystemUtil.runShellCommand(
+ "settings get global streaming_verifier_timeout"
+ )
+ .toLongOrNull()
+ ?: PackageManagerShellCommandTest.DEFAULT_STREAMING_VERIFICATION_TIMEOUT
+ }
+
+ @After
+ fun reset() {
+ uninstallPackageSilently(TEST_APP_PACKAGE)
+ assertFalse(PackageManagerShellCommandTest.isAppInstalled(TEST_APP_PACKAGE))
+ assertEquals(null, PackageManagerShellCommandTest.getSplits(TEST_APP_PACKAGE))
+
+ // Reset the global settings to their original values.
+ SystemUtil.runShellCommand(
+ "settings put global verifier_verify_adb_installs $mPackageVerifier"
+ )
+
+ // Set the test override to invalid.
+ setSystemProperty("debug.pm.uses_sdk_library_default_cert_digest", "invalid")
+ setSystemProperty("debug.pm.prune_unused_shared_libraries_delay", "invalid")
+ setSystemProperty("debug.pm.adb_verifier_override_package", "invalid")
+ }
+
+ @Test
+ fun testGetFirstInstallTime(
+ @StringTestParameter(
+ "install",
+ "install-streaming",
+ "install-incremental"
+ ) installTypeString: String
+ ) {
+ val startTimeMillisForPrimaryUser = System.currentTimeMillis()
+ installPackageAsUser(TEST_HW5, primaryUser, installTypeString)
+ assertTrue(isAppInstalledForUser(TEST_APP_PACKAGE, primaryUser))
+ val origFirstInstallTimeForPrimaryUser =
+ getFirstInstallTimeAsUser(TEST_APP_PACKAGE, primaryUser)
+ // Validate the timestamp
+ assertTrue(origFirstInstallTimeForPrimaryUser > 0)
+ assertTrue(startTimeMillisForPrimaryUser < origFirstInstallTimeForPrimaryUser)
+ assertTrue(System.currentTimeMillis() > origFirstInstallTimeForPrimaryUser)
+
+ // Install again with replace and the firstInstallTime should remain the same
+ installPackage(TEST_HW5, installTypeString)
+ var firstInstallTimeForPrimaryUser =
+ getFirstInstallTimeAsUser(TEST_APP_PACKAGE, primaryUser)
+ assertEquals(origFirstInstallTimeForPrimaryUser, firstInstallTimeForPrimaryUser)
+
+ // Start another user and install this test itself for that user
+ var startTimeMillisForSecondaryUser = System.currentTimeMillis()
+ installExistingPackageAsUser(context.packageName, secondaryUser)
+ assertTrue(isAppInstalledForUser(context.packageName, secondaryUser))
+ // Install test package with replace
+ installPackageAsUser(TEST_HW5, secondaryUser, installTypeString)
+ assertTrue(isAppInstalledForUser(TEST_APP_PACKAGE, secondaryUser))
+ firstInstallTimeForPrimaryUser = getFirstInstallTimeAsUser(TEST_APP_PACKAGE, primaryUser)
+ // firstInstallTime should remain unchanged for the current user
+ assertEquals(origFirstInstallTimeForPrimaryUser, firstInstallTimeForPrimaryUser)
+ var firstInstallTimeForSecondaryUser =
+ getFirstInstallTimeAsUser(TEST_APP_PACKAGE, secondaryUser)
+ // firstInstallTime for the other user should be different
+ assertNotEquals(firstInstallTimeForPrimaryUser, firstInstallTimeForSecondaryUser)
+ assertTrue(startTimeMillisForSecondaryUser < firstInstallTimeForSecondaryUser)
+ assertTrue(System.currentTimeMillis() > firstInstallTimeForSecondaryUser)
+
+ // Uninstall for the other user
+ uninstallPackageAsUser(TEST_APP_PACKAGE, secondaryUser)
+ assertFalse(isAppInstalledForUser(TEST_APP_PACKAGE, secondaryUser))
+ // Install test package as an existing package
+ startTimeMillisForSecondaryUser = System.currentTimeMillis()
+ installExistingPackageAsUser(TEST_APP_PACKAGE, secondaryUser)
+ assertTrue(isAppInstalledForUser(TEST_APP_PACKAGE, secondaryUser))
+ firstInstallTimeForPrimaryUser = getFirstInstallTimeAsUser(TEST_APP_PACKAGE, primaryUser)
+ // firstInstallTime still remains unchanged for the current user
+ assertEquals(origFirstInstallTimeForPrimaryUser, firstInstallTimeForPrimaryUser)
+ firstInstallTimeForSecondaryUser =
+ getFirstInstallTimeAsUser(TEST_APP_PACKAGE, secondaryUser)
+ // firstInstallTime for the other user should be different
+ assertNotEquals(firstInstallTimeForPrimaryUser, firstInstallTimeForSecondaryUser)
+ assertTrue(startTimeMillisForSecondaryUser < firstInstallTimeForSecondaryUser)
+ assertTrue(System.currentTimeMillis() > firstInstallTimeForSecondaryUser)
+
+ // Uninstall for all users
+ uninstallPackageSilently(TEST_APP_PACKAGE)
+ assertFalse(isAppInstalledForUser(TEST_APP_PACKAGE, primaryUser))
+ assertFalse(isAppInstalledForUser(TEST_APP_PACKAGE, secondaryUser))
+ // Reinstall for all users
+ installPackage(TEST_HW5, installTypeString)
+ assertTrue(isAppInstalledForUser(TEST_APP_PACKAGE, primaryUser))
+ assertTrue(isAppInstalledForUser(TEST_APP_PACKAGE, secondaryUser))
+ firstInstallTimeForPrimaryUser = getFirstInstallTimeAsUser(TEST_APP_PACKAGE, primaryUser)
+ // First install time is now different because the package was fully uninstalled
+ assertNotEquals(origFirstInstallTimeForPrimaryUser, firstInstallTimeForPrimaryUser)
+ firstInstallTimeForSecondaryUser =
+ getFirstInstallTimeAsUser(TEST_APP_PACKAGE, secondaryUser)
+ // Same firstInstallTime because package was installed for both users at the same time
+ assertEquals(firstInstallTimeForPrimaryUser, firstInstallTimeForSecondaryUser)
+ }
+
+ @Test
+ fun testPackageFullyRemovedBroadcastAfterUninstall(
+ @StringTestParameter(
+ "install",
+ "install-streaming",
+ "install-incremental"
+ ) installTypeString: String
+ ) {
+ installExistingPackageAsUser(context.packageName, secondaryUser)
+ installPackage(TEST_HW5, installTypeString)
+ assertTrue(isAppInstalledForUser(context.packageName, primaryUser))
+ assertTrue(isAppInstalledForUser(context.packageName, secondaryUser))
+ assertTrue(isAppInstalledForUser(TEST_APP_PACKAGE, primaryUser))
+ assertTrue(isAppInstalledForUser(TEST_APP_PACKAGE, secondaryUser))
+ val broadcastReceiverForPrimaryUser =
+ FullyRemovedBroadcastReceiver(TEST_APP_PACKAGE, primaryUser.id())
+ val broadcastReceiverForSecondaryUser =
+ FullyRemovedBroadcastReceiver(TEST_APP_PACKAGE, secondaryUser.id())
+ val intentFilter = IntentFilter()
+ intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED)
+ intentFilter.addDataScheme("package")
+ context.registerReceiver(
+ broadcastReceiverForPrimaryUser, intentFilter, RECEIVER_EXPORTED
+ )
+ uiAutomation.adoptShellPermissionIdentity(
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL
+ )
+ try {
+ context.createContextAsUser(secondaryUser.userHandle(), 0).registerReceiver(
+ broadcastReceiverForSecondaryUser, intentFilter, RECEIVER_EXPORTED
+ )
+ } finally {
+ uiAutomation.dropShellPermissionIdentity()
+ }
+ // Verify that uninstall with "keep data" doesn't send the broadcast
+ uninstallPackageWithKeepData(TEST_APP_PACKAGE, secondaryUser)
+ assertFalse(broadcastReceiverForSecondaryUser.isBroadcastReceived)
+ installExistingPackageAsUser(TEST_APP_PACKAGE, secondaryUser)
+ // Verify that uninstall on a specific user only sends the broadcast to the user
+ uninstallPackageAsUser(TEST_APP_PACKAGE, secondaryUser)
+ assertTrue(broadcastReceiverForSecondaryUser.isBroadcastReceived)
+ assertFalse(broadcastReceiverForPrimaryUser.isBroadcastReceived)
+ uninstallPackageSilently(TEST_APP_PACKAGE)
+ assertTrue(broadcastReceiverForPrimaryUser.isBroadcastReceived)
+ }
+
+ private fun getFirstInstallTimeAsUser(packageName: String, user: UserReference) =
+ context.createContextAsUser(user.userHandle(), 0)
+ .packageManager
+ .getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0))
+ .firstInstallTime
+
+ private fun installPackage(baseName: String, installTypeString: String) {
+ val file = File(PackageManagerShellCommandTest.createApkPath(baseName))
+ assertThat(SystemUtil.runShellCommand("pm $installTypeString -t -g ${file.path}"))
+ .isEqualTo("Success\n")
+ }
+
+ private fun installExistingPackageAsUser(packageName: String, user: UserReference) {
+ val userId = user.id()
+ assertThat(SystemUtil.runShellCommand("pm install-existing --user $userId $packageName"))
+ .isEqualTo("Package $packageName installed for user: $userId\n")
+ }
+
+ private fun installPackageAsUser(
+ baseName: String,
+ user: UserReference,
+ installTypeString: String
+ ) {
+ val file = File(PackageManagerShellCommandTest.createApkPath(baseName))
+ assertThat(
+ SystemUtil.runShellCommand(
+ "pm $installTypeString -t -g --user ${user.id()} ${file.path}"
+ )
+ )
+ .isEqualTo("Success\n")
+ }
+
+ private fun uninstallPackageAsUser(packageName: String, user: UserReference) =
+ assertThat(SystemUtil.runShellCommand("pm uninstall --user ${user.id()} $packageName"))
+ .isEqualTo("Success\n")
+
+ private fun uninstallPackageWithKeepData(packageName: String, user: UserReference) =
+ SystemUtil.runShellCommand("pm uninstall -k --user ${user.id()} $packageName")
+
+ private fun uninstallPackageSilently(packageName: String) =
+ SystemUtil.runShellCommand("pm uninstall $packageName")
+
+ private fun isAppInstalledForUser(packageName: String, user: UserReference) =
+ SystemUtil.runShellCommand("pm list packages --user ${user.id()} $packageName")
+ .split("\\r?\\n".toRegex())
+ .any { it == "package:$packageName" }
+
+ private fun setSystemProperty(name: String, value: String) =
+ assertThat(SystemUtil.runShellCommand("setprop $name $value"))
+ .isEmpty()
+}
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
index da8a7ab..d923ad7 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
@@ -66,7 +66,6 @@
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.platform.test.annotations.AppModeFull;
import android.util.PackageUtils;
@@ -79,7 +78,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -109,12 +107,12 @@
@RunWith(Parameterized.class)
@AppModeFull
public class PackageManagerShellCommandTest {
- private static final String TEST_APP_PACKAGE = "com.example.helloworld";
+ static final String TEST_APP_PACKAGE = "com.example.helloworld";
private static final String CTS_PACKAGE_NAME = "android.content.cts";
private static final String TEST_APK_PATH = "/data/local/tmp/cts/content/";
- private static final String TEST_HW5 = "HelloWorld5.apk";
+ static final String TEST_HW5 = "HelloWorld5.apk";
private static final String TEST_HW5_SPLIT0 = "HelloWorld5_hdpi-v4.apk";
private static final String TEST_HW5_SPLIT1 = "HelloWorld5_mdpi-v4.apk";
private static final String TEST_HW5_SPLIT2 = "HelloWorld5_xhdpi-v4.apk";
@@ -154,7 +152,7 @@
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
- private static final long DEFAULT_STREAMING_VERIFICATION_TIMEOUT = 3 * 1000;
+ static final long DEFAULT_STREAMING_VERIFICATION_TIMEOUT = 3 * 1000;
@Rule
public AbandonAllPackageSessionsRule mAbandonSessionsRule = new AbandonAllPackageSessionsRule();
@@ -1398,90 +1396,6 @@
}
}
- @Ignore
- @Test
- public void testGetFirstInstallTime() throws Exception {
- final int currentUser = getContext().getUserId();
- final long startTimeMillisForCurrentUser = System.currentTimeMillis();
- installPackage(TEST_HW5);
- assertTrue(isAppInstalledForUser(TEST_APP_PACKAGE, currentUser));
- final long origFirstInstallTimeForCurrentUser = getFirstInstallTimeAsUser(
- TEST_APP_PACKAGE, currentUser);
- // Validate the timestamp
- assertTrue(origFirstInstallTimeForCurrentUser > 0);
- assertTrue(startTimeMillisForCurrentUser < origFirstInstallTimeForCurrentUser);
- assertTrue(System.currentTimeMillis() > origFirstInstallTimeForCurrentUser);
-
- // Install again with replace and the firstInstallTime should remain the same
- installPackage(TEST_HW5);
- long firstInstallTimeForCurrentUser = getFirstInstallTimeAsUser(
- TEST_APP_PACKAGE, currentUser);
- assertEquals(origFirstInstallTimeForCurrentUser, firstInstallTimeForCurrentUser);
-
- // Start another user and install this test itself for that user
- mSecondUser = createUser("Another User");
- assertTrue(startUser(mSecondUser));
- long startTimeMillisForSecondUser = System.currentTimeMillis();
- installExistingPackageAsUser(getContext().getPackageName(), mSecondUser);
- assertTrue(isAppInstalledForUser(getContext().getPackageName(), mSecondUser));
- // Install test package with replace
- installPackageAsUser(TEST_HW5, mSecondUser);
- assertTrue(isAppInstalledForUser(TEST_APP_PACKAGE, mSecondUser));
- firstInstallTimeForCurrentUser = getFirstInstallTimeAsUser(
- TEST_APP_PACKAGE, currentUser);
- // firstInstallTime should remain unchanged for the current user
- assertEquals(origFirstInstallTimeForCurrentUser, firstInstallTimeForCurrentUser);
-
- long firstInstallTimeForSecondUser = getFirstInstallTimeAsUser(
- TEST_APP_PACKAGE, mSecondUser);
- // firstInstallTime for the other user should be different
- assertNotEquals(firstInstallTimeForCurrentUser, firstInstallTimeForSecondUser);
- assertTrue(startTimeMillisForSecondUser < firstInstallTimeForSecondUser);
- assertTrue(System.currentTimeMillis() > firstInstallTimeForSecondUser);
-
- // Uninstall for the other user
- uninstallPackageAsUser(TEST_APP_PACKAGE, mSecondUser);
- assertFalse(isAppInstalledForUser(TEST_APP_PACKAGE, mSecondUser));
- // Install test package as an existing package
- startTimeMillisForSecondUser = System.currentTimeMillis();
- installExistingPackageAsUser(TEST_APP_PACKAGE, mSecondUser);
- assertTrue(isAppInstalledForUser(TEST_APP_PACKAGE, mSecondUser));
-
- firstInstallTimeForCurrentUser = getFirstInstallTimeAsUser(
- TEST_APP_PACKAGE, currentUser);
- // firstInstallTime still remains unchanged for the current user
- assertEquals(origFirstInstallTimeForCurrentUser, firstInstallTimeForCurrentUser);
- firstInstallTimeForSecondUser = getFirstInstallTimeAsUser(TEST_APP_PACKAGE, mSecondUser);
- // firstInstallTime for the other user should be different
- assertNotEquals(firstInstallTimeForCurrentUser, firstInstallTimeForSecondUser);
- assertTrue(startTimeMillisForSecondUser < firstInstallTimeForSecondUser);
- assertTrue(System.currentTimeMillis() > firstInstallTimeForSecondUser);
-
- // Uninstall for all users
- uninstallPackageSilently(TEST_APP_PACKAGE);
- assertFalse(isAppInstalledForUser(TEST_APP_PACKAGE, currentUser));
- assertFalse(isAppInstalledForUser(TEST_APP_PACKAGE, mSecondUser));
- // Reinstall for all users
- installPackage(TEST_HW5);
- assertTrue(isAppInstalledForUser(TEST_APP_PACKAGE, currentUser));
- assertTrue(isAppInstalledForUser(TEST_APP_PACKAGE, mSecondUser));
- firstInstallTimeForCurrentUser = getFirstInstallTimeAsUser(TEST_APP_PACKAGE, currentUser);
- // First install time is now different because the package was fully uninstalled
- assertNotEquals(origFirstInstallTimeForCurrentUser, firstInstallTimeForCurrentUser);
- firstInstallTimeForSecondUser = getFirstInstallTimeAsUser(TEST_APP_PACKAGE, mSecondUser);
- // Same firstInstallTime because package was installed for both users at the same time
- assertEquals(firstInstallTimeForCurrentUser, firstInstallTimeForSecondUser);
- }
-
- private long getFirstInstallTimeAsUser(String packageName, int userId)
- throws PackageManager.NameNotFoundException {
- final Context contextAsUser = getContext().createContextAsUser(UserHandle.of(userId), 0);
- final PackageManager packageManager = contextAsUser.getPackageManager();
- final PackageInfo packageInfo = packageManager.getPackageInfo(packageName,
- PackageManager.PackageInfoFlags.of(0));
- return packageInfo.firstInstallTime;
- }
-
@Test
public void testAppWithNoAppStorageUpdateSuccess() throws Exception {
installPackage(TEST_HW_NO_APP_STORAGE);
@@ -1523,49 +1437,6 @@
assertTrue(isAppInstalled(TEST_APP_PACKAGE));
}
- @Ignore
- @Test
- public void testPackageFullyRemovedBroadcastAfterUninstall() throws IOException {
- final int currentUser = getContext().getUserId();
- // Start another user and install this test itself for that user
- mSecondUser = createUser("Another User");
- assertTrue(startUser(mSecondUser));
- installExistingPackageAsUser(getContext().getPackageName(), mSecondUser);
- installPackage(TEST_HW5);
- assertTrue(isAppInstalledForUser(getContext().getPackageName(), currentUser));
- assertTrue(isAppInstalledForUser(getContext().getPackageName(), mSecondUser));
- assertTrue(isAppInstalledForUser(TEST_APP_PACKAGE, currentUser));
- assertTrue(isAppInstalledForUser(TEST_APP_PACKAGE, mSecondUser));
- final FullyRemovedBroadcastReceiver broadcastReceiverForCurrentUser =
- new FullyRemovedBroadcastReceiver(TEST_APP_PACKAGE, currentUser);
- final FullyRemovedBroadcastReceiver broadcastReceiverForSecondUser =
- new FullyRemovedBroadcastReceiver(TEST_APP_PACKAGE, mSecondUser);
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
- intentFilter.addDataScheme("package");
- getContext().registerReceiver(
- broadcastReceiverForCurrentUser, intentFilter, RECEIVER_EXPORTED);
- getUiAutomation().adoptShellPermissionIdentity(
- android.Manifest.permission.INTERACT_ACROSS_USERS,
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
- try {
- getContext().createContextAsUser(UserHandle.of(mSecondUser), 0).registerReceiver(
- broadcastReceiverForSecondUser, intentFilter, RECEIVER_EXPORTED);
- } finally {
- getUiAutomation().dropShellPermissionIdentity();
- }
- // Verify that uninstall with "keep data" doesn't send the broadcast
- uninstallPackageWithKeepData(TEST_APP_PACKAGE, mSecondUser);
- assertFalse(broadcastReceiverForSecondUser.isBroadcastReceived());
- installExistingPackageAsUser(TEST_APP_PACKAGE, mSecondUser);
- // Verify that uninstall on a specific user only sends the broadcast to the user
- uninstallPackageAsUser(TEST_APP_PACKAGE, mSecondUser);
- assertTrue(broadcastReceiverForSecondUser.isBroadcastReceived());
- assertFalse(broadcastReceiverForCurrentUser.isBroadcastReceived());
- uninstallPackageSilently(TEST_APP_PACKAGE);
- assertTrue(broadcastReceiverForCurrentUser.isBroadcastReceived());
- }
-
@Test
public void testQuerySdkSandboxPackageName() throws Exception {
final PackageManager pm = getPackageManager();
@@ -1601,7 +1472,7 @@
assertEquals(pm.getSdkSandboxPackageName(), names[0]);
}
- private static class FullyRemovedBroadcastReceiver extends BroadcastReceiver {
+ static class FullyRemovedBroadcastReceiver extends BroadcastReceiver {
private final String mTargetPackage;
private final int mTargetUserId;
private final ConditionVariable mUserReceivedBroadcast;
@@ -1694,7 +1565,7 @@
assertEquals("Success\n", executeShellCommand("pm install-commit " + sessionId));
}
- private boolean isAppInstalled(String packageName) throws IOException {
+ static boolean isAppInstalled(String packageName) throws IOException {
final String commandResult = executeShellCommand("pm list packages");
final int prefixLength = "package:".length();
return Arrays.stream(commandResult.split("\\r?\\n")).anyMatch(
@@ -1702,14 +1573,6 @@
packageName));
}
- private boolean isAppInstalledForUser(String packageName, int userId) throws IOException {
- final String commandResult = executeShellCommand(
- String.format("pm list packages --user %d %s", userId, packageName)
- );
- return Arrays.stream(commandResult.split("\\r?\\n"))
- .anyMatch(line -> line.equals("package:" + packageName));
- }
-
private boolean isSdkInstalled(String name, int versionMajor) throws IOException {
final String sdkString = name + ":" + versionMajor;
final String commandResult = executeShellCommand("pm list sdks");
@@ -1735,7 +1598,7 @@
}
}
- private String getSplits(String packageName) throws IOException {
+ static String getSplits(String packageName) throws IOException {
final String commandResult = executeShellCommand("pm dump " + packageName);
final String prefix = " splits=[";
final int prefixLength = prefix.length();
@@ -1748,7 +1611,7 @@
return splits.substring(prefixLength, splits.length() - 1);
}
- private static String createApkPath(String baseName) {
+ static String createApkPath(String baseName) {
return TEST_APK_PATH + baseName;
}
@@ -1766,20 +1629,6 @@
assertTrue(result, result.startsWith(expectedResultStartsWith));
}
- /* Install a package for a new user; this would replace the old package */
- private void installPackageAsUser(String baseName, int userId) throws IOException {
- File file = new File(createApkPath(baseName));
- assertEquals("Success\n", executeShellCommand(
- "pm " + mInstall + " -t -g --user " + userId + " " + file.getPath()));
- }
-
- /* Install an existing package for a new user */
- private void installExistingPackageAsUser(String packageName, int userId) throws IOException {
- String result = executeShellCommand(
- String.format("pm install-existing --user %d %s", userId, packageName));
- assertEquals("Package " + packageName + " installed for user: " + userId + "\n", result);
- }
-
private void updatePackage(String packageName, String baseName) throws IOException {
File file = new File(createApkPath(baseName));
assertEquals("Success\n", executeShellCommand(
@@ -1866,15 +1715,6 @@
return executeShellCommand("pm uninstall " + packageName);
}
- /* Uninstall for one user */
- private void uninstallPackageAsUser(String packageName, int userId) throws IOException {
- executeShellCommand(String.format("pm uninstall --user %d %s", userId, packageName));
- }
-
- private void uninstallPackageWithKeepData(String packageName, int userId) throws IOException {
- executeShellCommand(String.format("pm uninstall -k --user %d %s", userId, packageName));
- }
-
private void uninstallSplits(String packageName, String[] splitNames) throws IOException {
for (String splitName : splitNames) {
assertEquals("Success\n",
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
index d3a045f..bff425b 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
@@ -41,6 +41,8 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import com.google.common.truth.Expect;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -109,6 +111,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParser;
@@ -231,6 +234,8 @@
private final ServiceTestRule mServiceTestRule = new ServiceTestRule();
+ @Rule public final Expect expect = Expect.create();
+
@Before
public void setup() throws Exception {
mContext = InstrumentationRegistry.getContext();
@@ -1738,20 +1743,26 @@
*/
@Test
public void testGetInstalledPackages_WithFactoryFlag_ContainsNoDuplicates() {
+ final Set<String> packageNames = new HashSet<>();
runTestWithFlags(PACKAGE_INFO_MATCH_FLAGS,
- this::testGetInstalledPackages_WithFactoryFlag_ContainsNoDuplicates);
+ flags -> testGetInstalledPackages_WithFactoryFlag_ContainsNoDuplicates(flags,
+ packageNames));
}
- public void testGetInstalledPackages_WithFactoryFlag_ContainsNoDuplicates(int flags) {
+ public void testGetInstalledPackages_WithFactoryFlag_ContainsNoDuplicates(int flags,
+ Set<String> packageNames) {
List<PackageInfo> packageInfos =
mPackageManager.getInstalledPackages(
PackageManager.PackageInfoFlags.of(flags | MATCH_FACTORY_ONLY));
- Set<String> foundPackages = new HashSet<>();
+
+ final Set<String> localPackageNames = new HashSet<>();
for (PackageInfo pi : packageInfos) {
- if (foundPackages.contains(pi.packageName)) {
- throw new AssertionError(pi.packageName + " is listed at least twice.");
+ final String packageName = pi.packageName;
+ // Duplicate: already in local.
+ // Dedup error messages: not in global.
+ if (!localPackageNames.add(pi.packageName) && packageNames.add(packageName)) {
+ expect.withMessage("Duplicate package " + packageName + " detected").fail();
}
- foundPackages.add(pi.packageName);
}
}
diff --git a/tests/tests/content/src/android/content/pm/cts/ResourcesHardeningTest.java b/tests/tests/content/src/android/content/pm/cts/ResourcesHardeningTest.java
index 1c2cbad..272e062 100644
--- a/tests/tests/content/src/android/content/pm/cts/ResourcesHardeningTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ResourcesHardeningTest.java
@@ -290,7 +290,7 @@
private static class RemoteTest implements AutoCloseable {
private static final int SPIN_SLEEP_MS = 500;
- private static final long RESPONSE_TIMEOUT_MS = 60 * 1000;
+ private static final long RESPONSE_TIMEOUT_MS = 120 * 1000;
private final ShellInstallSession mSession;
private final String mTestName;
diff --git a/tests/tests/display/src/android/display/cts/BrightnessTest.java b/tests/tests/display/src/android/display/cts/BrightnessTest.java
index 95c7b5e..73d900f 100644
--- a/tests/tests/display/src/android/display/cts/BrightnessTest.java
+++ b/tests/tests/display/src/android/display/cts/BrightnessTest.java
@@ -66,12 +66,14 @@
private DisplayManager mDisplayManager;
private PowerManager.WakeLock mWakeLock;
private Context mContext;
+ private PackageManager mPackageManager;
@Before
public void setUp() {
mContext = InstrumentationRegistry.getContext();
mDisplayManager = mContext.getSystemService(DisplayManager.class);
PowerManager pm = mContext.getSystemService(PowerManager.class);
+ mPackageManager = mContext.getPackageManager();
mWakeLock = pm.newWakeLock(
PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
@@ -91,6 +93,9 @@
@Test
public void testBrightnessSliderTracking() throws InterruptedException {
+ // Only run if we have a valid ambient light sensor.
+ assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_LIGHT));
+
// Don't run as there is no app that has permission to access slider usage.
assumeTrue(
numberOfSystemAppsWithPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE) > 0);
@@ -174,6 +179,9 @@
@Test
public void testNoColorSampleData() throws InterruptedException {
+ // Only run if we have a valid ambient light sensor.
+ assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_LIGHT));
+
// Don't run as there is no app that has permission to access slider usage.
assumeTrue(
numberOfSystemAppsWithPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE) > 0);
@@ -330,6 +338,9 @@
@Test
public void testSliderEventsReflectCurves() throws InterruptedException {
+ // Only run if we have a valid ambient light sensor.
+ assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_LIGHT));
+
// Don't run as there is no app that has permission to access slider usage.
assumeTrue(
numberOfSystemAppsWithPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE) > 0);
@@ -426,6 +437,9 @@
@Test
public void testSetAndGetPerDisplay() throws InterruptedException{
+ // Only run if we have a valid ambient light sensor.
+ assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_LIGHT));
+
assumeTrue(numberOfSystemAppsWithPermission(
Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) > 0);
diff --git a/tests/tests/dreams/AndroidTest.xml b/tests/tests/dreams/AndroidTest.xml
index cc4c9b5..18f7891 100644
--- a/tests/tests/dreams/AndroidTest.xml
+++ b/tests/tests/dreams/AndroidTest.xml
@@ -19,6 +19,7 @@
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <option name="config-descriptor:metadata" key="parameter" value="all_foldable_states" />
<option name="not-shardable" value="true" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/gameservice/AndroidManifest.xml b/tests/tests/gameservice/AndroidManifest.xml
index a81e64d..936184b 100644
--- a/tests/tests/gameservice/AndroidManifest.xml
+++ b/tests/tests/gameservice/AndroidManifest.xml
@@ -20,6 +20,9 @@
<uses-permission android:name="android.permission.MANAGE_GAME_ACTIVITY"/>
<uses-permission android:name="android.service.games.cts.TEST_START_ACTIVITY"/>
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.MANAGE_MEDIA"/>
<application android:label="CtsGameServiceTestApp">
@@ -47,6 +50,7 @@
</service>
<uses-library android:name="android.test.runner" />
+ <activity android:name="android.service.games.testing.GetResultActivity"/>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/gameservice/src/android/service/games/GameServiceTest.java b/tests/tests/gameservice/src/android/service/games/GameServiceTest.java
index 6d458ae..d95cabe 100644
--- a/tests/tests/gameservice/src/android/service/games/GameServiceTest.java
+++ b/tests/tests/gameservice/src/android/service/games/GameServiceTest.java
@@ -20,30 +20,44 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
+import android.app.Activity;
import android.app.GameManager;
+import android.app.Instrumentation;
+import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Color;
+import android.graphics.ImageDecoder;
import android.graphics.Rect;
+import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
+import android.provider.MediaStore;
import android.service.games.testing.ActivityResult;
+import android.service.games.testing.GetResultActivity;
import android.service.games.testing.IGameServiceTestService;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.Until;
+import android.util.Log;
import android.util.Size;
import android.view.WindowManager;
import android.view.WindowMetrics;
-import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.PollingCheck;
@@ -57,7 +71,11 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized.Parameter;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
@@ -68,6 +86,8 @@
*/
@RunWith(AndroidJUnit4.class)
public final class GameServiceTest {
+ static final String TAG = "GameServiceTest";
+
private static final String GAME_PACKAGE_NAME = "android.service.games.cts.game";
private static final String FALSE_POSITIVE_GAME_PACKAGE_NAME =
"android.service.games.cts.falsepositive";
@@ -83,7 +103,11 @@
private static final String TOUCH_VERIFIER_PACKAGE_NAME =
"android.service.games.cts.touchverifier";
+ @Parameter(0)
+ public String mVolumeName;
+
private ServiceConnection mServiceConnection;
+ private ContentResolver mContentResolver;
@Before
public void setUp() throws Exception {
@@ -106,9 +130,11 @@
GameManager gameManager =
getInstrumentation().getContext().getSystemService(GameManager.class);
+
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(gameManager,
manager -> manager.setGameServiceProvider(
getInstrumentation().getContext().getPackageName()));
+ mContentResolver = getInstrumentation().getContext().getContentResolver();
}
@After
@@ -378,7 +404,7 @@
}
@Test
- public void takeScreenshot_expectedBitmapReturned() throws Exception {
+ public void takeScreenshot_expectedScreenshotSaved() throws Exception {
assumeGameServiceFeaturePresent();
launchAndWaitForPackage(TAKE_SCREENSHOT_VERIFIER_PACKAGE_NAME);
@@ -386,68 +412,131 @@
// Make sure that the overlay is shown so that assertions can be made to check that
// the overlay is excluded from the game screenshot.
getTestService().showOverlayForFocusedGameSession();
- Rect overlayBounds = waitForTouchableOverlayBounds();
+ final Rect overlayBounds = waitForTouchableOverlayBounds();
- Bitmap gameScreenshot = getTestService().getBitmapScreenshotForFocusedGameSession();
+ long startTimeSecs = Instant.now().getEpochSecond();
+ final boolean ret = getTestService().takeScreenshotForFocusedGameSession();
- // Make sure a screenshot was taken and has the same dimensions as the device screen.
- assertNotNull(gameScreenshot);
+ // Make sure a screenshot was taken, saved in media, and has the same dimensions as the
+ // device screen.
+ assertTrue(ret);
+ final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+ final List<Uri> list = new ArrayList<>();
+ try (Cursor cursor = mContentResolver.query(contentUri,
+ new String[]{MediaStore.MediaColumns._ID, MediaStore.MediaColumns.DISPLAY_NAME,
+ MediaStore.MediaColumns.DATE_ADDED}, null, null,
+ MediaStore.MediaColumns.DATE_ADDED + " DESC")) {
+ while (cursor.moveToNext()) {
+ final long addedTimeSecs = cursor.getLong(2);
+ // try to find the latest screenshot file created within 5s
+ if (addedTimeSecs >= startTimeSecs && addedTimeSecs - startTimeSecs < 5) {
+ final long id = cursor.getLong(0);
+ final Uri screenshotUri = ContentUris.withAppendedId(contentUri, id);
+ final String name = cursor.getString(1);
+ Log.d(TAG, "Found screenshot with name " + name);
+ list.add(screenshotUri);
+ final ImageDecoder.Source source = ImageDecoder.createSource(mContentResolver,
+ screenshotUri);
+ // convert the hardware bitmap to a mutable 4-byte bitmap to get/compare pixel
+ final Bitmap gameScreenshot = ImageDecoder.decodeBitmap(source).copy(
+ Bitmap.Config.ARGB_8888, true);
- Size screenSize = getScreenSize();
- assertThat(gameScreenshot.getWidth()).isEqualTo(screenSize.getWidth());
- assertThat(gameScreenshot.getHeight()).isEqualTo(screenSize.getHeight());
+ final Size screenSize = getScreenSize();
+ assertThat(gameScreenshot.getWidth()).isEqualTo(screenSize.getWidth());
+ assertThat(gameScreenshot.getHeight()).isEqualTo(screenSize.getHeight());
- // The test game is always fullscreen red. It is too expensive to verify that the entire
- // bitmap is red, so spot check certain areas.
+ // The test game is always fullscreen red. It is too expensive to verify that
+ // the entire bitmap is red, so spot check certain areas.
- // 1. Make sure that the overlay is excluded from the screenshot by checking pixels within
- // the overlay bounds:
+ // 1. Make sure that the overlay is excluded from the screenshot by checking
+ // pixels within the overlay bounds:
- // top-left of overlay bounds:
- assertThat(
- gameScreenshot.getPixel(overlayBounds.left + 1, overlayBounds.top + 1)).isEqualTo(
- Color.RED);
- // bottom-left corner of overlay bounds:
- assertThat(gameScreenshot.getPixel(overlayBounds.left + 1,
- overlayBounds.bottom - 1)).isEqualTo(Color.RED);
- // top-right corner of overlay bounds:
- assertThat(
- gameScreenshot.getPixel(overlayBounds.right - 1, overlayBounds.top + 1)).isEqualTo(
- Color.RED);
- // bottom-right corner of overlay bounds:
- assertThat(gameScreenshot.getPixel(overlayBounds.right - 1,
- overlayBounds.bottom - 1)).isEqualTo(Color.RED);
- // middle corner of overlay bounds:
- assertThat(gameScreenshot.getPixel((overlayBounds.left + overlayBounds.right) / 2,
- (overlayBounds.top + overlayBounds.bottom) / 2)).isEqualTo(Color.RED);
+ // top-left of overlay bounds:
+ assertThat(
+ gameScreenshot.getPixel(overlayBounds.left + 1,
+ overlayBounds.top + 1)).isEqualTo(
+ Color.RED);
+ // bottom-left corner of overlay bounds:
+ assertThat(gameScreenshot.getPixel(overlayBounds.left + 1,
+ overlayBounds.bottom - 1)).isEqualTo(Color.RED);
+ // top-right corner of overlay bounds:
+ assertThat(
+ gameScreenshot.getPixel(overlayBounds.right - 1,
+ overlayBounds.top + 1)).isEqualTo(
+ Color.RED);
+ // bottom-right corner of overlay bounds:
+ assertThat(gameScreenshot.getPixel(overlayBounds.right - 1,
+ overlayBounds.bottom - 1)).isEqualTo(Color.RED);
+ // middle corner of overlay bounds:
+ assertThat(
+ gameScreenshot.getPixel((overlayBounds.left + overlayBounds.right) / 2,
+ (overlayBounds.top + overlayBounds.bottom) / 2)).isEqualTo(
+ Color.RED);
- // 2. Also check some pixels between the edge of the screen and the overlay bounds:
+ // 2. Also check some pixels between the edge of the screen and the overlay
+ // bounds:
- // above and to the left of the overlay
- assertThat(
- gameScreenshot.getPixel(overlayBounds.left / 2, overlayBounds.top / 2)).isEqualTo(
- Color.RED);
- // below and to the left of the overlay
- assertThat(gameScreenshot.getPixel(overlayBounds.left / 2,
- (overlayBounds.bottom + gameScreenshot.getHeight()) / 2)).isEqualTo(Color.RED);
- // above and to the right of the overlay
- assertThat(gameScreenshot.getPixel((overlayBounds.left + gameScreenshot.getWidth()) / 2,
- overlayBounds.top / 2)).isEqualTo(Color.RED);
- // below and to the right of the overlay
- assertThat(gameScreenshot.getPixel((overlayBounds.left + gameScreenshot.getWidth()) / 2,
- (overlayBounds.bottom + gameScreenshot.getHeight()) / 2)).isEqualTo(Color.RED);
+ // above and to the left of the overlay
+ assertThat(
+ gameScreenshot.getPixel(overlayBounds.left / 2,
+ overlayBounds.top / 2)).isEqualTo(
+ Color.RED);
+ // below and to the left of the overlay
+ assertThat(gameScreenshot.getPixel(overlayBounds.left / 2,
+ (overlayBounds.bottom + gameScreenshot.getHeight()) / 2)).isEqualTo(
+ Color.RED);
+ // above and to the right of the overlay
+ assertThat(gameScreenshot.getPixel(
+ (overlayBounds.left + gameScreenshot.getWidth()) / 2,
+ overlayBounds.top / 2)).isEqualTo(Color.RED);
+ // below and to the right of the overlay
+ assertThat(gameScreenshot.getPixel(
+ (overlayBounds.left + gameScreenshot.getWidth()) / 2,
+ (overlayBounds.bottom + gameScreenshot.getHeight()) / 2)).isEqualTo(
+ Color.RED);
- // 3. Finally check some pixels at the corners of the screen:
+ // 3. Finally check some pixels at the corners of the screen:
- // top-left corner of screen
- assertThat(gameScreenshot.getPixel(0, 0)).isEqualTo(Color.RED);
- // bottom-left corner of screen
- assertThat(gameScreenshot.getPixel(0, gameScreenshot.getHeight() - 1)).isEqualTo(Color.RED);
- // top-right corner of screen
- assertThat(gameScreenshot.getPixel(gameScreenshot.getWidth() - 1, 0)).isEqualTo(Color.RED);
- // bottom-right corner of screen
- assertThat(gameScreenshot.getPixel(gameScreenshot.getWidth() - 1,
- gameScreenshot.getHeight() - 1)).isEqualTo(Color.RED);
+ // top-left corner of screen
+ assertThat(gameScreenshot.getPixel(0, 0)).isEqualTo(Color.RED);
+ // bottom-left corner of screen
+ assertThat(
+ gameScreenshot.getPixel(0, gameScreenshot.getHeight() - 1)).isEqualTo(
+ Color.RED);
+ // top-right corner of screen
+ assertThat(gameScreenshot.getPixel(gameScreenshot.getWidth() - 1, 0)).isEqualTo(
+ Color.RED);
+ // bottom-right corner of screen
+ assertThat(gameScreenshot.getPixel(gameScreenshot.getWidth() - 1,
+ gameScreenshot.getHeight() - 1)).isEqualTo(Color.RED);
+ final PendingIntent pi = MediaStore.createDeleteRequest(mContentResolver,
+ ImmutableList.of(screenshotUri));
+ final GetResultActivity.Result result = startIntentWithGrant(pi);
+ assertEquals(Activity.RESULT_OK, result.resultCode);
+ }
+ }
+ }
+ assertThat(list.size()).isGreaterThan(0);
+ }
+
+ private GetResultActivity.Result startIntentWithGrant(PendingIntent pi) throws Exception {
+ final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+ final Intent intent = new Intent(inst.getContext(), GetResultActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ final UiDevice device = UiDevice.getInstance(inst);
+ final GetResultActivity activity = (GetResultActivity) inst.startActivitySync(intent);
+ inst.waitForIdleSync();
+ activity.mResult.clear();
+ device.waitForIdle();
+ activity.startIntentSenderForResult(pi.getIntentSender(), 42, null, 0, 0, 0);
+ device.waitForIdle();
+ final UiSelector grant = new UiSelector().textMatches("(?i)Allow");
+ final boolean grantExists = new UiObject(grant).waitForExists(5000);
+ if (grantExists) {
+ device.findObject(grant).click();
+ }
+ return activity.getResult();
}
private IGameServiceTestService getTestService() {
diff --git a/tests/tests/gameservice/src/android/service/games/GameServiceTestService.java b/tests/tests/gameservice/src/android/service/games/GameServiceTestService.java
index bd0198f..31a4efd 100644
--- a/tests/tests/gameservice/src/android/service/games/GameServiceTestService.java
+++ b/tests/tests/gameservice/src/android/service/games/GameServiceTestService.java
@@ -20,7 +20,6 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
@@ -154,37 +153,36 @@
}
@Override
- public Bitmap getBitmapScreenshotForFocusedGameSession() {
+ public boolean takeScreenshotForFocusedGameSession() {
+ boolean result = false;
TestGameSession focusedGameSession = TestGameSessionService.getFocusedSession();
- if (focusedGameSession == null) {
- return null;
+ if (focusedGameSession != null) {
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ final boolean[] ret = new boolean[1];
+ ScreenshotCallback callback =
+ new ScreenshotCallback() {
+ @Override
+ public void onFailure(int statusCode) {
+ ret[0] = false;
+ countDownLatch.countDown();
+ }
+
+ @Override
+ public void onSuccess() {
+ ret[0] = true;
+ countDownLatch.countDown();
+ }
+ };
+ focusedGameSession.takeScreenshot(Runnable::run, callback);
+ try {
+ countDownLatch.await(
+ SCREENSHOT_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ result = ret[0];
}
-
- CountDownLatch countDownLatch = new CountDownLatch(1);
- Bitmap[] ret = new Bitmap[1];
- ScreenshotCallback callback =
- new ScreenshotCallback() {
- @Override
- public void onFailure(int statusCode) {
- countDownLatch.countDown();
- }
-
- @Override
- public void onSuccess(Bitmap bitmap) {
- ret[0] = bitmap;
- countDownLatch.countDown();
- }
- };
- focusedGameSession.takeScreenshot(Runnable::run, callback);
-
- try {
- countDownLatch.await(
- SCREENSHOT_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- return null;
- }
-
- return ret[0];
+ return result;
}
public OnSystemBarVisibilityChangedInfo getOnSystemBarVisibilityChangedInfo() {
diff --git a/tests/tests/gameservice/src/android/service/games/testing/GetResultActivity.java b/tests/tests/gameservice/src/android/service/games/testing/GetResultActivity.java
new file mode 100644
index 0000000..87f42dd
--- /dev/null
+++ b/tests/tests/gameservice/src/android/service/games/testing/GetResultActivity.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.games.testing;
+
+import android.app.Activity;
+import android.content.Intent;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+public class GetResultActivity extends Activity {
+ public static class Result {
+ public final int requestCode;
+ public final int resultCode;
+ public final Intent data;
+
+ public Result(int requestCode, int resultCode, Intent data) {
+ this.requestCode = requestCode;
+ this.resultCode = resultCode;
+ this.data = data;
+ }
+ }
+ public LinkedBlockingQueue<Result> mResult = new LinkedBlockingQueue<>();
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ mResult.offer(new Result(requestCode, resultCode, data));
+ finish();
+ }
+
+ public Result getResult() {
+ final Result result;
+ try {
+ result = mResult.poll(20, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ if (result == null) {
+ throw new IllegalStateException("Activity didn't receive a Result in 20 seconds");
+ }
+ return result;
+ }
+}
diff --git a/tests/tests/gameservice/src/android/service/games/testing/IGameServiceTestService.aidl b/tests/tests/gameservice/src/android/service/games/testing/IGameServiceTestService.aidl
index cd227bb..90ed0fe 100644
--- a/tests/tests/gameservice/src/android/service/games/testing/IGameServiceTestService.aidl
+++ b/tests/tests/gameservice/src/android/service/games/testing/IGameServiceTestService.aidl
@@ -16,7 +16,6 @@
package android.service.games.testing;
import android.content.Intent;
-import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Bundle;
import android.service.games.testing.ActivityResult;
@@ -43,7 +42,7 @@
void showOverlayForFocusedGameSession();
- Bitmap getBitmapScreenshotForFocusedGameSession();
+ boolean takeScreenshotForFocusedGameSession();
OnSystemBarVisibilityChangedInfo getOnSystemBarVisibilityChangedInfo();
diff --git a/tests/tests/graphics/src/android/graphics/text/cts/MeasuredTextTest.java b/tests/tests/graphics/src/android/graphics/text/cts/MeasuredTextTest.java
index ec4bcfb..089ce23 100644
--- a/tests/tests/graphics/src/android/graphics/text/cts/MeasuredTextTest.java
+++ b/tests/tests/graphics/src/android/graphics/text/cts/MeasuredTextTest.java
@@ -63,9 +63,9 @@
new MeasuredText.Builder(text.toCharArray())
.appendStyleRun(sPaint, text.length(), false /* isRtl */).build();
- LineBreakConfig config = new LineBreakConfig();
- config.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE);
- config.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
+ LineBreakConfig config = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE).build();
new MeasuredText.Builder(text.toCharArray())
.appendStyleRun(sPaint, config, text.length(), false /* isRtl */).build();
}
diff --git a/tests/tests/hardware/OWNERS b/tests/tests/hardware/OWNERS
index 8001641..21b257e 100644
--- a/tests/tests/hardware/OWNERS
+++ b/tests/tests/hardware/OWNERS
@@ -8,4 +8,4 @@
# Trust that people only touch their own resources.
per-file *.xml=*
# Only input tests use JSON so far
-per-file *.json=svv@google.com
+per-file *.json=file:platform/frameworks/base:/INPUT_OWNERS
diff --git a/tests/tests/hardware/src/android/hardware/input/OWNERS b/tests/tests/hardware/src/android/hardware/input/OWNERS
index b0a2050..c88bfe9 100644
--- a/tests/tests/hardware/src/android/hardware/input/OWNERS
+++ b/tests/tests/hardware/src/android/hardware/input/OWNERS
@@ -1,4 +1 @@
-# Bug component:136048
-lzye@google.com
-michaelwr@google.com
-svv@google.com
+include platform/frameworks/base:/INPUT_OWNERS
diff --git a/tests/tests/keystore/Android.bp b/tests/tests/keystore/Android.bp
index 931f04e..8b18756 100644
--- a/tests/tests/keystore/Android.bp
+++ b/tests/tests/keystore/Android.bp
@@ -117,3 +117,25 @@
// sdk_version: "test_current",
platform_apis: true,
}
+
+android_test {
+ name: "CtsKeystoreWycheproofTestCases",
+ defaults: ["cts_defaults"],
+ manifest: "CtsKeystoreWycheproofTestManifest.xml",
+ test_config: "CtsKeystoreWycheproofTestConfig.xml",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+ libs: [
+ "android.test.base",
+ "android.test.runner",
+ ],
+ static_libs: [
+ "cts-core-test-runner-axt",
+ "wycheproof-keystore",
+ ],
+ // sdk_version: "test_current",
+ platform_apis: true,
+}
diff --git a/tests/tests/keystore/CtsKeystoreWycheproofTestConfig.xml b/tests/tests/keystore/CtsKeystoreWycheproofTestConfig.xml
new file mode 100644
index 0000000..0b09028
--- /dev/null
+++ b/tests/tests/keystore/CtsKeystoreWycheproofTestConfig.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Keystore wycheproof tests">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="security" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsKeystoreWycheproofTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.keystore.cts.wycheproof" />
+ <option name="runtime-hint" value="17m" />
+ <option name="test-timeout" value="34m" />
+ <option name="hidden-api-checks" value="false" />
+ <option name="isolated-storage" value="false" />
+ </test>
+</configuration>
diff --git a/tests/tests/keystore/CtsKeystoreWycheproofTestManifest.xml b/tests/tests/keystore/CtsKeystoreWycheproofTestManifest.xml
new file mode 100644
index 0000000..9ef7249
--- /dev/null
+++ b/tests/tests/keystore/CtsKeystoreWycheproofTestManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.keystore.cts.wycheproof">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.keystore.cts.wycheproof"
+ android:label="CTS tests of android.keystore.cts.wycheproof">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/keystore/src/android/keystore/cts/Curve25519Test.java b/tests/tests/keystore/src/android/keystore/cts/Curve25519Test.java
index 7feecd1..30bd40b 100644
--- a/tests/tests/keystore/src/android/keystore/cts/Curve25519Test.java
+++ b/tests/tests/keystore/src/android/keystore/cts/Curve25519Test.java
@@ -37,6 +37,7 @@
import java.security.NoSuchProviderException;
import java.security.ProviderException;
import java.security.spec.ECGenParameterSpec;
+import java.security.spec.NamedParameterSpec;
@RunWith(AndroidJUnit4.class)
public class Curve25519Test {
@@ -119,4 +120,34 @@
assertThrows(InvalidAlgorithmParameterException.class, () -> kpg.initialize(keySpec));
}
+
+ @Test
+ public void x25519CannotCreateKeyUsingKPGWithNamedParameterSpec()
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidAlgorithmParameterException {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("XDH", "AndroidKeyStore");
+
+ NamedParameterSpec paramSpec = new NamedParameterSpec("X25519");
+ try {
+ kpg.initialize(paramSpec);
+ fail("Should not be able to generate keys using NamedParameterSpec");
+ } catch (IllegalArgumentException e) {
+ assertThat(e.getMessage()).contains("cannot be initialized using NamedParameterSpec");
+ }
+ }
+
+ @Test
+ public void ed25519CannotCreateKeyUsingKPGWithNamedParameterSpec()
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidAlgorithmParameterException {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("XDH", "AndroidKeyStore");
+
+ NamedParameterSpec paramSpec = new NamedParameterSpec("Ed25519");
+ try {
+ kpg.initialize(paramSpec);
+ fail("Should not be able to generate keys using NamedParameterSpec");
+ } catch (IllegalArgumentException e) {
+ assertThat(e.getMessage()).contains("cannot be initialized using NamedParameterSpec");
+ }
+ }
}
\ No newline at end of file
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index d182cfc..d5f919a 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -80,6 +80,8 @@
import androidx.test.filters.RequiresDevice;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.CddTest;
+
import com.google.common.collect.ImmutableSet;
import org.bouncycastle.asn1.x500.X500Name;
@@ -726,6 +728,7 @@
testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_MEID, "Unable to retrieve MEID");
}
+ @CddTest(requirement="9.11.4")
@Test
public void testMandatoryDeviceidAttestation() {
// ID attestation is only mandatory on devices that have shipped with T and
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyFactoryTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyFactoryTest.java
index 98cb2c3..8c6759d 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyFactoryTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyFactoryTest.java
@@ -22,8 +22,8 @@
import static org.junit.Assert.fail;
import android.content.Context;
-import android.keystore.cts.util.TestUtils;
import android.keystore.cts.R;
+import android.keystore.cts.util.TestUtils;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyInfo;
import android.security.keystore.KeyProperties;
@@ -32,6 +32,9 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
@@ -41,6 +44,8 @@
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.Provider;
+import java.security.Provider.Service;
+import java.security.PublicKey;
import java.security.Security;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPublicKey;
@@ -52,8 +57,6 @@
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
-import java.security.Provider.Service;
-import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
@@ -65,9 +68,6 @@
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
@RunWith(AndroidJUnit4.class)
public class KeyFactoryTest {
private static final String EXPECTED_PROVIDER_NAME = TestUtils.EXPECTED_PROVIDER_NAME;
@@ -94,6 +94,9 @@
Set<String> actualAlgsLowerCase = new HashSet<String>();
Set<String> expectedAlgsLowerCase = new HashSet<String>(
Arrays.asList(TestUtils.toLowerCase(EXPECTED_ALGORITHMS)));
+ // XDH is also a supported algorithm, but not available for other tests as the keys
+ // generated with it have more limited set of uses.
+ expectedAlgsLowerCase.add("xdh");
for (Service service : services) {
if ("KeyFactory".equalsIgnoreCase(service.getType())) {
String algLowerCase = service.getAlgorithm().toLowerCase(Locale.US);
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java b/tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java
index 5820089..ff1944e 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java
@@ -16,6 +16,7 @@
package android.media.codec.cts;
+import android.content.Context;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
@@ -23,16 +24,31 @@
import android.media.cts.InputSurface;
import android.media.cts.OutputSurface;
import android.opengl.GLES20;
-import android.test.AndroidTestCase;
import android.util.Log;
+import androidx.test.platform.app.InstrumentationRegistry;
+
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.Arrays;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import com.android.compatibility.common.util.MediaUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+import static org.junit.Assert.fail;
/**
* This test has three steps:
@@ -48,15 +64,14 @@
* no longer exercising the code in the way we expect it to be used (and the code
* gets a bit unwieldy).
*/
-public class DecodeEditEncodeTest extends AndroidTestCase {
+@RunWith(Parameterized.class)
+public class DecodeEditEncodeTest {
private static final String TAG = "DecodeEditEncode";
private static final boolean WORK_AROUND_BUGS = false; // avoid fatal codec bugs
private static final boolean VERBOSE = false; // lots of logging
private static final boolean DEBUG_SAVE_FILE = false; // save copy of encoded movie
// parameters for the encoder
- // H.264 Advanced Video Coding
- private static final String MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_AVC;
private static final int FRAME_RATE = 15; // 15fps
private static final int IFRAME_INTERVAL = 10; // 10 seconds between I-frames
private static final String KEY_ALLOW_FRAME_DROP = "allow-frame-drop";
@@ -93,26 +108,73 @@
" gl_FragColor = texture2D(sTexture, vTextureCoord).rbga;\n" +
"}\n";
+ // component names
+ private final String mEncoderName;
+ private final String mDecoderName;
+ // mime
+ private final String mMediaType;
// size of a frame, in pixels
- private int mWidth = -1;
- private int mHeight = -1;
+ private final int mWidth;
+ private final int mHeight;
// bit rate, in bits per second
- private int mBitRate = -1;
+ private final int mBitRate;
// largest color component delta seen (i.e. actual vs. expected)
private int mLargestColorDelta;
+ static private List<Object[]> prepareParamList(List<Object[]> exhaustiveArgsList) {
+ final List<Object[]> argsList = new ArrayList<>();
+ int argLength = exhaustiveArgsList.get(0).length;
+ for (Object[] arg : exhaustiveArgsList) {
+ String[] encoderNamesForMime = MediaUtils.getEncoderNamesForMime((String)arg[0]);
+ String[] decoderNamesForMime = MediaUtils.getDecoderNamesForMime((String)arg[0]);
+ Object[] testArgs = new Object[argLength + 2];
+ // Add encoder name and decoder name as first two arguments and then
+ // copy arguments passed
+ testArgs[0] = encoderNamesForMime[0];
+ testArgs[1] = decoderNamesForMime[0];
+ System.arraycopy(arg, 0, testArgs, 2, argLength);
+ argsList.add(testArgs);
+ }
+ return argsList;
+ }
- public void testVideoEditQCIF() throws Throwable {
- setParameters(176, 144, 1100000);
- VideoEditWrapper.runTest(this);
+ @Before
+ public void shouldSkip() {
+ MediaFormat format = MediaFormat.createVideoFormat(mMediaType, mWidth, mHeight);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);
+ format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
+ format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
+ assumeTrue(MediaUtils.supports(mEncoderName, format));
+ assumeTrue(MediaUtils.supports(mDecoderName, format));
}
- public void testVideoEditQVGA() throws Throwable {
- setParameters(320, 240, 2000000);
- VideoEditWrapper.runTest(this);
+
+ @Parameterized.Parameters(name = "{index}({0}_{1}_{2}_{3}_{4})")
+ public static Collection<Object[]> input() {
+ final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+ // mediaType, width, height, bitrate
+ {MediaFormat.MIMETYPE_VIDEO_AVC, 176, 144, 1000000},
+ {MediaFormat.MIMETYPE_VIDEO_AVC, 320, 240, 2000000},
+ {MediaFormat.MIMETYPE_VIDEO_AVC, 1280, 720, 6000000},
+ });
+ return prepareParamList(exhaustiveArgsList);
}
- public void testVideoEdit720p() throws Throwable {
- setParameters(1280, 720, 6000000);
+
+ public DecodeEditEncodeTest(String encoder, String decoder, String mimeType, int width,
+ int height, int bitRate) {
+ if ((width % 16) != 0 || (height % 16) != 0) {
+ Log.w(TAG, "WARNING: width or height not multiple of 16");
+ }
+ mEncoderName = encoder;
+ mDecoderName = decoder;
+ mMediaType = mimeType;
+ mWidth = width;
+ mHeight = height;
+ mBitRate = bitRate;
+ }
+
+ @Test
+ public void testVideoEdit() throws Throwable {
VideoEditWrapper.runTest(this);
}
@@ -151,18 +213,6 @@
}
/**
- * Sets the desired frame size and bit rate.
- */
- private void setParameters(int width, int height, int bitRate) {
- if ((width % 16) != 0 || (height % 16) != 0) {
- Log.w(TAG, "WARNING: width or height not multiple of 16");
- }
- mWidth = width;
- mHeight = height;
- mBitRate = bitRate;
- }
-
- /**
* Tests editing of a video file with GL.
*/
private void videoEditTest()
@@ -177,7 +227,8 @@
if (DEBUG_SAVE_FILE) {
// Save a copy to a file. We call it ".mp4", but it's actually just an elementary
// stream, so not all video players will know what to do with it.
- String dirName = getContext().getFilesDir().getAbsolutePath();
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ String dirName = context.getFilesDir().getAbsolutePath();
String fileName = "vedit1_" + mWidth + "x" + mHeight + ".mp4";
sourceChunks.saveToFile(new File(dirName, fileName));
}
@@ -185,7 +236,8 @@
VideoChunks destChunks = editVideoFile(sourceChunks);
if (DEBUG_SAVE_FILE) {
- String dirName = getContext().getFilesDir().getAbsolutePath();
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ String dirName = context.getFilesDir().getAbsolutePath();
String fileName = "vedit2_" + mWidth + "x" + mHeight + ".mp4";
destChunks.saveToFile(new File(dirName, fileName));
}
@@ -208,15 +260,7 @@
try {
// We avoid the device-specific limitations on width and height by using values that
// are multiples of 16, which all tested devices seem to be able to handle.
- MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);
-
- String codecName = selectCodec(format);
- if (codecName == null) {
- // Don't fail CTS if they don't have an AVC codec (not here, anyway).
- Log.e(TAG, "Unable to find an appropriate codec for " + MIME_TYPE);
- return false;
- }
- if (VERBOSE) Log.d(TAG, "found codec: " + codecName);
+ MediaFormat format = MediaFormat.createVideoFormat(mMediaType, mWidth, mHeight);
// Set some properties. Failing to specify some of these can cause the MediaCodec
// configure() call to throw an unhelpful exception.
@@ -230,7 +274,7 @@
// Create a MediaCodec for the desired codec, then configure it as an encoder with
// our desired properties.
- encoder = MediaCodec.createByCodecName(codecName);
+ encoder = MediaCodec.createByCodecName(mEncoderName);
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
inputSurface = new InputSurface(encoder.createInputSurface());
inputSurface.makeCurrent();
@@ -253,15 +297,6 @@
}
/**
- * Returns the first codec capable of encoding the specified MIME type, or null if no
- * match was found.
- */
- private static String selectCodec(MediaFormat format) {
- MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
- return mcl.findEncoderForFormat(format);
- }
-
- /**
* Generates video frames, feeds them into the encoder, and writes the output to the
* VideoChunks instance.
*/
@@ -411,7 +446,7 @@
// Create an encoder format that matches the input format. (Might be able to just
// re-use the format used to generate the video, since we want it to be the same.)
- MediaFormat outputFormat = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);
+ MediaFormat outputFormat = MediaFormat.createVideoFormat(mMediaType, mWidth, mHeight);
outputFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
outputFormat.setInteger(MediaFormat.KEY_BIT_RATE,
@@ -423,14 +458,14 @@
outputData.setMediaFormat(outputFormat);
- encoder = MediaCodec.createEncoderByType(MIME_TYPE);
+ encoder = MediaCodec.createByCodecName(mEncoderName);
encoder.configure(outputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
inputSurface = new InputSurface(encoder.createInputSurface());
inputSurface.makeCurrent();
encoder.start();
// OutputSurface uses the EGL context created by InputSurface.
- decoder = MediaCodec.createDecoderByType(MIME_TYPE);
+ decoder = MediaCodec.createByCodecName(mDecoderName);
outputSurface = new OutputSurface();
outputSurface.changeFragmentShader(FRAGMENT_SHADER);
// do not allow frame drops
@@ -639,7 +674,7 @@
surface = new OutputSurface(mWidth, mHeight);
MediaFormat format = inputData.getMediaFormat();
- decoder = MediaCodec.createDecoderByType(MIME_TYPE);
+ decoder = MediaCodec.createByCodecName(mDecoderName);
format.setInteger(KEY_ALLOW_FRAME_DROP, 0);
decoder.configure(format, surface.getSurface(), null, 0);
decoder.start();
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayTest.java b/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayTest.java
index 9250141..5ef9e7f 100755
--- a/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayTest.java
@@ -47,6 +47,7 @@
import android.widget.ImageView;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.ApiLevelUtil;
import com.android.compatibility.common.util.MediaUtils;
@@ -55,8 +56,19 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
/**
* Tests connecting a virtual display to the input of a MediaCodec encoder.
@@ -77,36 +89,24 @@
@Presubmit
@SmallTest
@RequiresDevice
-public class EncodeVirtualDisplayTest extends AndroidTestCase {
+@RunWith(Parameterized.class)
+public class EncodeVirtualDisplayTest {
private static final String TAG = "EncodeVirtualTest";
private static final boolean VERBOSE = false; // lots of logging
private static final boolean DEBUG_SAVE_FILE = false; // save copy of encoded movie
private static final String DEBUG_FILE_NAME_BASE = "/sdcard/test.";
-
- // Encoder parameters table, sort by encoder level from high to low.
- private static final int[][] ENCODER_PARAM_TABLE = {
- // width, height, bitrate, framerate /* level */
- { 1280, 720, 14000000, 30 }, /* AVCLevel31 */
- { 720, 480, 10000000, 30 }, /* AVCLevel3 */
- { 720, 480, 4000000, 15 }, /* AVCLevel22 */
- { 352, 576, 4000000, 25 }, /* AVCLevel21 */
- };
+ private static final String CODEC_PREFIX_KEY = "codec-prefix";
+ private static String mCodecPrefix;
// Virtual display characteristics. Scaled down from full display size because not all
// devices can encode at the resolution of their own display.
private static final String NAME = TAG;
- private static int sWidth = ENCODER_PARAM_TABLE[ENCODER_PARAM_TABLE.length-1][0];
- private static int sHeight = ENCODER_PARAM_TABLE[ENCODER_PARAM_TABLE.length-1][1];
private static final int DENSITY = DisplayMetrics.DENSITY_HIGH;
private static final int UI_TIMEOUT_MS = 2000;
private static final int UI_RENDER_PAUSE_MS = 400;
- // Encoder parameters. We use the same width/height as the virtual display.
- private static final String MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_AVC;
- private static int sFrameRate = 15; // 15fps
// 100 days between I-frames
private static final int IFRAME_INTERVAL = 60 * 60 * 24 * 100;
- private static int sBitRate = 6000000; // 6Mbps
// Colors to test (RGB). These must convert cleanly to and from BT.601 YUV.
private static final int TEST_COLORS[] = {
@@ -123,6 +123,14 @@
private Handler mUiHandler; // Handler on main Looper
private DisplayManager mDisplayManager;
volatile boolean mInputDone;
+ private Context mContext;
+ private String mEncoderName;
+ private String mMediaType;
+ private int mWidth;
+ private int mHeight;
+ private int mBitRate;
+ private int mFrameRate;
+ private MediaFormat mFormat;
/* TEST_COLORS static initialization; need ARGB for ColorDrawable */
private static int makeColor(int red, int green, int blue) {
@@ -132,13 +140,57 @@
private static boolean sIsAtLeastR = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
private static boolean sIsAtLeastS = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S);
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ public EncodeVirtualDisplayTest(String encodername, String mediaType, int width, int height,
+ int bitrate, int framerate, @SuppressWarnings("unused") String level) {
+ mEncoderName = encodername;
+ mMediaType = mediaType;
+ mWidth = width;
+ mHeight = height;
+ mBitRate = bitrate;
+ mFrameRate = framerate;
+ }
+ @Before
+ public void setUp() throws Exception {
mUiHandler = new Handler(Looper.getMainLooper());
+ mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
mDisplayManager = (DisplayManager)mContext.getSystemService(Context.DISPLAY_SERVICE);
- setupEncoderParameters();
+ }
+
+ static private List<Object[]> prepareParamList(List<Object[]> exhaustiveArgsList) {
+ final List<Object[]> argsList = new ArrayList<>();
+ int argLength = exhaustiveArgsList.get(0).length;
+ for (Object[] arg : exhaustiveArgsList) {
+ String[] componentNames = MediaUtils.getEncoderNamesForMime((String)arg[0]);
+ for (String name : componentNames) {
+ if (mCodecPrefix != null && !name.startsWith(mCodecPrefix)) {
+ continue;
+ }
+ Object[] testArgs = new Object[argLength + 1];
+ // Add codec name as first argument and then copy all other arguments passed
+ testArgs[0] = name;
+ System.arraycopy(arg, 0, testArgs, 1, argLength);
+ argsList.add(testArgs);
+ }
+ }
+ return argsList;
+ }
+
+ static {
+ android.os.Bundle args = InstrumentationRegistry.getArguments();
+ mCodecPrefix = args.getString(CODEC_PREFIX_KEY);
+ }
+
+ @Parameterized.Parameters(name = "{index}({0}:{6})")
+ public static Collection<Object[]> input() {
+ final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+ // mediaType, width, height, bitrate, framerate, level
+ {MediaFormat.MIMETYPE_VIDEO_AVC, 1280, 720, 14000000, 30, "AVCLevel31"},
+ {MediaFormat.MIMETYPE_VIDEO_AVC, 720, 480, 10000000, 30, "AVCLevel3"},
+ {MediaFormat.MIMETYPE_VIDEO_AVC, 720, 480, 4000000, 15, "AVCLevel22"},
+ {MediaFormat.MIMETYPE_VIDEO_AVC, 352, 576, 4000000, 25, "AVCLevel21"},
+ });
+ return prepareParamList(exhaustiveArgsList);
}
/**
@@ -146,9 +198,21 @@
*
* @throws Exception
*/
+ @Test
public void testEncodeVirtualDisplay() throws Throwable {
-
if (!MediaUtils.check(sIsAtLeastR, "test needs Android 11")) return;
+ // Encoded video resolution matches virtual display.
+ mFormat = MediaFormat.createVideoFormat(mMediaType, mWidth, mHeight);
+ mFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+ MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
+ mFormat.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);
+ mFormat.setInteger(MediaFormat.KEY_FRAME_RATE, mFrameRate);
+ mFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
+ mFormat.setInteger(MediaFormat.KEY_COLOR_RANGE, MediaFormat.COLOR_RANGE_LIMITED);
+ mFormat.setInteger(MediaFormat.KEY_COLOR_STANDARD, MediaFormat.COLOR_STANDARD_BT601_PAL);
+ mFormat.setInteger(MediaFormat.KEY_COLOR_TRANSFER, MediaFormat.COLOR_TRANSFER_SDR_VIDEO);
+ assumeTrue(mEncoderName + " doesn't support format " + mFormat,
+ MediaUtils.supports(mEncoderName, mFormat));
EncodeVirtualWrapper.runTest(this);
}
@@ -188,41 +252,6 @@
}
/**
- * Returns true if the encoder level, specified in the ENCODER_PARAM_TABLE, can be supported.
- */
- private static boolean verifySupportForEncoderLevel(int i) {
- MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
- MediaFormat format = MediaFormat.createVideoFormat(
- MIME_TYPE, ENCODER_PARAM_TABLE[i][0], ENCODER_PARAM_TABLE[i][1]);
- format.setInteger(MediaFormat.KEY_BIT_RATE, ENCODER_PARAM_TABLE[i][2]);
- format.setInteger(MediaFormat.KEY_FRAME_RATE, ENCODER_PARAM_TABLE[i][3]);
- return mcl.findEncoderForFormat(format) != null;
- }
-
- /**
- * Initialize the encoder parameters according to the device capability.
- */
- private static void setupEncoderParameters() {
-
- // Loop over each tabel entry until a proper encoder setting is found.
- for (int i = 0; i < ENCODER_PARAM_TABLE.length; i++) {
-
- // Check if we can support it?
- if (verifySupportForEncoderLevel(i)) {
-
- sWidth = ENCODER_PARAM_TABLE[i][0];
- sHeight = ENCODER_PARAM_TABLE[i][1];
- sBitRate = ENCODER_PARAM_TABLE[i][2];
- sFrameRate = ENCODER_PARAM_TABLE[i][3];
-
- Log.d(TAG, "encoder parameters changed: width = " + sWidth + ", height = " + sHeight
- + ", bitrate = " + sBitRate + ", framerate = " + sFrameRate);
- break;
- }
- }
- }
-
- /**
* Prepares the encoder, decoder, and virtual display.
*/
private void encodeVirtualDisplayTest() throws IOException {
@@ -230,52 +259,40 @@
MediaCodec decoder = null;
OutputSurface outputSurface = null;
VirtualDisplay virtualDisplay = null;
+ ColorSlideShow slideShow = null;
try {
- // Encoded video resolution matches virtual display.
- MediaFormat encoderFormat = MediaFormat.createVideoFormat(MIME_TYPE, sWidth, sHeight);
- encoderFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
- MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
- encoderFormat.setInteger(MediaFormat.KEY_BIT_RATE, sBitRate);
- encoderFormat.setInteger(MediaFormat.KEY_FRAME_RATE, sFrameRate);
- encoderFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
- encoderFormat.setInteger(MediaFormat.KEY_COLOR_RANGE, MediaFormat.COLOR_RANGE_LIMITED);
- encoderFormat.setInteger(MediaFormat.KEY_COLOR_STANDARD, MediaFormat.COLOR_STANDARD_BT601_PAL);
- encoderFormat.setInteger(MediaFormat.KEY_COLOR_TRANSFER, MediaFormat.COLOR_TRANSFER_SDR_VIDEO);
-
- MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
- String codec = mcl.findEncoderForFormat(encoderFormat);
- if (codec == null) {
- // Don't run the test if the codec isn't present.
- Log.i(TAG, "SKIPPING test: no support for " + encoderFormat);
- return;
- }
-
- encoder = MediaCodec.createByCodecName(codec);
- encoder.configure(encoderFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ encoder = MediaCodec.createByCodecName(mEncoderName);
+ encoder.configure(mFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
Surface inputSurface = encoder.createInputSurface();
encoder.start();
// Create a virtual display that will output to our encoder.
virtualDisplay = mDisplayManager.createVirtualDisplay(NAME,
- sWidth, sHeight, DENSITY, inputSurface, 0);
+ mWidth, mHeight, DENSITY, inputSurface, 0);
// We also need a decoder to check the output of the encoder.
- decoder = MediaCodec.createDecoderByType(MIME_TYPE);
- MediaFormat decoderFormat = MediaFormat.createVideoFormat(MIME_TYPE, sWidth, sHeight);
- outputSurface = new OutputSurface(sWidth, sHeight);
+ decoder = MediaCodec.createDecoderByType(mMediaType);
+ MediaFormat decoderFormat = MediaFormat.createVideoFormat(mMediaType, mWidth, mHeight);
+ outputSurface = new OutputSurface(mWidth, mHeight);
decoder.configure(decoderFormat, outputSurface.getSurface(), null, 0);
decoder.start();
// Run the color slide show on a separate thread.
mInputDone = false;
- new ColorSlideShow(virtualDisplay.getDisplay()).start();
+ slideShow = new ColorSlideShow(virtualDisplay.getDisplay());
+ slideShow.start();
// Record everything we can and check the results.
doTestEncodeVirtual(encoder, decoder, outputSurface);
} finally {
if (VERBOSE) Log.d(TAG, "releasing codecs, surfaces, and virtual display");
+ if (slideShow != null) {
+ try {
+ slideShow.join();
+ } catch (InterruptedException ignore) {}
+ }
if (virtualDisplay != null) {
virtualDisplay.release();
}
@@ -311,7 +328,7 @@
MediaMuxer muxer = null;
int trackIndex = -1;
if (DEBUG_SAVE_FILE) {
- String fileName = DEBUG_FILE_NAME_BASE + sWidth + "x" + sHeight + ".mp4";
+ String fileName = DEBUG_FILE_NAME_BASE + mWidth + "x" + mHeight + ".mp4";
try {
muxer = new MediaMuxer(fileName, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
Log.d(TAG, "encoded output will be saved as " + fileName);
@@ -497,8 +514,8 @@
// Read a pixel from the center of the surface. Might want to read from multiple points
// and average them together.
- int x = sWidth / 2;
- int y = sHeight / 2;
+ int x = mWidth / 2;
+ int y = mHeight / 2;
GLES20.glReadPixels(x, y, 1, 1, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, mPixelBuf);
int r = mPixelBuf.get(0) & 0xff;
int g = mPixelBuf.get(1) & 0xff;
@@ -556,7 +573,7 @@
runOnUiThread(() -> {
// Want to create presentation on UI thread so it finds the right Looper
// when setting up the Dialog.
- presentation[0] = new TestPresentation(getContext(), mDisplay, color);
+ presentation[0] = new TestPresentation(mContext, mDisplay, color);
if (VERBOSE) Log.d(TAG, "showing color=0x" + Integer.toHexString(color));
presentation[0].show();
latch.countDown();
@@ -619,7 +636,7 @@
setTitle("Encode Virtual Test");
// Create a solid color image to use as the content of the presentation.
- ImageView view = new ImageView(getContext());
+ ImageView view = new ImageView(mContext);
view.setImageDrawable(new ColorDrawable(mColor));
view.setLayoutParams(new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/ExtractDecodeEditEncodeMuxTest.java b/tests/tests/media/codec/src/android/media/codec/cts/ExtractDecodeEditEncodeMuxTest.java
index eec4568..b2fbc6c 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/ExtractDecodeEditEncodeMuxTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/ExtractDecodeEditEncodeMuxTest.java
@@ -524,8 +524,11 @@
int expectedSampleRate = OUTPUT_AUDIO_SAMPLE_RATE_HZ;
// SBR mode halves the sample rate in the format.
- if (OUTPUT_AUDIO_AAC_PROFILE ==
- MediaCodecInfo.CodecProfileLevel.AACObjectHE) {
+ // Query output profile. KEY_PROFILE gets precedence over KEY_AAC_PROFILE
+ int aac_profile = trackFormat.getInteger(MediaFormat.KEY_AAC_PROFILE, -1);
+ int profile = trackFormat.getInteger(MediaFormat.KEY_PROFILE, aac_profile);
+
+ if (profile == MediaCodecInfo.CodecProfileLevel.AACObjectHE) {
expectedSampleRate /= 2;
}
assertEquals("sample rates should match", expectedSampleRate,
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTestBase.java b/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTestBase.java
index cbe3966..b4d4b31 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTestBase.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTestBase.java
@@ -16,7 +16,6 @@
package android.media.codec.cts;
-import android.content.res.Resources;
import android.media.MediaCodec;
import android.media.MediaCodec.CodecException;
import android.media.MediaCodecInfo;
@@ -34,10 +33,11 @@
import android.platform.test.annotations.AppModeFull;
import android.util.Log;
-import androidx.test.platform.app.InstrumentationRegistry;
-
import com.android.compatibility.common.util.MediaUtils;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -48,9 +48,6 @@
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
-
/**
* Verification test for video encoder and decoder.
*
@@ -269,10 +266,11 @@
public ArrayList<MediaCodec.BufferInfo> bufferInfo;
public EncodingStatisticsInfo encStat;
- VideoEncodeOutput(ArrayList<MediaCodec.BufferInfo> bufferInfo,
- EncodingStatisticsInfo encStat) {
- bufferInfo = bufferInfo;
- encStat = encStat;
+ VideoEncodeOutput(
+ ArrayList<MediaCodec.BufferInfo> bufferInfo,
+ EncodingStatisticsInfo encStat) {
+ this.bufferInfo = bufferInfo;
+ this.encStat = encStat;
}
}
@@ -346,6 +344,7 @@
params.runInLooperThread = true;
}
outputParameters.add(params);
+ params.encodingStatisticsLevel = MediaFormat.VIDEO_ENCODING_STATISTICS_LEVEL_NONE;
}
return outputParameters;
}
@@ -1042,10 +1041,6 @@
out.inPresentationTimeUs = mInPresentationTimeUs;
out.outPresentationTimeUs = mOutPresentationTimeUs;
}
- mCodec.releaseOutputBuffer(index, false);
-
- out.flags = info.flags;
- out.outputGenerated = true;
MediaFormat format = codec.getOutputFormat(index);
if (format.containsKey(MediaFormat.KEY_VIDEO_QP_AVERAGE)) {
@@ -1054,6 +1049,11 @@
mHelper.saveAvgQp(avgQp);
}
+ mCodec.releaseOutputBuffer(index, false);
+
+ out.flags = info.flags;
+ out.outputGenerated = true;
+
if (mHelper.saveOutputFrame(out)) {
// output EOS
signalCompletion();
@@ -1092,6 +1092,17 @@
@Override
public void run() {
Looper.prepare();
+ setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+ @Override
+ public void uncaughtException(Thread t, Throwable e) {
+ Log.e(TAG, "thread " + t + " exception " + e);
+ try {
+ deleteCodec();
+ } catch (Exception ex) {
+ Log.e(TAG, "exception from deleteCodec " + e);
+ }
+ }
+ });
synchronized (mThreadEvent) {
mHandler = new Handler();
mThreadEvent.notify();
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/VideoEncodingStatisticsTest.java b/tests/tests/media/codec/src/android/media/codec/cts/VideoEncodingStatisticsTest.java
index 10a18dd..ff38e6c 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/VideoEncodingStatisticsTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/VideoEncodingStatisticsTest.java
@@ -193,7 +193,7 @@
}
double differenceBitrate = TEST_BITRATES_SET[i] - TEST_BITRATES_SET[j];
double differenceAvgQp = avgSeqQp[i] - avgSeqQp[j];
- if (differenceBitrate * differenceAvgQp > 0) {
+ if (differenceBitrate * differenceAvgQp >= 0) {
throw new RuntimeException("Target bitrates: " +
TEST_BITRATES_SET[j] + ", " + TEST_BITRATES_SET[i] +
". Average QP: "
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java
index 4c729ea..0f3281c 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java
@@ -32,14 +32,20 @@
import android.util.Log;
import android.view.View;
+import androidx.test.platform.app.InstrumentationRegistry;
+
import com.android.compatibility.common.util.MediaUtils;
import java.io.File;
+import java.io.IOException;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -63,6 +69,7 @@
private static final int ALLOWED_GREATEST_PIXEL_DIFFERENCE = 90;
private static final int OFFSET = 10;
private static final long PER_TEST_TIMEOUT_MS = 60000;
+ private static final String CODEC_PREFIX_KEY = "codec-prefix";
private static final String[] VIDEO_FILES = {
// 144p
"video_decode_accuracy_and_capability-h264_256x108_30fps.mp4",
@@ -141,13 +148,29 @@
"video_decode_with_cropping-vp9_520x360_30fps.webm"
};
+ private static final String INP_PREFIX = WorkDir.getMediaDirString() +
+ "assets/decode_accuracy/";
+ private static String mCodecPrefix;
+
private View videoView;
private VideoViewFactory videoViewFactory;
- private String fileName;
private String testName;
+ private String fileName;
+ private String decoderName;
private String methodName;
private SimplePlayer player;
+ static {
+ android.os.Bundle args = InstrumentationRegistry.getArguments();
+ mCodecPrefix = args.getString(CODEC_PREFIX_KEY);
+ }
+
+ public DecodeAccuracyTest(String decoderName, String fileName, String testName) {
+ this.testName = testName;
+ this.fileName = fileName;
+ this.decoderName = decoderName;
+ }
+
@After
@Override
public void tearDown() throws Exception {
@@ -163,64 +186,76 @@
super.tearDown();
}
- @Parameters
- public static Collection<Object[]> data() {
+ @Parameters(name = "{index}({0}_{2})")
+ public static Collection<Object[]> input() throws IOException {
final List<Object[]> testParams = new ArrayList<>();
- for (int i = 0; i < VIDEO_FILES.length; i++) {
- final String file = VIDEO_FILES[i];
+ for (String file : VIDEO_FILES) {
Pattern regex = Pattern.compile("^\\w+-(\\w+)_\\d+fps\\.\\w+");
Matcher matcher = regex.matcher(file);
String testName = "";
if (matcher.matches()) {
testName = matcher.group(1);
}
- testParams.add(new Object[] { testName, file });
+ MediaFormat mediaFormat =
+ MediaUtils.getTrackFormatForResource(INP_PREFIX + file, "video");
+ String mediaType = mediaFormat.getString(MediaFormat.KEY_MIME);
+ String[] componentNames = MediaUtils.getDecoderNamesForMime(mediaType);
+ for (String componentName : componentNames) {
+ if (mCodecPrefix != null && !componentName.startsWith(mCodecPrefix)) {
+ continue;
+ }
+ if (MediaUtils.supports(componentName, mediaFormat)) {
+ testParams.add(new Object[] {componentName, file, testName});
+ // Test only the first decoder that supports given format.
+ // Remove the following break statement to test all decoders on the device.
+ break;
+ }
+ }
}
return testParams;
}
- public DecodeAccuracyTest(String testName, String fileName) {
- this.fileName = fileName;
- this.testName = testName;
- }
-
@Test(timeout = PER_TEST_TIMEOUT_MS)
public void testGLViewDecodeAccuracy() throws Exception {
this.methodName = "testGLViewDecodeAccuracy";
- runTest(new GLSurfaceViewFactory(), new VideoFormat(fileName));
+ runTest(new GLSurfaceViewFactory(), new VideoFormat(fileName), decoderName);
}
@Test(timeout = PER_TEST_TIMEOUT_MS)
public void testGLViewLargerHeightDecodeAccuracy() throws Exception {
this.methodName = "testGLViewLargerHeightDecodeAccuracy";
- runTest(new GLSurfaceViewFactory(), getLargerHeightVideoFormat(new VideoFormat(fileName)));
+ runTest(new GLSurfaceViewFactory(), getLargerHeightVideoFormat(new VideoFormat(fileName)),
+ decoderName);
}
@Test(timeout = PER_TEST_TIMEOUT_MS)
public void testGLViewLargerWidthDecodeAccuracy() throws Exception {
this.methodName = "testGLViewLargerWidthDecodeAccuracy";
- runTest(new GLSurfaceViewFactory(), getLargerWidthVideoFormat(new VideoFormat(fileName)));
+ runTest(new GLSurfaceViewFactory(), getLargerWidthVideoFormat(new VideoFormat(fileName)),
+ decoderName);
}
@Test(timeout = PER_TEST_TIMEOUT_MS)
public void testSurfaceViewVideoDecodeAccuracy() throws Exception {
this.methodName = "testSurfaceViewVideoDecodeAccuracy";
- runTest(new SurfaceViewFactory(), new VideoFormat(fileName));
+ runTest(new SurfaceViewFactory(), new VideoFormat(fileName), decoderName);
}
@Test(timeout = PER_TEST_TIMEOUT_MS)
public void testSurfaceViewLargerHeightDecodeAccuracy() throws Exception {
this.methodName = "testSurfaceViewLargerHeightDecodeAccuracy";
- runTest(new SurfaceViewFactory(), getLargerHeightVideoFormat(new VideoFormat(fileName)));
+ runTest(new SurfaceViewFactory(), getLargerHeightVideoFormat(new VideoFormat(fileName)),
+ decoderName);
}
@Test(timeout = PER_TEST_TIMEOUT_MS)
public void testSurfaceViewLargerWidthDecodeAccuracy() throws Exception {
this.methodName = "testSurfaceViewLargerWidthDecodeAccuracy";
- runTest(new SurfaceViewFactory(), getLargerWidthVideoFormat(new VideoFormat(fileName)));
+ runTest(new SurfaceViewFactory(), getLargerWidthVideoFormat(new VideoFormat(fileName)),
+ decoderName);
}
- private void runTest(VideoViewFactory videoViewFactory, VideoFormat vf) {
+ private void runTest(VideoViewFactory videoViewFactory, VideoFormat vf, String decoderName) {
Log.i(TAG, "Running test for " + vf.toPrettyString());
if (!MediaUtils.canDecodeVideo(vf.getMimeType(), vf.getWidth(), vf.getHeight(), 30)) {
MediaUtils.skipTest(TAG, "No supported codec is found.");
@@ -249,12 +284,13 @@
}
final int golden = getGoldenId(vf.getDescription(), vf.getOriginalSize());
assertTrue("No golden found.", golden != 0);
- decodeVideo(vf, videoViewFactory);
+ decodeVideo(vf, videoViewFactory, decoderName);
validateResult(vf, videoViewFactory.getVideoViewSnapshot(), golden);
}
- private void decodeVideo(VideoFormat videoFormat, VideoViewFactory videoViewFactory) {
- this.player = new SimplePlayer(getHelper().getContext());
+ private void decodeVideo(VideoFormat videoFormat, VideoViewFactory videoViewFactory,
+ String decoderName) {
+ this.player = new SimplePlayer(getHelper().getContext(), decoderName);
final SimplePlayer.PlayerResult playerResult = player.decodeVideoFrames(
videoViewFactory.getSurface(), videoFormat, 10);
assertTrue(playerResult.getFailureMessage(), playerResult.isSuccess());
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderConformanceTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderConformanceTest.java
index 893c437c..0c79713 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderConformanceTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderConformanceTest.java
@@ -16,8 +16,6 @@
package android.media.decoder.cts;
-import static org.junit.Assert.fail;
-
import android.content.res.AssetFileDescriptor;
import android.media.decoder.cts.R;
import android.media.MediaCodec;
@@ -31,6 +29,7 @@
import android.util.Log;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.DeviceReportLog;
import com.android.compatibility.common.util.MediaUtils;
@@ -39,8 +38,9 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.runner.RunWith;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
import java.io.BufferedReader;
import java.io.File;
@@ -49,9 +49,13 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.HashMap;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
/**
* Conformance test for decoders on the device.
@@ -62,7 +66,7 @@
* based on the YUV 420 plannar format.
*/
@AppModeFull(reason = "There should be no instant apps specific behavior related to conformance")
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
public class DecoderConformanceTest extends MediaTestBase {
private enum Status {
FAIL,
@@ -73,14 +77,51 @@
private static final String REPORT_LOG_NAME = "CtsMediaDecoderTestCases";
private static final String TAG = "DecoderConformanceTest";
private static final String CONFORMANCE_SUBDIR = "conformance_vectors/";
- private DeviceReportLog mReportLog;
- private MediaCodec mDecoder;
- private MediaExtractor mExtractor;
- static final String mInpPrefix = WorkDir.getMediaDirString() + CONFORMANCE_SUBDIR;
-
- private static final Map<String, String> MIMETYPE_TO_TAG = new HashMap <String, String>() {{
+ private static final String CODEC_PREFIX_KEY = "codec-prefix";
+ private static final String mInpPrefix = WorkDir.getMediaDirString() + CONFORMANCE_SUBDIR;
+ private static final Map<String, String> MIMETYPE_TO_TAG = new HashMap<String, String>() {{
put(MediaFormat.MIMETYPE_VIDEO_VP9, "vp9");
}};
+ private static String mCodecPrefix;
+
+ private final String mDecoderName;
+ private final String mMediaType;
+ private final String mTestVector;
+
+ private MediaCodec mDecoder;
+ private MediaExtractor mExtractor;
+
+ private DeviceReportLog mReportLog;
+
+ static {
+ android.os.Bundle args = InstrumentationRegistry.getArguments();
+ mCodecPrefix = args.getString(CODEC_PREFIX_KEY);
+ }
+
+ @Parameterized.Parameters(name = "{index}({0})")
+ public static Collection<Object[]> input() throws Exception {
+ final String[] mediaTypeList = new String[] {MediaFormat.MIMETYPE_VIDEO_VP9};
+ final List<Object[]> argsList = new ArrayList<>();
+ for (String mediaType : mediaTypeList) {
+ String[] componentNames = MediaUtils.getDecoderNamesForMime(mediaType);
+ List<String> testVectors = readCodecTestVectors(mediaType);
+ for (String testVector : testVectors) {
+ for (String name : componentNames) {
+ if (mCodecPrefix != null && !name.startsWith(mCodecPrefix)) {
+ continue;
+ }
+ argsList.add(new Object[] {name, mediaType, testVector});
+ }
+ }
+ }
+ return argsList;
+ }
+
+ public DecoderConformanceTest(String decodername, String mediaType, String testvector) {
+ mDecoderName = decodername;
+ mMediaType = mediaType;
+ mTestVector = testvector;
+ }
@Before
@Override
@@ -94,24 +135,7 @@
super.tearDown();
}
- /**
- * Test VP9 decoders from vendor.
- */
- @Test
- public void testVP9Other() throws Exception {
- decodeTestVectors(MediaFormat.MIMETYPE_VIDEO_VP9, false /* isGoog */);
- }
-
- /**
- * Test Google's VP9 decoder from libvpx.
- */
- @Test
- public void testVP9Goog() throws Exception {
- decodeTestVectors(MediaFormat.MIMETYPE_VIDEO_VP9, true /* isGoog */);
- }
-
- private List<String> readResourceLines(String fileName) throws Exception {
- Preconditions.assertTestFileExists(mInpPrefix + fileName);
+ private static List<String> readResourceLines(String fileName) throws Exception {
InputStream is = new FileInputStream(mInpPrefix + fileName);
BufferedReader in = new BufferedReader(new InputStreamReader(is, "UTF-8"));
@@ -128,7 +152,7 @@
return lines;
}
- private List<String> readCodecTestVectors(String mime) throws Exception {
+ private static List<String> readCodecTestVectors(String mime) throws Exception {
String tag = MIMETYPE_TO_TAG.get(mime);
String testVectorFileName = tag + "_test_vectors";
return readResourceLines(testVectorFileName);
@@ -202,44 +226,26 @@
}
}
- void decodeTestVectors(String mime, boolean isGoog) throws Exception {
- MediaFormat format = new MediaFormat();
- format.setString(MediaFormat.KEY_MIME, mime);
- String[] decoderNames = MediaUtils.getDecoderNames(isGoog, format);
- for (String decoderName: decoderNames) {
- List<String> testVectors = readCodecTestVectors(mime);
- for (String vectorName: testVectors) {
- boolean pass = false;
- Log.d(TAG, "Decode vector " + vectorName + " with " + decoderName);
- try {
- Status stat = decodeTestVector(mime, decoderName, vectorName);
- if (stat == Status.PASS) {
- pass = true;
- } else if (stat == Status.SKIP) {
- release();
- continue;
- }
- } catch (Exception e) {
- Log.e(TAG, "Decode " + vectorName + " fail");
- fail("Received exception " + e);
- }
-
- String streamName = "decoder_conformance_test";
- mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
- mReportLog.addValue("mime", mime, ResultType.NEUTRAL, ResultUnit.NONE);
- mReportLog.addValue("is_goog", isGoog, ResultType.NEUTRAL, ResultUnit.NONE);
- mReportLog.addValue("pass", pass, ResultType.NEUTRAL, ResultUnit.NONE);
- mReportLog.addValue("vector_name", vectorName, ResultType.NEUTRAL, ResultUnit.NONE);
- mReportLog.addValue("decode_name", decoderName, ResultType.NEUTRAL,
- ResultUnit.NONE);
- mReportLog.submit(getInstrumentation());
-
- if (!pass) {
- // Release mediacodec in failure or exception cases.
- release();
- }
- }
-
+ @Test
+ public void testDecoderConformance() {
+ Log.d(TAG, "Decode vector " + mTestVector + " with " + mDecoderName);
+ Status stat = Status.PASS;
+ try {
+ stat = decodeTestVector(mMediaType, mDecoderName, mTestVector);
+ } catch (Exception e) {
+ Log.e(TAG, "Decode " + mTestVector + " fail");
+ fail("Received exception " + e);
+ } finally {
+ release();
}
+ String streamName = "decoder_conformance_test";
+ mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
+ mReportLog.addValue("mime", mMediaType, ResultType.NEUTRAL, ResultUnit.NONE);
+ mReportLog.addValue("pass", stat != Status.FAIL, ResultType.NEUTRAL, ResultUnit.NONE);
+ mReportLog.addValue("vector_name", mTestVector, ResultType.NEUTRAL, ResultUnit.NONE);
+ mReportLog.addValue("decode_name", mDecoderName, ResultType.NEUTRAL, ResultUnit.NONE);
+ mReportLog.submit(InstrumentationRegistry.getInstrumentation());
+ assumeTrue(mDecoderName + " failed for " + mTestVector, stat != Status.FAIL);
+ assumeTrue(mDecoderName + " skipped for " + mTestVector, stat != Status.SKIP);
}
}
diff --git a/tests/tests/media/drmframework/AndroidTest.xml b/tests/tests/media/drmframework/AndroidTest.xml
index 01639e5..c6e311d 100644
--- a/tests/tests/media/drmframework/AndroidTest.xml
+++ b/tests/tests/media/drmframework/AndroidTest.xml
@@ -35,10 +35,6 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsMediaDrmFrameworkTestCases.apk" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <!-- MediaProjectionTest needs this one to not be granted, SuiteApkInstaller grants all of them by default.-->
- <option name="run-command" value="pm revoke android.media.drmframework.cts android.permission.SYSTEM_ALERT_WINDOW"/>
- </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
<option name="target" value="device" />
<option name="config-filename" value="CtsMediaDrmFrameworkTestCases" />
diff --git a/tests/tests/media/drmframework/jni/native-mediadrm-jni.cpp b/tests/tests/media/drmframework/jni/native-mediadrm-jni.cpp
index 40584b6..630c7f6 100644
--- a/tests/tests/media/drmframework/jni/native-mediadrm-jni.cpp
+++ b/tests/tests/media/drmframework/jni/native-mediadrm-jni.cpp
@@ -27,7 +27,6 @@
#include <jni.h>
#include <nativehelper/JNIHelp.h>
#include <sys/stat.h>
-
#include <android/native_window_jni.h>
#include "AMediaObjects.h"
@@ -1041,6 +1040,17 @@
return JNI_FALSE;
}
+ // Check service availability
+ const char *outValue = NULL;
+ status = AMediaDrm_getPropertyString(aMediaObjects.getDrm(),
+ "aidlVersion", &outValue);
+ if (status != AMEDIA_OK) {
+ // Drm service not using aidl interface, skip checking default url value
+ return JNI_TRUE;
+ }
+
+ ALOGD("aidlVersion is [%s]", outValue);
+
ALOGD("kDefaultUrl [%s], length %d, defaultUrl [%s], length %d",
kDefaultUrl,
(int)strlen(kDefaultUrl),
diff --git a/tests/tests/media/extractor/AndroidTest.xml b/tests/tests/media/extractor/AndroidTest.xml
index 09c79fc..007a65b 100644
--- a/tests/tests/media/extractor/AndroidTest.xml
+++ b/tests/tests/media/extractor/AndroidTest.xml
@@ -47,10 +47,6 @@
<option name="config-filename" value="CtsMediaExtractorTestCases" />
<option name="version" value="1.0"/>
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <!-- MediaProjectionTest needs this one to not be granted, SuiteApkInstaller grants all of them by default.-->
- <option name="run-command" value="pm revoke android.media.extractor.cts android.permission.SYSTEM_ALERT_WINDOW"/>
- </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.media.extractor.cts" />
<!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/misc/res/raw/a_4.ogg b/tests/tests/media/misc/res/raw/a_4.ogg
deleted file mode 100644
index 155e790..0000000
--- a/tests/tests/media/misc/res/raw/a_4.ogg
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/a_4_aac.mp4 b/tests/tests/media/misc/res/raw/a_4_aac.mp4
deleted file mode 100644
index 05a776f..0000000
--- a/tests/tests/media/misc/res/raw/a_4_aac.mp4
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/a_4_haptic.ogg b/tests/tests/media/misc/res/raw/a_4_haptic.ogg
deleted file mode 100644
index 3c94c8d..0000000
--- a/tests/tests/media/misc/res/raw/a_4_haptic.ogg
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/b_5.ogg b/tests/tests/media/misc/res/raw/b_5.ogg
deleted file mode 100644
index c64e508..0000000
--- a/tests/tests/media/misc/res/raw/b_5.ogg
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/b_5_aac.mp4 b/tests/tests/media/misc/res/raw/b_5_aac.mp4
deleted file mode 100644
index 9bce44d..0000000
--- a/tests/tests/media/misc/res/raw/b_5_aac.mp4
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/b_5_haptic.ogg b/tests/tests/media/misc/res/raw/b_5_haptic.ogg
deleted file mode 100644
index 90ab939..0000000
--- a/tests/tests/media/misc/res/raw/b_5_haptic.ogg
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/c_sharp_5.ogg b/tests/tests/media/misc/res/raw/c_sharp_5.ogg
deleted file mode 100644
index 18900f9..0000000
--- a/tests/tests/media/misc/res/raw/c_sharp_5.ogg
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/c_sharp_5_aac.mp4 b/tests/tests/media/misc/res/raw/c_sharp_5_aac.mp4
deleted file mode 100644
index 1e7f988..0000000
--- a/tests/tests/media/misc/res/raw/c_sharp_5_aac.mp4
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/c_sharp_5_haptic.ogg b/tests/tests/media/misc/res/raw/c_sharp_5_haptic.ogg
deleted file mode 100644
index 57c46ea..0000000
--- a/tests/tests/media/misc/res/raw/c_sharp_5_haptic.ogg
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/e_5.ogg b/tests/tests/media/misc/res/raw/e_5.ogg
deleted file mode 100644
index 2597e75..0000000
--- a/tests/tests/media/misc/res/raw/e_5.ogg
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/e_5_aac.mp4 b/tests/tests/media/misc/res/raw/e_5_aac.mp4
deleted file mode 100644
index 95bad2a..0000000
--- a/tests/tests/media/misc/res/raw/e_5_aac.mp4
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/e_5_haptic.ogg b/tests/tests/media/misc/res/raw/e_5_haptic.ogg
deleted file mode 100644
index 98289dc..0000000
--- a/tests/tests/media/misc/res/raw/e_5_haptic.ogg
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/g_sharp_5.ogg b/tests/tests/media/misc/res/raw/g_sharp_5.ogg
deleted file mode 100644
index 02e8112..0000000
--- a/tests/tests/media/misc/res/raw/g_sharp_5.ogg
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/g_sharp_5_aac.mp4 b/tests/tests/media/misc/res/raw/g_sharp_5_aac.mp4
deleted file mode 100644
index a357912..0000000
--- a/tests/tests/media/misc/res/raw/g_sharp_5_aac.mp4
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/g_sharp_5_haptic.ogg b/tests/tests/media/misc/res/raw/g_sharp_5_haptic.ogg
deleted file mode 100644
index 6fb7388..0000000
--- a/tests/tests/media/misc/res/raw/g_sharp_5_haptic.ogg
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/midi_a.mid b/tests/tests/media/misc/res/raw/midi_a.mid
deleted file mode 100644
index 941885f..0000000
--- a/tests/tests/media/misc/res/raw/midi_a.mid
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/midi_b.mid b/tests/tests/media/misc/res/raw/midi_b.mid
deleted file mode 100644
index 424c960..0000000
--- a/tests/tests/media/misc/res/raw/midi_b.mid
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/midi_cs.mid b/tests/tests/media/misc/res/raw/midi_cs.mid
deleted file mode 100644
index ee9cb23..0000000
--- a/tests/tests/media/misc/res/raw/midi_cs.mid
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/midi_e.mid b/tests/tests/media/misc/res/raw/midi_e.mid
deleted file mode 100644
index dac820d..0000000
--- a/tests/tests/media/misc/res/raw/midi_e.mid
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/midi_gs.mid b/tests/tests/media/misc/res/raw/midi_gs.mid
deleted file mode 100644
index 1d43841..0000000
--- a/tests/tests/media/misc/res/raw/midi_gs.mid
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/sine1khzm40db.wav b/tests/tests/media/misc/res/raw/sine1khzm40db.wav
deleted file mode 100644
index b653a77..0000000
--- a/tests/tests/media/misc/res/raw/sine1khzm40db.wav
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/sine1khzs40dblong.mp3 b/tests/tests/media/misc/res/raw/sine1khzs40dblong.mp3
deleted file mode 100644
index 29bc683..0000000
--- a/tests/tests/media/misc/res/raw/sine1khzs40dblong.mp3
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/test1m1s.mp3 b/tests/tests/media/misc/res/raw/test1m1s.mp3
deleted file mode 100644
index d54a9df..0000000
--- a/tests/tests/media/misc/res/raw/test1m1s.mp3
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/testopus.opus b/tests/tests/media/misc/res/raw/testopus.opus
deleted file mode 100644
index f2d598a..0000000
--- a/tests/tests/media/misc/res/raw/testopus.opus
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/res/raw/testwav_16bit_44100hz.wav b/tests/tests/media/misc/res/raw/testwav_16bit_44100hz.wav
deleted file mode 100644
index f57ee85..0000000
--- a/tests/tests/media/misc/res/raw/testwav_16bit_44100hz.wav
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/misc/src/android/media/misc/cts/MediaRouter2Test.java b/tests/tests/media/misc/src/android/media/misc/cts/MediaRouter2Test.java
index f1e140f..d38f767 100644
--- a/tests/tests/media/misc/src/android/media/misc/cts/MediaRouter2Test.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/MediaRouter2Test.java
@@ -198,7 +198,7 @@
public void testAllowedPackages() throws Exception {
RouteDiscoveryPreference preference =
new RouteDiscoveryPreference.Builder(FEATURES_ALL, true)
- .setAllowedPackages(List.of("android.media.cts"))
+ .setAllowedPackages(List.of("android.media.misc.cts"))
.build();
Map<String, MediaRoute2Info> routes = waitAndGetRoutes(preference);
diff --git a/tests/tests/media/muxer/AndroidTest.xml b/tests/tests/media/muxer/AndroidTest.xml
index aa4110b..502f2ca 100644
--- a/tests/tests/media/muxer/AndroidTest.xml
+++ b/tests/tests/media/muxer/AndroidTest.xml
@@ -47,10 +47,6 @@
<option name="config-filename" value="CtsMediaMuxerTestCases" />
<option name="version" value="1.0"/>
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <!-- MediaProjectionTest needs this one to not be granted, SuiteApkInstaller grants all of them by default.-->
- <option name="run-command" value="pm revoke android.media.muxer.cts android.permission.SYSTEM_ALERT_WINDOW"/>
- </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.media.muxer.cts" />
<!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/player/AndroidTest.xml b/tests/tests/media/player/AndroidTest.xml
index 7b92b12..e3e8b02 100644
--- a/tests/tests/media/player/AndroidTest.xml
+++ b/tests/tests/media/player/AndroidTest.xml
@@ -47,10 +47,6 @@
<option name="config-filename" value="CtsMediaPlayerTestCases" />
<option name="version" value="1.0"/>
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <!-- MediaProjectionTest needs this one to not be granted, SuiteApkInstaller grants all of them by default.-->
- <option name="run-command" value="pm revoke android.media.player.cts android.permission.SYSTEM_ALERT_WINDOW"/>
- </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.media.player.cts" />
<!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/multiuser/src/android/multiuser/cts/UserManagerTest.java b/tests/tests/multiuser/src/android/multiuser/cts/UserManagerTest.java
index 8aa4e7f..1b3e627 100644
--- a/tests/tests/multiuser/src/android/multiuser/cts/UserManagerTest.java
+++ b/tests/tests/multiuser/src/android/multiuser/cts/UserManagerTest.java
@@ -139,7 +139,7 @@
userHandle);
final UserManager cloneUserManager = userContext.getSystemService(UserManager.class);
assertThat(cloneUserManager.isMediaSharedWithParent()).isTrue();
- assertThat(cloneUserManager.isCredentialSharedWithParent()).isTrue();
+ assertThat(cloneUserManager.isCredentialSharableWithParent()).isTrue();
assertThat(cloneUserManager.isCloneProfile()).isTrue();
final List<UserInfo> list = mUserManager.getUsers(true, true, true);
diff --git a/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
index 4fb4917..e4ba869 100644
--- a/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
+++ b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
@@ -184,27 +184,25 @@
public void testSuspendPackage() throws Exception {
toggleListenerAccess(TestNotificationListener.getId(),
InstrumentationRegistry.getInstrumentation(), true);
- Thread.sleep(500); // wait for listener to be allowed
+ Thread.sleep(1000); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
Assert.assertNotNull(mListener);
sendNotification(1, R.drawable.icon_black);
- Thread.sleep(500); // wait for notification listener to receive notification
- assertEquals(1, mListener.mPosted.size());
+ assertTrue(pollForPostedNotifications(1));
mListener.resetData();
// suspend package, listener receives onRemoved
suspendPackage(mContext.getPackageName(), InstrumentationRegistry.getInstrumentation(),
true);
- Thread.sleep(500); // wait for notification listener to get response
- assertEquals(1, mListener.mRemoved.size());
+ Thread.sleep(1000); // wait for notification listener to get response
+ assertTrue(pollForRemovedNotifications(1));
// unsuspend package, listener receives onPosted
suspendPackage(mContext.getPackageName(), InstrumentationRegistry.getInstrumentation(),
false);
- Thread.sleep(500); // wait for notification listener to get response
- assertEquals(1, mListener.mPosted.size());
+ assertTrue(pollForPostedNotifications(1));
toggleListenerAccess(TestNotificationListener.getId(),
InstrumentationRegistry.getInstrumentation(), false);
@@ -227,14 +225,13 @@
Thread.sleep(500); // wait for notification listener to get response
sendNotification(1, R.drawable.icon_black);
- Thread.sleep(500); // wait for notification listener in case it receives notification
+ Thread.sleep(1000); // wait for notification listener in case it receives notification
assertEquals(0, mListener.mPosted.size()); // shouldn't see any notifications posted
// unsuspend package, listener should receive onPosted
suspendPackage(mContext.getPackageName(), InstrumentationRegistry.getInstrumentation(),
false);
- Thread.sleep(500); // wait for notification listener to get response
- assertEquals(1, mListener.mPosted.size());
+ assertTrue(pollForPostedNotifications(1));
toggleListenerAccess(TestNotificationListener.getId(),
InstrumentationRegistry.getInstrumentation(), false);
@@ -324,13 +321,13 @@
assertEquals(Build.VERSION_CODES.O_MR1, mContext.getApplicationInfo().targetSdkVersion);
toggleListenerAccess(TestNotificationListener.getId(),
InstrumentationRegistry.getInstrumentation(), true);
- Thread.sleep(500); // wait for listener to be allowed
+ Thread.sleep(1000); // wait for listener to be allowed
mListener = TestNotificationListener.getInstance();
sendNotification(566, R.drawable.icon_black);
- Thread.sleep(500); // wait for notification listener to receive notification
- assertEquals(1, mListener.mPosted.size());
+ // wait for notification listener to receive notification
+ assertTrue(pollForPostedNotifications(1));
String key = mListener.mPosted.get(0).getKey();
mNotificationManager.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
@@ -363,6 +360,36 @@
mNotificationManager.notify(id, notification);
}
+ // Wait for the listener to have received the specified number of posted notifications.
+ private boolean pollForPostedNotifications(int expected) {
+ for (int tries = 5; tries-- > 0; ) {
+ if (mListener.mPosted.size() >= expected) {
+ return true;
+ }
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ex) {
+ // pass
+ }
+ }
+ return false;
+ }
+
+ // Wait for the listener to have received the specified number of removed notifications.
+ private boolean pollForRemovedNotifications(int expected) {
+ for (int tries = 5; tries-- > 0; ) {
+ if (mListener.mRemoved.size() >= expected) {
+ return true;
+ }
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ex) {
+ // pass
+ }
+ }
+ return false;
+ }
+
private int getCancellationReason(String key) {
for (int tries = 3; tries-- > 0; ) {
if (mListener.mRemoved.containsKey(key)) {
diff --git a/tests/tests/os/UffdGc/jni/android_os_cts_uffdgc_UserfaultfdTest.cc b/tests/tests/os/UffdGc/jni/android_os_cts_uffdgc_UserfaultfdTest.cc
index a35ff16..8c17a72f 100644
--- a/tests/tests/os/UffdGc/jni/android_os_cts_uffdgc_UserfaultfdTest.cc
+++ b/tests/tests/os/UffdGc/jni/android_os_cts_uffdgc_UserfaultfdTest.cc
@@ -23,13 +23,17 @@
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
+#include <string.h>
#include <syscall.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/utsname.h>
+#include <sys/xattr.h>
#include <unistd.h>
+#define SELINUX_CTXT_LEN 255
+
static void* userfault_handler_thread(void* arg) {
struct uffd_msg msg;
struct uffdio_copy uffdio_copy;
@@ -95,6 +99,17 @@
pthread_exit(reinterpret_cast<void*>(ret));
}
+int64_t uffd_api_ioctl(int fd, uint64_t features) {
+ struct uffdio_api api;
+ std::memset(&api, '\0', sizeof api);
+ api.api = UFFD_API;
+ api.features = features;
+ if (ioctl(fd, UFFDIO_API, &api) < 0) {
+ return -1;
+ }
+ return api.features;
+}
+
extern "C"
JNIEXPORT bool JNICALL Java_android_os_cts_uffdgc_UserfaultfdTest_confirmKernelVersion(JNIEnv*) {
#if defined(__linux__)
@@ -150,10 +165,7 @@
goto out_close_both;
}
- struct uffdio_api api;
- std::memset(&api, '\0', sizeof api);
- api.api = UFFD_API;
- if (ioctl(uffd, UFFDIO_API, &api) < 0) {
+ if (uffd_api_ioctl(uffd, /*features*/ 0) == -1) {
ret = errno;
goto out_unmap;
}
@@ -227,25 +239,51 @@
extern "C"
JNIEXPORT jint JNICALL Java_android_os_cts_uffdgc_UserfaultfdTest_performMinorUffd(JNIEnv*) {
- uint64_t req_features;
+ uint64_t req_features = UFFD_FEATURE_MINOR_SHMEM;
+ int64_t available_features = 0;
int ret = 0;
int uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY);
if (uffd < 0) {
ret = errno;
goto out;
}
- struct uffdio_api api;
- std::memset(&api, '\0', sizeof api);
- api.api = UFFD_API;
- req_features = UFFD_FEATURE_MINOR_SHMEM;
- api.features = req_features;
- if (ioctl(uffd, UFFDIO_API, &api) < 0) {
+ available_features = uffd_api_ioctl(uffd, req_features);
+ if (available_features == -1) {
ret = errno;
+ } else if ((available_features & req_features) != req_features) {
+ // Minor feature is not supported by this kernel.
+ ret = EINVAL;
}
- // Minor feature is not supported by this kernel.
- if ((api.features & req_features) != req_features) {
- ret = -EINVAL;
+ close(uffd);
+out:
+ return ret;
+}
+
+extern "C"
+JNIEXPORT jint JNICALL Java_android_os_cts_uffdgc_UserfaultfdTest_checkGetattr(JNIEnv*) {
+ ssize_t attr_ret = 0;
+ char selinux_ctxt[SELINUX_CTXT_LEN + 1];
+ int ret = 0;
+ int uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY);
+ if (uffd < 0) {
+ ret = errno;
+ goto out;
}
+ if (uffd_api_ioctl(uffd, /*features*/ 0) == -1) {
+ ret = errno;
+ goto out_close;
+ }
+ attr_ret = fgetxattr(uffd, XATTR_NAME_SELINUX, selinux_ctxt, SELINUX_CTXT_LEN);
+ if (attr_ret == -1) {
+ ret = errno;
+ goto out_close;
+ }
+ // We should never reach here as the call to fgetxattr must return EACCES.
+ selinux_ctxt[attr_ret] = 0;
+ if (strstr(selinux_ctxt, "userfaultfd") == nullptr) {
+ ret = -1;
+ }
+out_close:
close(uffd);
out:
return ret;
diff --git a/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java b/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java
index 5ebe92c..fc4df13 100644
--- a/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java
+++ b/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java
@@ -74,9 +74,18 @@
assertEquals(0, performMinorUffd());
}
+ // Confirms if userfaultfd is controlled by selinux or not.
+ // We don't allow getattr operation in our selinux policy.
+ @Test
+ public void selinuxEnabled() {
+ // Expect the return value to be EACCES (13).
+ assertEquals(13, checkGetattr());
+ }
+
private native boolean confirmKernelVersion();
private native int performKernelSpaceUffd();
private native int uffdWithoutUserModeOnly();
private native int performMremapDontUnmap();
private native int performMinorUffd();
+ private native int checkGetattr();
}
diff --git a/tests/tests/os/src/android/os/cts/BundleTest.java b/tests/tests/os/src/android/os/cts/BundleTest.java
index 27d5643..380cf23 100644
--- a/tests/tests/os/src/android/os/cts/BundleTest.java
+++ b/tests/tests/os/src/android/os/cts/BundleTest.java
@@ -671,6 +671,28 @@
}
@Test
+ public void testGetParcelableArrayListTypeSafe_withMismatchingTypeAndDifferentReturnType_returnsNull() {
+ final ArrayList<CustomParcelable> originalObjects = new ArrayList<>();
+ originalObjects.add(new CustomParcelable(42, "don't panic"));
+ mBundle.putParcelableArrayList(KEY1, originalObjects);
+ roundtrip();
+ ArrayList<Parcelable> result = mBundle.getParcelableArrayList(KEY1, Intent.class);
+ assertNull(result);
+ assertFalse(CustomParcelable.sDeserialized);
+ }
+
+ @Test
+ public void testGetParcelableArrayListTypeSafe_withMatchingTypeAndDifferentReturnType__returnsObject() {
+ final ArrayList<CustomParcelable> original = new ArrayList<>();
+ original.add(new CustomParcelable(42, "don't panic"));
+ original.add(new CustomParcelable(1961, "off we go"));
+ mBundle.putParcelableArrayList(KEY1, original);
+ roundtrip();
+ ArrayList<Parcelable> result = mBundle.getParcelableArrayList(KEY1, CustomParcelable.class);
+ assertEquals(original, result);
+ }
+
+ @Test
public void testGetParcelableArrayListTypeSafe_withBaseType_returnsObject() {
final ArrayList<CustomParcelable> original = new ArrayList<>();
original.add(new CustomParcelable(42, "don't panic"));
@@ -826,6 +848,29 @@
}
@Test
+ public void testGetSparseParcelableArrayTypeSafe_withMismatchingTypeAndDifferentReturnType_returnsNull() {
+ final SparseArray<CustomParcelable> originalObjects = new SparseArray<>();
+ originalObjects.put(42, new CustomParcelable(42, "don't panic"));
+ mBundle.putSparseParcelableArray(KEY1, originalObjects);
+ roundtrip();
+ SparseArray<Parcelable> result = mBundle.getSparseParcelableArray(KEY1, Intent.class);
+ assertNull(result);
+ assertFalse(CustomParcelable.sDeserialized);
+ }
+
+ @Test
+ public void testGetSparseParcelableArrayTypeSafe_withMatchingTypeAndDifferentReturnType_returnsObject() {
+ final SparseArray<CustomParcelable> original = new SparseArray<>();
+ original.put(42, new CustomParcelable(42, "don't panic"));
+ original.put(1961, new CustomParcelable(1961, "off we go"));
+ mBundle.putSparseParcelableArray(KEY1, original);
+ roundtrip();
+ SparseArray<Parcelable> result = mBundle.getSparseParcelableArray(KEY1,
+ CustomParcelable.class);
+ assertTrue(original.contentEquals(result));
+ }
+
+ @Test
public void testGetSparseParcelableArrayTypeSafe_withBaseType_returnsObject() {
final SparseArray<CustomParcelable> original = new SparseArray<>();
original.put(42, new CustomParcelable(42, "don't panic"));
diff --git a/tests/app/src/android/app/cts/PropertyInvalidatedCacheTests.java b/tests/tests/os/src/android/os/cts/IpcDataCacheTest.java
similarity index 86%
rename from tests/app/src/android/app/cts/PropertyInvalidatedCacheTests.java
rename to tests/tests/os/src/android/os/cts/IpcDataCacheTest.java
index 98b1bca..89c647d 100644
--- a/tests/app/src/android/app/cts/PropertyInvalidatedCacheTests.java
+++ b/tests/tests/os/src/android/os/cts/IpcDataCacheTest.java
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-package android.app.cts;
+package android.os.cts;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
-import android.app.PropertyInvalidatedCache;
+import android.os.IpcDataCache;
import androidx.test.filters.SmallTest;
@@ -28,19 +28,19 @@
import org.junit.Test;
/**
- * Test for verifying the behavior of {@link PropertyInvalidatedCache}. This test does
+ * Test for verifying the behavior of {@link IpcDataCache}. This test does
* not use any actual binder calls - it is entirely self-contained. This test also relies
- * on the test mode of {@link PropertyInvalidatedCache} because Android SELinux rules do
+ * on the test mode of {@link IpcDataCache} because Android SELinux rules do
* not grant test processes the permission to set system properties.
* <p>
* Build/Install/Run:
- * atest FrameworksCoreTests:PropertyInvalidatedCacheTests
+ * atest CtsOsTestCases:IpcDataCacheTest
*/
@SmallTest
-public class PropertyInvalidatedCacheTests {
+public class IpcDataCacheTest {
// Configuration for creating caches
- private static final String MODULE = PropertyInvalidatedCache.MODULE_TEST;
+ private static final String MODULE = IpcDataCache.MODULE_TEST;
private static final String API = "testApi";
// This class is a proxy for binder calls. It contains a counter that increments
@@ -68,7 +68,7 @@
// The functions for querying the server.
private static class ServerQuery
- extends PropertyInvalidatedCache.QueryHandler<Integer, Boolean> {
+ extends IpcDataCache.QueryHandler<Integer, Boolean> {
private final ServerProxy mServer;
ServerQuery(ServerProxy server) {
@@ -89,7 +89,7 @@
// tests. This also resets the test property map.
@After
public void tearDown() throws Exception {
- PropertyInvalidatedCache.setTestMode(false);
+ IpcDataCache.setTestMode(false);
}
// This test is disabled pending an sepolicy change that allows any app to set the
@@ -102,11 +102,11 @@
ServerProxy tester = new ServerProxy();
// Create a cache that uses simple arithmetic to computer its values.
- PropertyInvalidatedCache<Integer, Boolean> testCache =
- new PropertyInvalidatedCache<>(4, MODULE, API, "testCache1",
+ IpcDataCache<Integer, Boolean> testCache =
+ new IpcDataCache<>(4, MODULE, API, "testCache1",
new ServerQuery(tester));
- PropertyInvalidatedCache.setTestMode(true);
+ IpcDataCache.setTestMode(true);
testCache.testPropertyName();
tester.verify(0);
@@ -148,14 +148,14 @@
ServerProxy tester = new ServerProxy();
// Three caches, all using the same system property but one uses a different name.
- PropertyInvalidatedCache<Integer, Boolean> cache1 =
- new PropertyInvalidatedCache<>(4, MODULE, API, "cacheA",
+ IpcDataCache<Integer, Boolean> cache1 =
+ new IpcDataCache<>(4, MODULE, API, "cacheA",
new ServerQuery(tester));
- PropertyInvalidatedCache<Integer, Boolean> cache2 =
- new PropertyInvalidatedCache<>(4, MODULE, API, "cacheA",
+ IpcDataCache<Integer, Boolean> cache2 =
+ new IpcDataCache<>(4, MODULE, API, "cacheA",
new ServerQuery(tester));
- PropertyInvalidatedCache<Integer, Boolean> cache3 =
- new PropertyInvalidatedCache<>(4, MODULE, API, "cacheB",
+ IpcDataCache<Integer, Boolean> cache3 =
+ new IpcDataCache<>(4, MODULE, API, "cacheB",
new ServerQuery(tester));
// Caches are enabled upon creation.
@@ -177,7 +177,7 @@
assertEquals(false, cache3.getDisabledState());
// Create a new cache1. Verify that the new instance is disabled.
- cache1 = new PropertyInvalidatedCache<>(4, MODULE, API, "cacheA",
+ cache1 = new IpcDataCache<>(4, MODULE, API, "cacheA",
new ServerQuery(tester));
assertEquals(true, cache1.getDisabledState());
@@ -188,13 +188,13 @@
assertEquals(false, cache3.getDisabledState());
// Create a new cache1. Verify that the new instance is not disabled.
- cache1 = new PropertyInvalidatedCache<>(4, MODULE, API, "cacheA",
+ cache1 = new IpcDataCache<>(4, MODULE, API, "cacheA",
new ServerQuery(tester));
assertEquals(false, cache1.getDisabledState());
}
private static class TestQuery
- extends PropertyInvalidatedCache.QueryHandler<Integer, String> {
+ extends IpcDataCache.QueryHandler<Integer, String> {
private int mRecomputeCount = 0;
@@ -209,7 +209,7 @@
}
}
- private static class TestCache extends PropertyInvalidatedCache<Integer, String> {
+ private static class TestCache extends IpcDataCache<Integer, String> {
private final TestQuery mQuery;
TestCache() {
@@ -248,7 +248,7 @@
assertEquals("foo5", cache.query(5));
assertEquals(3, cache.getRecomputeCount());
// Invalidate the cache with a direct call to the property.
- PropertyInvalidatedCache.invalidateCache(MODULE, API);
+ IpcDataCache.invalidateCache(MODULE, API);
assertEquals("foo5", cache.query(5));
assertEquals("foo5", cache.query(5));
assertEquals(4, cache.getRecomputeCount());
diff --git a/tests/tests/os/src/android/os/cts/ProcessTest.java b/tests/tests/os/src/android/os/cts/ProcessTest.java
index 8ca7811..f72cd01 100644
--- a/tests/tests/os/src/android/os/cts/ProcessTest.java
+++ b/tests/tests/os/src/android/os/cts/ProcessTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -26,6 +27,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.Process;
import android.util.Log;
@@ -242,11 +244,23 @@
@Test
public void testSdkSandboxUids() {
assertEquals(SANDBOX_SDK_UID, Process.toSdkSandboxUid(APP_UID));
- assertEquals(APP_UID, Process.sdkSandboxToAppUid(SANDBOX_SDK_UID));
+ assertEquals(APP_UID, Process.getAppUidForSdkSandboxUid(SANDBOX_SDK_UID));
assertFalse(Process.isSdkSandboxUid(APP_UID));
assertTrue(Process.isSdkSandboxUid(SANDBOX_SDK_UID));
assertFalse(Process.isSdkSandbox());
}
+
+ /**
+ * Tests that the reserved UID is not taken by an actual package.
+ */
+ @Test
+ public void testReservedVirtualUid() {
+ PackageManager pm = mContext.getPackageManager();
+ final String name = pm.getNameForUid(Process.SDK_SANDBOX_VIRTUAL_UID);
+ assertNull(name);
+ final String[] packages = pm.getPackagesForUid(Process.SDK_SANDBOX_VIRTUAL_UID);
+ assertNull(packages);
+ }
}
diff --git a/tests/tests/packageinstaller/adminpackageinstaller/Android.bp b/tests/tests/packageinstaller/adminpackageinstaller/Android.bp
index 40f85c4..62a44fc 100644
--- a/tests/tests/packageinstaller/adminpackageinstaller/Android.bp
+++ b/tests/tests/packageinstaller/adminpackageinstaller/Android.bp
@@ -25,6 +25,7 @@
"ub-uiautomator",
"androidx.test.rules",
"androidx.legacy_legacy-support-v4",
+ "cts-install-lib",
],
libs: ["android.test.base"],
sdk_version: "test_current",
diff --git a/tests/tests/packageinstaller/adminpackageinstaller/AndroidTest.xml b/tests/tests/packageinstaller/adminpackageinstaller/AndroidTest.xml
index 5deef30..4ef431c 100644
--- a/tests/tests/packageinstaller/adminpackageinstaller/AndroidTest.xml
+++ b/tests/tests/packageinstaller/adminpackageinstaller/AndroidTest.xml
@@ -29,7 +29,9 @@
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="mkdir -p /data/local/tmp/cts/packageinstaller/" />
+ <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
<option name="teardown-command" value="rm -rf /data/local/tmp/cts"/>
+ <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
diff --git a/tests/tests/packageinstaller/adminpackageinstaller/src/android/packageinstaller/admin/cts/SessionCommitBroadcastTest.java b/tests/tests/packageinstaller/adminpackageinstaller/src/android/packageinstaller/admin/cts/SessionCommitBroadcastTest.java
index 8d8d19e..6ebd026 100644
--- a/tests/tests/packageinstaller/adminpackageinstaller/src/android/packageinstaller/admin/cts/SessionCommitBroadcastTest.java
+++ b/tests/tests/packageinstaller/adminpackageinstaller/src/android/packageinstaller/admin/cts/SessionCommitBroadcastTest.java
@@ -28,6 +28,11 @@
import android.os.UserManager;
import android.text.TextUtils;
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.TestApp;
+import com.android.cts.install.lib.Uninstall;
+
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -54,6 +59,7 @@
@Override
protected void tearDown() throws Exception {
mContext.unregisterReceiver(mReceiver);
+ Uninstall.packages(TestApp.A);
}
public void testBroadcastNotReceivedForDifferentLauncher() throws Exception {
@@ -91,6 +97,36 @@
assertEquals(TEST_APP_PKG, info.getAppPackageName());
}
+ public void testBroadcastNotReceivedForUpdateInstall() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+
+ try {
+ setLauncher(mThisAppLauncher.flattenToString());
+
+ int sessionId = Install.single(TestApp.A1).commit();
+ assertEquals(1, InstallUtils.getInstalledVersion(TestApp.A));
+ // Check the broadcast is received for a new install and session id matches
+ Intent intent = mReceiver.blockingGetIntent();
+ PackageInstaller.SessionInfo info =
+ intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
+ assertEquals(sessionId, info.getSessionId());
+
+ mContext.unregisterReceiver(mReceiver);
+ mReceiver = new SessionCommitReceiver();
+ Install.single(TestApp.A2).commit();
+ assertEquals(2, InstallUtils.getInstalledVersion(TestApp.A));
+
+ // Check no broadcast is received for an update install
+ intent = mReceiver.blockingGetIntent();
+ assertNull(intent);
+ } finally {
+ // Revert to default launcher
+ setLauncher(mDefaultLauncher.flattenToString());
+ }
+ }
+
public void testBroadcastReceivedForNewInstall() throws Exception {
if (!mHasFeature) {
return;
diff --git a/tests/tests/permission/AndroidTest.xml b/tests/tests/permission/AndroidTest.xml
index 3176050..6f9b07a 100644
--- a/tests/tests/permission/AndroidTest.xml
+++ b/tests/tests/permission/AndroidTest.xml
@@ -91,6 +91,7 @@
<option name="push" value="CtsStorageEscalationApp28.apk->/data/local/tmp/cts/permissions/CtsStorageEscalationApp28.apk" />
<option name="push" value="CtsStorageEscalationApp29Full.apk->/data/local/tmp/cts/permissions/CtsStorageEscalationApp29Full.apk" />
<option name="push" value="CtsStorageEscalationApp29Scoped.apk->/data/local/tmp/cts/permissions/CtsStorageEscalationApp29Scoped.apk" />
+ <option name="push" value="CtsAppThatHasNotificationListener.apk->/data/local/tmp/cts/permissions/CtsAppThatHasNotificationListener.apk" />
</target_preparer>
<!-- Remove additional apps if installed -->
@@ -102,6 +103,7 @@
<option name="teardown-command" value="pm uninstall android.permission.cts.revokepermissionwhenremoved.userapp" />
<option name="teardown-command" value="pm uninstall android.permission.cts.revokepermissionwhenremoved.runtimepermissiondefinerapp" />
<option name="teardown-command" value="pm uninstall android.permission.cts.revokepermissionwhenremoved.runtimepermissionuserapp" />
+ <option name="teardown-command" value="pm uninstall android.permission.cts.appthathasnotificationlistener" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
diff --git a/tests/tests/permission/AppThatHasNotificationListener/Android.bp b/tests/tests/permission/AppThatHasNotificationListener/Android.bp
new file mode 100644
index 0000000..419ab5d
--- /dev/null
+++ b/tests/tests/permission/AppThatHasNotificationListener/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatHasNotificationListener",
+ defaults: [
+ "cts_defaults",
+ "mts-target-sdk-version-current",
+ ],
+ sdk_version: "current",
+ min_sdk_version: "30",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ "mts-permission",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+}
diff --git a/tests/tests/permission/AppThatHasNotificationListener/AndroidManifest.xml b/tests/tests/permission/AppThatHasNotificationListener/AndroidManifest.xml
new file mode 100644
index 0000000..03d23df
--- /dev/null
+++ b/tests/tests/permission/AppThatHasNotificationListener/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission.cts.appthathasnotificationlistener"
+ android:versionCode="1">
+
+ <application android:label="CtsNotificationListener">
+ <service
+ android:name=".CtsNotificationListenerService"
+ android:label="CtsNotificationListener"
+ android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.service.notification.NotificationListenerService"/>
+ </intent-filter>
+ </service>
+ </application>
+</manifest>
diff --git a/tests/tests/permission/AppThatHasNotificationListener/src/android/permission/cts/appthathasnotificationlistener/CtsNotificationListenerService.java b/tests/tests/permission/AppThatHasNotificationListener/src/android/permission/cts/appthathasnotificationlistener/CtsNotificationListenerService.java
new file mode 100644
index 0000000..2bd423e
--- /dev/null
+++ b/tests/tests/permission/AppThatHasNotificationListener/src/android/permission/cts/appthathasnotificationlistener/CtsNotificationListenerService.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts.appthathasnotificationlistener;
+
+import android.service.notification.NotificationListenerService;
+
+public class CtsNotificationListenerService extends NotificationListenerService {}
diff --git a/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/TestUtils.java b/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/TestUtils.java
new file mode 100644
index 0000000..d7c71b9
--- /dev/null
+++ b/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/TestUtils.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+/** Common test utilities */
+public class TestUtils {
+ private static final String LOG_TAG = TestUtils.class.getSimpleName();
+
+ /**
+ * A {@link java.util.concurrent.Callable} that can throw a {@link Throwable}
+ */
+ public interface ThrowingCallable<T> {
+ T call() throws Throwable;
+ }
+
+ /**
+ * A {@link Runnable} that can throw a {@link Throwable}
+ */
+ public interface ThrowingRunnable {
+ void run() throws Throwable;
+ }
+
+ /**
+ * Make sure that a {@link ThrowingRunnable} eventually finishes without throwing a {@link
+ * Exception}.
+ *
+ * @param r The {@link ThrowingRunnable} to run.
+ * @param timeout the maximum time to wait
+ */
+ public static void eventually(@NonNull ThrowingRunnable r, long timeout) throws Throwable {
+ eventually(() -> {
+ r.run();
+ return 0;
+ }, timeout);
+ }
+
+ /**
+ * Make sure that a {@link ThrowingCallable} eventually finishes without throwing a {@link
+ * Exception}.
+ *
+ * @param r The {@link ThrowingCallable} to run.
+ * @param timeout the maximum time to wait
+ * @return the return value from the callable
+ * @throws NullPointerException If the return value never becomes non-null
+ */
+ public static <T> T eventually(@NonNull ThrowingCallable<T> r, long timeout) throws Throwable {
+ long start = System.currentTimeMillis();
+
+ while (true) {
+ try {
+ T res = r.call();
+ if (res == null) {
+ throw new NullPointerException("No result");
+ }
+
+ return res;
+ } catch (Throwable e) {
+ if (System.currentTimeMillis() - start < timeout) {
+ Log.d(LOG_TAG, "Ignoring exception, occurred within valid wait time", e);
+
+ Thread.sleep(500);
+ } else {
+ throw e;
+ }
+ }
+ }
+ }
+}
diff --git a/tests/tests/permission/src/android/permission/cts/NotificationListenerCheckTest.java b/tests/tests/permission/src/android/permission/cts/NotificationListenerCheckTest.java
new file mode 100644
index 0000000..8d58bee
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/NotificationListenerCheckTest.java
@@ -0,0 +1,638 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.content.Intent.ACTION_BOOT_COMPLETED;
+import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
+import static android.os.Process.myUserHandle;
+import static android.permission.cts.PermissionUtils.clearAppState;
+import static android.permission.cts.PermissionUtils.install;
+import static android.permission.cts.PermissionUtils.uninstallApp;
+import static android.permission.cts.TestUtils.eventually;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+import static com.android.server.job.nano.JobPackageHistoryProto.START_PERIODIC_JOB;
+import static com.android.server.job.nano.JobPackageHistoryProto.STOP_PERIODIC_JOB;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+
+import static java.lang.Math.max;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import android.app.NotificationManager;
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
+import android.provider.DeviceConfig;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.DeviceConfigStateHelper;
+import com.android.compatibility.common.util.ProtoUtils;
+import com.android.compatibility.common.util.mainline.MainlineModule;
+import com.android.compatibility.common.util.mainline.ModuleDetector;
+import com.android.server.job.nano.JobPackageHistoryProto;
+import com.android.server.job.nano.JobSchedulerServiceDumpProto;
+import com.android.server.job.nano.JobSchedulerServiceDumpProto.RegisteredJob;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests the {@code NotificationListenerCheck} in permission controller.
+ */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "Cannot set system settings as instant app. Also we never show a notification"
+ + " listener check notification for instant apps.")
+public class NotificationListenerCheckTest {
+ private static final String LOG_TAG = NotificationListenerCheckTest.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ private static final String TEST_APP_PKG =
+ "android.permission.cts.appthathasnotificationlistener";
+ private static final String TEST_APP_LABEL = "CtsLocationAccess";
+ private static final String TEST_APP_NOTIFICATION_SERVICE =
+ TEST_APP_PKG + ".CtsNotificationListenerService";
+ private static final String TEST_APP_NOTIFICATION_LISTENER_APK =
+ "/data/local/tmp/cts/permissions/CtsAppThatHasNotificationListener.apk";
+
+ private static final int NOTIFICATION_LISTENER_CHECK_JOB_ID = 4;
+
+ /**
+ * Device config property for whether notification listener check is enabled on the device
+ */
+ private static final String PROPERTY_NOTIFICATION_LISTENER_CHECK_ENABLED =
+ "notification_listener_check_enabled";
+
+ /**
+ * Device config property for time period in milliseconds after which current enabled
+ * notification
+ * listeners are queried
+ */
+ private static final String PROPERTY_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS =
+ "notification_listener_check_interval_millis";
+
+ private static final Long OVERRIDE_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS =
+ SECONDS.toMillis(1);
+
+ /**
+ * Device config property for time period in milliseconds after which a followup notification
+ * can be
+ * posted for an enabled notification listener
+ */
+ private static final String PROPERTY_NOTIFICATION_LISTENER_CHECK_PACKAGE_INTERVAL_MILLIS =
+ "notification_listener_check_pkg_interval_millis";
+
+ /**
+ * ID for notification shown by
+ * {@link com.android.permissioncontroller.permission.service.NotificationListenerCheck}.
+ */
+ public static final int NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID = 3;
+
+ private static final long UNEXPECTED_TIMEOUT_MILLIS = 10000;
+ private static final long EXPECTED_TIMEOUT_MILLIS = 15000;
+
+ private static final Context sContext = InstrumentationRegistry.getTargetContext();
+ private static final PackageManager sPackageManager = sContext.getPackageManager();
+ private static final UiAutomation sUiAutomation = InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation();
+
+ private static final String PERMISSION_CONTROLLER_PKG = sContext.getPackageManager()
+ .getPermissionControllerPackageName();
+
+ private static DeviceConfigStateHelper sPrivacyDeviceConfig =
+ new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_PRIVACY);
+ private static DeviceConfigStateHelper sJobSchedulerDeviceConfig =
+ new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_JOB_SCHEDULER);
+
+ private static List<ComponentName> sPreviouslyEnabledNotificationListeners;
+
+ /**
+ * Enable notification listener check
+ */
+ private static void enableNotificationListenerCheckFeature() {
+ sPrivacyDeviceConfig.set(PROPERTY_NOTIFICATION_LISTENER_CHECK_ENABLED,
+ String.valueOf(true));
+ }
+
+ /**
+ * Disable notification listener check
+ */
+ private static void disableNotificationListenerCheckFeature() {
+ sPrivacyDeviceConfig.set(PROPERTY_NOTIFICATION_LISTENER_CHECK_ENABLED,
+ String.valueOf(false));
+ }
+
+ private static void setNotificationListenerCheckInterval(long intervalMs) {
+ // Override general notification interval
+ sPrivacyDeviceConfig.set(PROPERTY_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS,
+ Long.toString(intervalMs));
+ }
+
+ private static void setNotificationListenerCheckPackageInterval(long intervalMs) {
+ // Override package notification interval
+ sPrivacyDeviceConfig.set(PROPERTY_NOTIFICATION_LISTENER_CHECK_PACKAGE_INTERVAL_MILLIS,
+ Long.toString(intervalMs));
+ }
+
+ /**
+ * Allow or disallow a {@link NotificationListenerService} component for the current user
+ *
+ * @param listenerComponent {@link NotificationListenerService} component to allow or disallow
+ */
+ private static void setNotificationListenerServiceAllowed(ComponentName listenerComponent,
+ boolean allowed) {
+ String command = " cmd notification " + (allowed ? "allow_listener " : "disallow_listener ")
+ + listenerComponent.flattenToString();
+ runShellCommand(command);
+ }
+
+ private void allowTestAppNotificationListenerService() {
+ setNotificationListenerServiceAllowed(
+ new ComponentName(TEST_APP_PKG, TEST_APP_NOTIFICATION_SERVICE), true);
+ }
+
+ private void disallowTestAppNotificationListenerService() {
+ setNotificationListenerServiceAllowed(
+ new ComponentName(TEST_APP_PKG, TEST_APP_NOTIFICATION_SERVICE), false);
+ }
+
+ /**
+ * Get the state of the job scheduler
+ */
+ private static JobSchedulerServiceDumpProto getJobSchedulerDump() throws Exception {
+ return ProtoUtils.getProto(sUiAutomation, JobSchedulerServiceDumpProto.class,
+ ProtoUtils.DUMPSYS_JOB_SCHEDULER);
+ }
+
+ /**
+ * Get the last time the NOTIFICATION_LISTENER_CHECK_JOB_ID job was started/stopped for
+ * permission
+ * controller.
+ *
+ * @param event the job event (start/stop)
+ * @return the last time the event happened.
+ */
+ private static long getLastJobTime(int event) throws Exception {
+ int permControllerUid = sPackageManager.getPackageUid(PERMISSION_CONTROLLER_PKG, 0);
+
+ long lastTime = -1;
+
+ for (JobPackageHistoryProto.HistoryEvent historyEvent :
+ getJobSchedulerDump().history.historyEvent) {
+ if (historyEvent.uid == permControllerUid
+ && historyEvent.jobId == NOTIFICATION_LISTENER_CHECK_JOB_ID
+ && historyEvent.event == event) {
+ lastTime = max(lastTime,
+ System.currentTimeMillis() - historyEvent.timeSinceEventMs);
+ }
+ }
+
+ return lastTime;
+ }
+
+ /**
+ * Force a run of the notification listener check.
+ */
+ private static void runNotificationListenerCheck() throws Throwable {
+ // Sleep a little to make sure we don't have overlap in timing
+ Thread.sleep(1000);
+
+ long beforeJob = System.currentTimeMillis();
+
+ // Sleep a little to avoid raciness in time keeping
+ Thread.sleep(1000);
+
+ runShellCommand("cmd jobscheduler run -u " + myUserHandle().getIdentifier() + " -f "
+ + PERMISSION_CONTROLLER_PKG + " " + NOTIFICATION_LISTENER_CHECK_JOB_ID);
+
+ eventually(() -> {
+ long startTime = getLastJobTime(START_PERIODIC_JOB);
+ assertTrue(startTime + " !> " + beforeJob, startTime > beforeJob);
+ }, EXPECTED_TIMEOUT_MILLIS);
+
+ // We can't simply require startTime <= endTime because the time being reported isn't
+ // accurate, and sometimes the end time may come before the start time by around 100 ms.
+ eventually(() -> {
+ long stopTime = getLastJobTime(STOP_PERIODIC_JOB);
+ assertTrue(stopTime + " !> " + beforeJob, stopTime > beforeJob);
+ }, EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ /**
+ * Get a notifications thrown by the permission controller that are currently visible.
+ *
+ * @return {@link java.util.List} of {@link StatusBarNotification}
+ */
+ private List<StatusBarNotification> getPermissionControllerNotifications() throws Exception {
+ NotificationListenerService notificationService = NotificationListener.getInstance();
+ List<StatusBarNotification> permissionControllerNotifications = new ArrayList<>();
+
+ for (StatusBarNotification notification : notificationService.getActiveNotifications()) {
+ if (notification.getPackageName().equals(PERMISSION_CONTROLLER_PKG)) {
+ permissionControllerNotifications.add(notification);
+ }
+ }
+
+ return permissionControllerNotifications;
+ }
+
+ /**
+ * Get a notification listener notification that is currently visible.
+ *
+ * @param cancelNotification if {@code true} the notification is canceled inside this method
+ * @return The notification or {@code null} if there is none
+ */
+ private StatusBarNotification getNotification(boolean cancelNotification) throws Throwable {
+ NotificationListenerService notificationService = NotificationListener.getInstance();
+
+ List<StatusBarNotification> notifications = getPermissionControllerNotifications();
+ if (notifications.isEmpty()) {
+ return null;
+ }
+
+ for (StatusBarNotification notification : notifications) {
+ // There may be multiple notification listeners on device that are already allowed. Just
+ // check for a notification posted from the NotificationListenerCheck
+ if (notification.getId() == NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID) {
+ if (cancelNotification) {
+ notificationService.cancelNotification(notification.getKey());
+
+ // Wait for notification to get canceled
+ eventually(() -> assertFalse(
+ Arrays.asList(notificationService.getActiveNotifications()).contains(
+ notification)), UNEXPECTED_TIMEOUT_MILLIS);
+ }
+
+ return notification;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Clears all permission controller notifications that are currently visible.
+ */
+ private void clearPermissionControllerNotifications() throws Throwable {
+ NotificationListenerService notificationService = NotificationListener.getInstance();
+
+ List<StatusBarNotification> notifications = getPermissionControllerNotifications();
+ if (notifications.isEmpty()) {
+ return;
+ }
+
+ for (StatusBarNotification notification : notifications) {
+ notificationService.cancelNotification(notification.getKey());
+
+ // Wait for notification to get canceled
+ eventually(() -> assertFalse(
+ Arrays.asList(notificationService.getActiveNotifications()).contains(
+ notification)), UNEXPECTED_TIMEOUT_MILLIS);
+ }
+ }
+
+ @BeforeClass
+ public static void beforeClassSetup() {
+ // Disallow any OEM enabled NLS
+ disallowPreexistingNotificationListeners();
+
+ // Allow NLS used to verify notifications sent
+ setNotificationListenerServiceAllowed(
+ new ComponentName(sContext, NotificationListener.class), true);
+
+ reduceDelays();
+ }
+
+ @AfterClass
+ public static void afterClassTearDown() throws Throwable {
+ resetJobSchedulerConfig();
+ resetPermissionControllerConfig();
+
+ // Disallow NLS used to verify notifications sent
+ setNotificationListenerServiceAllowed(
+ new ComponentName(sContext, NotificationListener.class), false);
+
+ // Reallow any previously OEM allowed NLS
+ reallowPreexistingNotificationListeners();
+ }
+
+ private static void disallowPreexistingNotificationListeners() {
+ runWithShellPermissionIdentity(() -> {
+ NotificationManager notificationManager =
+ sContext.getSystemService(NotificationManager.class);
+ sPreviouslyEnabledNotificationListeners =
+ notificationManager.getEnabledNotificationListeners();
+ });
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Found " + sPreviouslyEnabledNotificationListeners.size()
+ + " previously allowed notification listeners. Disabling before test run.");
+ }
+ for (ComponentName listener : sPreviouslyEnabledNotificationListeners) {
+ setNotificationListenerServiceAllowed(listener, false);
+ }
+ }
+
+ private static void reallowPreexistingNotificationListeners() {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Re-allowing " + sPreviouslyEnabledNotificationListeners.size()
+ + " previously allowed notification listeners found before test run.");
+ }
+ for (ComponentName listener : sPreviouslyEnabledNotificationListeners) {
+ setNotificationListenerServiceAllowed(listener, true);
+ }
+ }
+
+ /**
+ * Change settings so that permission controller can show notification listener notifications
+ * more often.
+ */
+ private static void reduceDelays() {
+ runWithShellPermissionIdentity(() -> {
+ // Override general notification interval from once every day to once ever 1 second
+ setNotificationListenerCheckInterval(
+ OVERRIDE_NOTIFICATION_LISTENER_CHECK_INTERVAL_MILLIS);
+
+ // Disable job scheduler throttling by allowing 300000 jobs per 30 sec
+ sJobSchedulerDeviceConfig.set("qc_max_job_count_per_rate_limiting_window", "3000000");
+ sJobSchedulerDeviceConfig.set("qc_rate_limiting_window_ms", "30000");
+ });
+ }
+
+ /**
+ * Reset job scheduler configs.
+ */
+ private static void resetJobSchedulerConfig() throws Throwable {
+ runWithShellPermissionIdentity(() -> {
+ sJobSchedulerDeviceConfig.restoreOriginalValues();
+ });
+ }
+
+ /**
+ * Reset privacy configs.
+ */
+ private static void resetPermissionControllerConfig() {
+ runWithShellPermissionIdentity(() -> {
+ sPrivacyDeviceConfig.restoreOriginalValues();
+ });
+ }
+
+ @Before
+ public void setup() throws Throwable {
+ assumeNotPlayManaged();
+ wakeUpAndDismissKeyguard();
+ resetPermissionControllerBeforeEachTest();
+
+ // Cts NLS is required to verify sent Notifications, however, we don't want it to show up in
+ // testing
+ showAndDismissCtsNotificationListener();
+
+ clearNotifications();
+
+ // Sleep a little to avoid raciness in time keeping
+ Thread.sleep(1000);
+
+ // Install and allow the app with NLS for testing
+ install(TEST_APP_NOTIFICATION_LISTENER_APK);
+ allowTestAppNotificationListenerService();
+ }
+
+ @After
+ public void tearDown() throws Throwable {
+ // Disallow and uninstall the app with NLS for testing
+ disallowTestAppNotificationListenerService();
+ uninstallApp(TEST_APP_NOTIFICATION_LISTENER_APK);
+
+ clearNotifications();
+ }
+
+ /**
+ * Skip each test for play managed module
+ */
+ private void assumeNotPlayManaged() throws Exception {
+ assumeFalse(ModuleDetector.moduleIsPlayManaged(
+ sContext.getPackageManager(), MainlineModule.PERMISSION_CONTROLLER));
+ }
+
+ private void wakeUpAndDismissKeyguard() {
+ runShellCommand("input keyevent KEYCODE_WAKEUP");
+ runShellCommand("wm dismiss-keyguard");
+ }
+
+ /**
+ * Reset the permission controllers state before each test
+ */
+ private void resetPermissionControllerBeforeEachTest() throws Throwable {
+ // Has to be before resetPermissionController
+ enableNotificationListenerCheckFeature();
+
+ resetPermissionController();
+
+ // ensure no posted notification listener notifications exits
+ eventually(() -> assertNull(getNotification(false)), UNEXPECTED_TIMEOUT_MILLIS);
+
+ // Reset job scheduler stats (to allow more jobs to be run)
+ runShellCommand(
+ "cmd jobscheduler reset-execution-quota -u " + myUserHandle().getIdentifier() + " "
+ + PERMISSION_CONTROLLER_PKG);
+ }
+
+ /**
+ * Reset the permission controllers state.
+ */
+ private static void resetPermissionController() throws Throwable {
+ clearAppState(PERMISSION_CONTROLLER_PKG);
+ int currentUserId = myUserHandle().getIdentifier();
+
+ // Wait until jobs are cleared
+ eventually(() -> {
+ JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
+
+ for (RegisteredJob job : dump.registeredJobs) {
+ if (job.dump.sourceUserId == currentUserId) {
+ assertNotEquals(job.dump.sourcePackageName, PERMISSION_CONTROLLER_PKG);
+ }
+ }
+ }, UNEXPECTED_TIMEOUT_MILLIS);
+
+ // Setup up permission controller again (simulate a reboot)
+ Intent permissionControllerSetupIntent = null;
+ for (ResolveInfo ri : sContext.getPackageManager().queryBroadcastReceivers(
+ new Intent(ACTION_BOOT_COMPLETED), 0)) {
+ String pkg = ri.activityInfo.packageName;
+
+ if (pkg.equals(PERMISSION_CONTROLLER_PKG)) {
+ permissionControllerSetupIntent = new Intent()
+ .setClassName(pkg, ri.activityInfo.name)
+ .setFlags(FLAG_RECEIVER_FOREGROUND)
+ .setPackage(PERMISSION_CONTROLLER_PKG);
+
+ sContext.sendBroadcast(permissionControllerSetupIntent);
+ }
+ }
+
+ // Wait until jobs are set up
+ eventually(() -> {
+ JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
+
+ for (RegisteredJob job : dump.registeredJobs) {
+ if (job.dump.sourceUserId == currentUserId
+ && job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)
+ && job.dump.jobInfo.service.className.contains(
+ "NotificationListenerCheck")) {
+ return;
+ }
+ }
+
+ fail("Permission controller jobs not found");
+ }, UNEXPECTED_TIMEOUT_MILLIS);
+ }
+
+ /**
+ * Preshow/dismiss cts NotificationListener notification as it negatively affects test results
+ * (can result in unexpected test pass/failures)
+ */
+ private void showAndDismissCtsNotificationListener() throws Throwable {
+ // CtsNotificationListenerService isn't enabled at this point, but NotificationListener
+ // should be. Mark as notified by showing and dismissing
+ runNotificationListenerCheck();
+
+ // Sleep a little to avoid raciness in time keeping
+ Thread.sleep(1000);
+ }
+
+ /**
+ * Clear any notifications related to NotificationListenerCheck to ensure clean test setup
+ */
+ private void clearNotifications() throws Throwable {
+ // Clear notification if present
+ clearPermissionControllerNotifications();
+ }
+
+ @Test
+ public void noNotificationIfFeatureDisabled() throws Throwable {
+ disableNotificationListenerCheckFeature();
+
+ runNotificationListenerCheck();
+
+ assertNull("Expected no notifications", getNotification(false));
+ }
+
+ @Test
+ public void notificationIsShown() throws Throwable {
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNotNull("Expected notification, none found", getNotification(true)),
+ EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void notificationIsShownOnlyOnce() throws Throwable {
+ runNotificationListenerCheck();
+ eventually(() -> assertNotNull(getNotification(true)), EXPECTED_TIMEOUT_MILLIS);
+
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void notificationIsShownAgainAfterClear() throws Throwable {
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), EXPECTED_TIMEOUT_MILLIS);
+
+ clearAppState(TEST_APP_PKG);
+
+ // Wait until package is cleared and permission controller has cleared the state
+ Thread.sleep(10000);
+
+ allowTestAppNotificationListenerService();
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void notificationIsShownAgainAfterUninstallAndReinstall() throws Throwable {
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), EXPECTED_TIMEOUT_MILLIS);
+
+ uninstallApp(TEST_APP_PKG);
+
+ // Wait until package permission controller has cleared the state
+ Thread.sleep(2000);
+
+ install(TEST_APP_NOTIFICATION_LISTENER_APK);
+
+ allowTestAppNotificationListenerService();
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNotNull(getNotification(true)), EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void removeNotificationOnUninstall() throws Throwable {
+ runNotificationListenerCheck();
+
+ eventually(() -> assertNotNull(getNotification(false)), EXPECTED_TIMEOUT_MILLIS);
+
+ uninstallApp(TEST_APP_PKG);
+
+ // Wait until package permission controller has cleared the state
+ Thread.sleep(2000);
+
+ eventually(() -> assertNull(getNotification(false)), EXPECTED_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void notificationIsNotShownAfterDisableAppNotificationListener() throws Throwable {
+ disallowTestAppNotificationListenerService();
+
+ runNotificationListenerCheck();
+
+ // We don't expect a notification, but try to trigger one anyway
+ eventually(() -> assertNull(getNotification(false)), UNEXPECTED_TIMEOUT_MILLIS);
+ }
+}
diff --git a/tests/tests/permission/src/android/permission/cts/SplitPermissionsSystemTest.java b/tests/tests/permission/src/android/permission/cts/SplitPermissionsSystemTest.java
index 28e5b20..b131462 100755
--- a/tests/tests/permission/src/android/permission/cts/SplitPermissionsSystemTest.java
+++ b/tests/tests/permission/src/android/permission/cts/SplitPermissionsSystemTest.java
@@ -30,7 +30,7 @@
import static android.Manifest.permission.READ_CONTACTS;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.READ_MEDIA_AUDIO;
-import static android.Manifest.permission.READ_MEDIA_IMAGE;
+import static android.Manifest.permission.READ_MEDIA_IMAGES;
import static android.Manifest.permission.READ_MEDIA_VIDEO;
import static android.Manifest.permission.READ_PHONE_STATE;
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
@@ -123,8 +123,8 @@
assertSplit(split, Build.VERSION_CODES.S_V2 + 1, READ_MEDIA_AUDIO);
} else if (newPermissions.contains(READ_MEDIA_VIDEO)) {
assertSplit(split, Build.VERSION_CODES.S_V2 + 1, READ_MEDIA_VIDEO);
- } else if (newPermissions.contains(READ_MEDIA_IMAGE)) {
- assertSplit(split, Build.VERSION_CODES.S_V2 + 1, READ_MEDIA_IMAGE);
+ } else if (newPermissions.contains(READ_MEDIA_IMAGES)) {
+ assertSplit(split, Build.VERSION_CODES.S_V2 + 1, READ_MEDIA_IMAGES);
}
break;
case READ_PRIVILEGED_PHONE_STATE:
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index fc564ea7..ffd5556 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -1023,7 +1023,7 @@
targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
<p>Protection level: dangerous -->
- <permission android:name="android.permission.READ_MEDIA_IMAGE"
+ <permission android:name="android.permission.READ_MEDIA_IMAGES"
android:permissionGroup="android.permission-group.UNDEFINED"
android:label="@string/permlab_readMediaImage"
android:description="@string/permdesc_readMediaImage"
@@ -1882,13 +1882,23 @@
android:protectionLevel="normal" />
<!-- Allows applications to enable/disable wifi auto join. This permission
- is used to let OEMs grant their trusted app access to a subset of privileged wifi APIs
- to improve wifi performance.
- <p>Not for use by third-party applications. -->
+ is used to let OEMs grant their trusted app access to a subset of privileged wifi APIs
+ to improve wifi performance.
+ <p>Not for use by third-party applications.
+ @deprecated will be replaced with MANAGE_WIFI_NETWORK_SELECTION -->
<permission android:name="android.permission.MANAGE_WIFI_AUTO_JOIN"
android:protectionLevel="signature|privileged|knownSigner"
android:knownCerts="@array/wifi_known_signers" />
+ <!-- This permission is used to let OEMs grant their trusted app access to a subset of
+ privileged wifi APIs to improve wifi performance. Allows applications to manage
+ Wi-Fi network selection related features such as enable or disable global auto-join,
+ modify connectivity scan intervals, and approve Wi-Fi Direct connections.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_WIFI_NETWORK_SELECTION"
+ android:protectionLevel="signature|privileged|knownSigner"
+ android:knownCerts="@array/wifi_known_signers" />
+
<!-- Allows applications to get notified when a Wi-Fi interface request cannot
be satisfied without tearing down one or more other interfaces, and provide a decision
whether to approve the request or reject it.
@@ -2928,7 +2938,7 @@
<!-- @SystemApi @hide Allows an application to set the profile owners and the device owner.
This permission is not available to third party applications.-->
<permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
- android:protectionLevel="signature|role|setup"
+ android:protectionLevel="signature|role"
android:label="@string/permlab_manageProfileAndDeviceOwners"
android:description="@string/permdesc_manageProfileAndDeviceOwners" />
@@ -2937,6 +2947,10 @@
<permission android:name="android.permission.QUERY_ADMIN_POLICY"
android:protectionLevel="signature|role" />
+ <!-- @SystemApi @hide Allows an application to set a device owner on retail demo devices.-->
+ <permission android:name="android.permission.PROVISION_DEMO_DEVICE"
+ android:protectionLevel="signature|setup" />
+
<!-- @TestApi @hide Allows an application to reset the record of previous system update freeze
periods. -->
<permission android:name="android.permission.CLEAR_FREEZE_PERIOD"
@@ -3081,7 +3095,7 @@
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY"
- android:protectionLevel="signature|recents|role"/>
+ android:protectionLevel="signature|recents|role|installer"/>
<!-- @deprecated Use {@link android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND}
@hide
@@ -3710,13 +3724,20 @@
android:protectionLevel="signature|privileged" />
<!-- ========================================= -->
- <!-- Permissions for SupplementalApi -->
+ <!-- Permissions for AdServices -->
<!-- ========================================= -->
<eat-comment />
- <!-- TODO(b/213488783): Update with correct names. -->
- <!-- Allows an application to access SupplementalApis. -->
- <permission android:name="android.permission.ACCESS_SUPPLEMENTAL_APIS"
+ <!-- Allows an application to access AdServices Topics API. -->
+ <permission android:name="android.permission.ACCESS_ADSERVICES_TOPICS"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to access AdServices Attribution APIs. -->
+ <permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to access AdServices Custom Audiences APIs. -->
+ <permission android:name="android.permission.ACCESS_ADSERVICES_CUSTOM_AUDIENCES"
android:protectionLevel="normal" />
<!-- ==================================== -->
@@ -6137,7 +6158,7 @@
<!-- Allows the use of FLAG_SLIPPERY, which permits touch events to slip from the current
window to the window where the touch currently is on top of. @hide -->
<permission android:name="android.permission.ALLOW_SLIPPERY_TOUCHES"
- android:protectionLevel="signature|recents" />
+ android:protectionLevel="signature|privileged|recents|role" />
<!-- Allows the caller to change the associations between input devices and displays.
Very dangerous! @hide -->
<permission android:name="android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY"
@@ -6376,6 +6397,12 @@
<permission android:name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an UID to be visible to the application based on an interaction between the
+ two apps. This permission is not intended to be held by apps.
+ @hide @TestApi -->
+ <permission android:name="android.permission.MAKE_UID_VISIBLE"
+ android:protectionLevel="signature" />
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
diff --git a/tests/tests/permission3/Android.bp b/tests/tests/permission3/Android.bp
index d3f2721..36d24af 100644
--- a/tests/tests/permission3/Android.bp
+++ b/tests/tests/permission3/Android.bp
@@ -58,6 +58,7 @@
":CtsHelperAppOverlay",
":CtsCreateNotificationChannelsApp31",
":CtsCreateNotificationChannelsApp33",
+ ":CtsDifferentPkgNameApp",
],
test_suites: [
"cts",
diff --git a/tests/tests/permission3/AndroidTest.xml b/tests/tests/permission3/AndroidTest.xml
index 129cb4d..9e54fc6 100644
--- a/tests/tests/permission3/AndroidTest.xml
+++ b/tests/tests/permission3/AndroidTest.xml
@@ -63,6 +63,7 @@
<option name="push" value="CtsHelperAppOverlay.apk->/data/local/tmp/cts/permission3/CtsHelperAppOverlay.apk" />
<option name="push" value="CtsCreateNotificationChannelsApp31.apk->/data/local/tmp/cts/permission3/CtsCreateNotificationChannelsApp31.apk" />
<option name="push" value="CtsCreateNotificationChannelsApp33.apk->/data/local/tmp/cts/permission3/CtsCreateNotificationChannelsApp33.apk" />
+ <option name="push" value="CtsDifferentPkgNameApp.apk->/data/local/tmp/cts/permission3/CtsDifferentPkgNameApp.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
diff --git a/tests/tests/permission3/CreateNotificationChannelsApp31/src/android/permission3/cts/usepermission/CreateNotificationChannelsActivity.kt b/tests/tests/permission3/CreateNotificationChannelsApp31/src/android/permission3/cts/usepermission/CreateNotificationChannelsActivity.kt
index 457549f..9264c6c 100644
--- a/tests/tests/permission3/CreateNotificationChannelsApp31/src/android/permission3/cts/usepermission/CreateNotificationChannelsActivity.kt
+++ b/tests/tests/permission3/CreateNotificationChannelsApp31/src/android/permission3/cts/usepermission/CreateNotificationChannelsActivity.kt
@@ -31,26 +31,35 @@
const val EXTRA_REQUEST_NOTIF_PERMISSION = "extra_request_notif_permission"
const val EXTRA_REQUEST_OTHER_PERMISSIONS = "extra_request_permissions"
const val EXTRA_REQUEST_OTHER_PERMISSIONS_DELAYED = "extra_request_permissions_delayed"
-const val CHANNEL_ID = "channel_id"
+const val EXTRA_START_SECOND_ACTIVITY = "extra_start_second_activity"
+const val EXTRA_START_SECOND_APP = "extra_start_second_app"
+const val SECONDARY_APP_INTENT = "emptyactivity.main"
+const val SECONDARY_APP_PKG = "android.permission3.cts.usepermissionother"
+const val CHANNEL_ID_31 = "test_channel_id"
const val BROADCAST_ACTION = "usepermission.createchannels.BROADCAST"
const val DELAY_MS = 1000L
+const val LONG_DELAY_MS = 5000L
class CreateNotificationChannelsActivity : Activity() {
lateinit var notificationManager: NotificationManager
override fun onStart() {
val handler = Handler(Looper.getMainLooper())
notificationManager = baseContext.getSystemService(NotificationManager::class.java)!!
- if (intent.getBooleanExtra(EXTRA_CREATE_CHANNELS, false)) {
- if (notificationManager.getNotificationChannel(CHANNEL_ID) == null) {
- notificationManager.createNotificationChannel(NotificationChannel(CHANNEL_ID,
- "Foreground Services", NotificationManager.IMPORTANCE_HIGH))
- }
+ if (intent.getBooleanExtra(EXTRA_START_SECOND_APP, false)) {
+ handler.postDelayed({
+ val intent2 = Intent(SECONDARY_APP_INTENT)
+ intent2.`package` = SECONDARY_APP_PKG
+ intent2.addCategory(Intent.CATEGORY_DEFAULT)
+ handler.postDelayed({
+ createChannel()
+ }, DELAY_MS)
+ startActivity(intent2)
+ }, LONG_DELAY_MS)
+ } else if (intent.getBooleanExtra(EXTRA_CREATE_CHANNELS, false)) {
+ createChannel()
} else if (intent.getBooleanExtra(EXTRA_CREATE_CHANNELS_DELAYED, false)) {
handler.postDelayed({
- if (notificationManager.getNotificationChannel(CHANNEL_ID) == null) {
- notificationManager.createNotificationChannel(NotificationChannel(CHANNEL_ID,
- "Foreground Services", NotificationManager.IMPORTANCE_HIGH))
- }
+ createChannel()
}, DELAY_MS)
}
@@ -65,12 +74,29 @@
if (intent.getBooleanExtra(EXTRA_REQUEST_NOTIF_PERMISSION, false)) {
requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), 0)
}
+ if (intent.getBooleanExtra(EXTRA_START_SECOND_ACTIVITY, false)) {
+ handler.postDelayed({
+ val intent2 = Intent(Intent.ACTION_MAIN)
+ intent2.`package` = packageName
+ intent2.addCategory(Intent.CATEGORY_DEFAULT)
+ intent2.putExtra(EXTRA_CREATE_CHANNELS_DELAYED, true)
+ startActivity(intent2)
+ }, LONG_DELAY_MS)
+ }
+
super.onStart()
}
+ private fun createChannel() {
+ if (notificationManager.getNotificationChannel(CHANNEL_ID_31) == null) {
+ notificationManager.createNotificationChannel(NotificationChannel(CHANNEL_ID_31,
+ "Foreground Services", NotificationManager.IMPORTANCE_HIGH))
+ }
+ }
+
override fun onPause() {
if (intent.getBooleanExtra(EXTRA_DELETE_CHANNELS_ON_CLOSE, false)) {
- notificationManager.deleteNotificationChannel(CHANNEL_ID)
+ notificationManager.deleteNotificationChannel(CHANNEL_ID_31)
}
super.onPause()
}
diff --git a/tests/tests/permission3/DifferentPkgNameApp/Android.bp b/tests/tests/permission3/DifferentPkgNameApp/Android.bp
new file mode 100644
index 0000000..3db3c30
--- /dev/null
+++ b/tests/tests/permission3/DifferentPkgNameApp/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsDifferentPkgNameApp",
+ defaults: ["mts-target-sdk-version-current"],
+ min_sdk_version: "31",
+
+ static_libs: [
+ "kotlin-stdlib",
+ ],
+
+ srcs: [
+ "src/**/*.kt",
+ ],
+}
diff --git a/tests/tests/permission3/DifferentPkgNameApp/AndroidManifest.xml b/tests/tests/permission3/DifferentPkgNameApp/AndroidManifest.xml
new file mode 100644
index 0000000..77c45ba
--- /dev/null
+++ b/tests/tests/permission3/DifferentPkgNameApp/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission3.cts.usepermissionother"
+ android:versionCode="1">
+
+ <uses-sdk android:minSdkVersion="31" android:targetSdkVersion="31" />
+
+ <application android:label="EmptyActivity">
+ <activity android:name=".EmptyActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="emptyactivity.main" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/tests/permission3/DifferentPkgNameApp/src/android/permission3/cts/usepermissionother/EmptyActivity.kt b/tests/tests/permission3/DifferentPkgNameApp/src/android/permission3/cts/usepermissionother/EmptyActivity.kt
new file mode 100644
index 0000000..e60466e
--- /dev/null
+++ b/tests/tests/permission3/DifferentPkgNameApp/src/android/permission3/cts/usepermissionother/EmptyActivity.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission3.cts.usepermissionother
+
+import android.app.Activity
+
+class EmptyActivity : Activity()
\ No newline at end of file
diff --git a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
index ebdc507..c611d3890 100644
--- a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
@@ -67,7 +67,10 @@
"$APK_DIRECTORY/CtsCreateNotificationChannelsApp31.apk"
const val APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_33 =
"$APK_DIRECTORY/CtsCreateNotificationChannelsApp33.apk"
+ const val APP_APK_PATH_OTHER_APP =
+ "$APK_DIRECTORY/CtsDifferentPkgNameApp.apk"
const val APP_PACKAGE_NAME = "android.permission3.cts.usepermission"
+ const val OTHER_APP_PACKAGE_NAME = "android.permission3.cts.usepermissionother"
const val ALLOW_BUTTON =
"com.android.permissioncontroller:id/permission_allow_button"
@@ -110,7 +113,7 @@
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
android.Manifest.permission.ACCESS_MEDIA_LOCATION,
android.Manifest.permission.READ_MEDIA_AUDIO,
- android.Manifest.permission.READ_MEDIA_IMAGE,
+ android.Manifest.permission.READ_MEDIA_IMAGES,
android.Manifest.permission.READ_MEDIA_VIDEO
)
}
@@ -182,7 +185,7 @@
android.Manifest.permission.READ_MEDIA_AUDIO to
"@android:string/permgrouplab_readMediaAural",
// Visual
- android.Manifest.permission.READ_MEDIA_IMAGE to
+ android.Manifest.permission.READ_MEDIA_IMAGES to
"@android:string/permgrouplab_readMediaVisual",
android.Manifest.permission.READ_MEDIA_VIDEO to
"@android:string/permgrouplab_readMediaVisual"
@@ -322,11 +325,11 @@
block
)
- protected fun clickPermissionRequestAllowButton() {
+ protected fun clickPermissionRequestAllowButton(timeoutMillis: Long = 20000) {
if (isAutomotive) {
- click(By.text(getPermissionControllerString(ALLOW_BUTTON_TEXT)))
+ click(By.text(getPermissionControllerString(ALLOW_BUTTON_TEXT)), timeoutMillis)
} else {
- click(By.res(ALLOW_BUTTON))
+ click(By.res(ALLOW_BUTTON), timeoutMillis)
}
}
diff --git a/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt
index 2e5baf5..dc9d177 100644
--- a/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt
@@ -48,14 +48,18 @@
const val EXTRA_REQUEST_OTHER_PERMISSIONS = "extra_request_permissions"
const val EXTRA_REQUEST_NOTIF_PERMISSION = "extra_request_notif_permission"
const val EXTRA_REQUEST_PERMISSIONS_DELAYED = "extra_request_permissions_delayed"
+const val EXTRA_START_SECOND_ACTIVITY = "extra_start_second_activity"
+const val EXTRA_START_SECOND_APP = "extra_start_second_app"
const val ACTIVITY_NAME = "CreateNotificationChannelsActivity"
const val ACTIVITY_LABEL = "CreateNotif"
+const val SECOND_ACTIVITY_LABEL = "EmptyActivity"
const val ALLOW = "to send you"
const val CONTINUE_ALLOW = "to continue sending you"
const val INTENT_ACTION = "usepermission.createchannels.MAIN"
const val BROADCAST_ACTION = "usepermission.createchannels.BROADCAST"
const val NOTIFICATION_PERMISSION_ENABLED = "notification_permission_enabled"
const val DELAY_MS = 5000L
+const val DELAY_MS_SHORT = 500L
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
class NotificationPermissionTest : BaseUsePermissionTest() {
@@ -153,54 +157,48 @@
}
@Test
- fun notificationPromptDoesNotShowForLegacyAppWithNoNotificationChannels() {
+ fun notificationPromptDoesNotShowForLegacyAppWithNoNotificationChannels_onLaunch() {
installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
- setReviewRequired()
launchApp(createChannels = false)
- try {
- clickPermissionRequestAllowButton()
- Assert.fail("Expected not to find permission request dialog")
- } catch (expected: RuntimeException) {
- // Do nothing
- }
+ assertDialogNotShowing()
+ }
+ @Test
+ fun notificationPromptDoesNotShowForNonLauncherIntentCategoryLaunches_onChannelCreate() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp(launcherCategory = false)
+ assertDialogNotShowing()
}
@Test
- fun notificationPromptDoesNotShowForNonLauncherIntentCategoryLaunches() {
+ fun notificationPromptDoesNotShowForNonLauncherIntentCategoryLaunches_onLaunch() {
installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
- setReviewRequired()
// create channels, then leave the app
launchApp()
killTestApp()
launchApp(launcherCategory = false)
- try {
- clickPermissionRequestAllowButton()
- Assert.fail("Expected not to find permission request dialog")
- } catch (expected: RuntimeException) {
- // Do nothing
- }
+ assertDialogNotShowing()
}
@Test
- fun notificationPromptDoesNotShowForNonMainIntentActionLaunches() {
+ fun notificationPromptDoesNotShowForNonMainIntentActionLaunches_onLaunch() {
installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
- setReviewRequired()
// create channels, then leave the app
launchApp()
killTestApp()
launchApp(mainIntent = false)
- try {
- clickPermissionRequestAllowButton()
- Assert.fail("Expected not to find permission request dialog")
- } catch (expected: RuntimeException) {
- // Do nothing
- }
+ assertDialogNotShowing()
+ }
+
+ @Test
+ fun notificationPromptDoesNotShowForNonMainIntentActionLaunches_onChannelCreate() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp(mainIntent = false)
+ assertDialogNotShowing()
}
@Test
fun notificationPromptShowsIfActivityOptionSet() {
installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
- setReviewRequired()
// create channels, then leave the app
launchApp()
killTestApp()
@@ -209,6 +207,55 @@
}
@Test
+ fun notificationPromptShownForSubsequentStartsIfTaskStartWasLauncher() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp(startSecondActivity = true)
+ pressBack()
+ assertDialogNotShowing(DELAY_MS_SHORT)
+ Thread.sleep(DELAY_MS)
+ clickPermissionRequestAllowButton()
+ }
+
+ @Test
+ fun notificationPromptNotShownForSubsequentStartsIfTaskStartWasNotLauncher() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp(mainIntent = false, startSecondActivity = true)
+ Thread.sleep(DELAY_MS)
+ assertDialogNotShowing()
+ }
+
+ @Test
+ fun notificationPromptShownForChannelCreateInSecondActivityIfTaskStartWasLauncher() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp(startSecondActivity = true, createChannels = false)
+ Thread.sleep(DELAY_MS)
+ clickPermissionRequestAllowButton()
+ }
+
+ @Test
+ fun notificationPromptNotShownForChannelCreateInSecondActivityIfTaskStartWasntLauncher() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ launchApp(mainIntent = false, startSecondActivity = true, createChannels = false)
+ Thread.sleep(DELAY_MS)
+ assertDialogNotShowing()
+ }
+
+ @Test
+ fun notificationPromptNotShownForSubsequentStartsIfSubsequentIsDifferentPkg() {
+ installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
+ installPackage(APP_APK_PATH_OTHER_APP, expectSuccess = true)
+ // perform a launcher start, then start a secondary app
+ launchApp(startSecondaryAppAndCreateChannelsAfterSecondStart = true)
+ Thread.sleep(DELAY_MS)
+ try {
+ waitFindObject(By.textContains(SECOND_ACTIVITY_LABEL))
+ assertDialogNotShowing()
+ } finally {
+ uninstallPackage(OTHER_APP_PACKAGE_NAME)
+ }
+ }
+
+ @Test
fun reviewRequiredNotClearedOnNonLauncherIntentCategoryLaunches() {
installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_33, expectSuccess = true)
setReviewRequired()
@@ -389,7 +436,9 @@
requestPermissionsDelayed: Boolean = false,
launcherCategory: Boolean = true,
mainIntent: Boolean = true,
- isEligibleForPromptOption: Boolean = false
+ isEligibleForPromptOption: Boolean = false,
+ startSecondActivity: Boolean = false,
+ startSecondaryAppAndCreateChannelsAfterSecondStart: Boolean = false
) {
val intent = if (mainIntent && launcherCategory) {
packageManager.getLaunchIntentForPackage(APP_PACKAGE_NAME)!!
@@ -410,6 +459,8 @@
intent.putExtra(EXTRA_REQUEST_PERMISSIONS_DELAYED, requestPermissionsDelayed)
}
intent.putExtra(EXTRA_REQUEST_NOTIF_PERMISSION, requestNotificationPermission)
+ intent.putExtra(EXTRA_START_SECOND_ACTIVITY, startSecondActivity)
+ intent.putExtra(EXTRA_START_SECOND_APP, startSecondaryAppAndCreateChannelsAfterSecondStart)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
val options = ActivityOptions.makeBasic()
@@ -429,4 +480,13 @@
}
waitForIdle()
}
+
+ private fun assertDialogNotShowing(timeoutMillis: Long = DELAY_MS) {
+ try {
+ clickPermissionRequestAllowButton(timeoutMillis)
+ Assert.fail("Expected not to find permission request dialog")
+ } catch (expected: RuntimeException) {
+ // Do nothing
+ }
+ }
}
\ No newline at end of file
diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt
index ae71cd9..5355fdc 100644
--- a/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt
@@ -108,6 +108,7 @@
}
@Test
+ @Ignore
fun testToggleSystemApps() {
// I had some hard time mocking a system app.
// Hence here I am only testing if the toggle is there.
@@ -158,6 +159,7 @@
}
@Test
+ @Ignore
fun testToggleFrom24HoursTo7DaysInTimeline() {
// Auto doesn't support the 7 day view
assumeFalse(isAutomotive)
diff --git a/tests/tests/permission3/src/android/permission3/cts/SensorBlockedBannerTest.kt b/tests/tests/permission3/src/android/permission3/cts/SensorBlockedBannerTest.kt
index 72f1de1..d39fb9c 100644
--- a/tests/tests/permission3/src/android/permission3/cts/SensorBlockedBannerTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/SensorBlockedBannerTest.kt
@@ -33,7 +33,6 @@
import org.junit.After
import org.junit.Assume
import org.junit.Before
-import org.junit.Ignore
import org.junit.Test
/**
@@ -119,7 +118,6 @@
}
@Test
- @Ignore
fun testLocationCardDisplayed() {
runSensorTest(LOCATION)
}
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStoreUtils.java b/tests/tests/provider/src/android/provider/cts/media/MediaStoreUtils.java
index 49a33ad..da7f0fb 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStoreUtils.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStoreUtils.java
@@ -27,16 +27,16 @@
import android.provider.MediaStore.MediaColumns;
import android.text.format.DateUtils;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.filters.SdkSuppress;
+
import org.junit.Test;
import java.io.FileNotFoundException;
import java.io.OutputStream;
import java.util.Objects;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.test.filters.SdkSuppress;
-
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
public class MediaStoreUtils {
@Test
@@ -118,6 +118,10 @@
}
}
+ public void setIsFavorite(@Nullable Boolean isFavorite) {
+ this.insertValues.put(MediaColumns.IS_FAVORITE, isFavorite);
+ }
+
/**
* Optionally set the Uri from where the file has been downloaded. This is used
* for files being added to {@link Downloads} table.
diff --git a/tests/tests/safetycenter/Android.bp b/tests/tests/safetycenter/Android.bp
deleted file mode 100644
index f3b9716..0000000
--- a/tests/tests/safetycenter/Android.bp
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-android_test {
- name: "CtsSafetyCenterTestCases",
- defaults: ["mts-target-sdk-version-current"],
- sdk_version: "test_current",
- min_sdk_version: "30",
- srcs: [
- "src/**/*.kt",
- ],
- static_libs: [
- "androidx.test.core",
- "androidx.test.ext.junit",
- "androidx.test.rules",
- "androidx.test.runner",
- "androidx.test.uiautomator_uiautomator",
- "compatibility-device-util-axt",
- "ctstestrunner-axt",
- "kotlin-stdlib",
- "kotlinx-coroutines-android",
- "kotlin-test",
- "modules-utils-build_system",
- "safety-center-resources-lib",
- "truth-prebuilt",
- ],
- test_suites: [
- "cts",
- "general-tests",
- "mts-permission",
- ],
-}
diff --git a/tests/tests/safetycenter/AndroidManifest.xml b/tests/tests/safetycenter/AndroidManifest.xml
deleted file mode 100644
index cfa22f7..0000000
--- a/tests/tests/safetycenter/AndroidManifest.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.safetycenter.cts">
-
- <application>
- <uses-library android:name="android.test.runner"/>
-
- <receiver android:name=".SafetySourceBroadcastReceiver" android:exported="false">
- <intent-filter>
- <action android:name="android.safetycenter.action.REFRESH_SAFETY_SOURCES"/>
- </intent-filter>
- </receiver>
- </application>
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:label="CTS tests for SafetyCenter"
- android:targetPackage="android.safetycenter.cts">
- <meta-data android:name="listener"
- android:value="com.android.cts.runner.CtsTestRunListener"/>
- </instrumentation>
-
- <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
-
- <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
-</manifest>
diff --git a/tests/tests/safetycenter/AndroidTest.xml b/tests/tests/safetycenter/AndroidTest.xml
deleted file mode 100644
index fc74c4a..0000000
--- a/tests/tests/safetycenter/AndroidTest.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<configuration description="Config for CTS SafetyCenter test cases">
-
- <!-- TODO(b/207111503): Use Sdk33ModuleController once available, and remove @SdkSuppress
- annotations -->
- <object
- class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController"
- type="module_controller"/>
-
- <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"/>
-
- <option name="test-suite-tag" value="cts"/>
-
- <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
- <option name="force-skip-system-props"
- value="true"/> <!-- avoid restarting device -->
- </target_preparer>
-
- <target_preparer
- class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true"/>
- <option name="test-file-name" value="CtsSafetyCenterTestCases.apk"/>
- </target_preparer>
-
- <test class="com.android.tradefed.testtype.AndroidJUnitTest">
- <option name="package" value="android.safetycenter.cts"/>
- <option name="runtime-hint" value="5m"/>
- </test>
-</configuration>
diff --git a/tests/tests/safetycenter/OWNERS b/tests/tests/safetycenter/OWNERS
deleted file mode 100644
index 026d342..0000000
--- a/tests/tests/safetycenter/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 1026964
-
-include platform/frameworks/base:/core/java/android/permission/OWNERS
diff --git a/tests/tests/safetycenter/res/values/strings.xml b/tests/tests/safetycenter/res/values/strings.xml
deleted file mode 100644
index 8ba7f04..0000000
--- a/tests/tests/safetycenter/res/values/strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Test reference -->
- <string name="reference" translatable="false">Reference</string>
-</resources>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_all_disabled_no_work.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_all_disabled_no_work.xml
deleted file mode 100644
index b2594c7..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_all_disabled_no_work.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="all_profiles"
- initialDisplayState="disabled"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_all_no_work.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_all_no_work.xml
deleted file mode 100644
index e582e04..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_all_no_work.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="all_profiles"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_disabled_no_summary.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_disabled_no_summary.xml
deleted file mode 100644
index 6d06599..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_disabled_no_summary.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- title="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"
- initialDisplayState="disabled"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_disabled_no_title.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_disabled_no_title.xml
deleted file mode 100644
index 6d53576..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_disabled_no_title.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"
- initialDisplayState="disabled"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_duplicate_key.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_duplicate_key.xml
deleted file mode 100644
index be7114d..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_duplicate_key.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id1"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- <safety-sources-group
- id="id2"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_hidden_with_intent.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_hidden_with_intent.xml
deleted file mode 100644
index b30a6d9..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_hidden_with_intent.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- intentAction="intent"
- profile="primary_profile_only"
- initialDisplayState="hidden"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_hidden_with_summary.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_hidden_with_summary.xml
deleted file mode 100644
index c0fd181..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_hidden_with_summary.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- summary="@string/reference"
- profile="primary_profile_only"
- initialDisplayState="hidden"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_hidden_with_title.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_hidden_with_title.xml
deleted file mode 100644
index 190fcdc..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_hidden_with_title.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- title="@string/reference"
- profile="primary_profile_only"
- initialDisplayState="hidden"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_invalid_display.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_invalid_display.xml
deleted file mode 100644
index 4c1d00a..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_invalid_display.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"
- initialDisplayState="invalid"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_invalid_profile.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_invalid_profile.xml
deleted file mode 100644
index 303415b..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_invalid_profile.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="invalid"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_id.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_id.xml
deleted file mode 100644
index 8ace4ea..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_id.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- packageName="package"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_intent.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_intent.xml
deleted file mode 100644
index 6119e4a..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_intent.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- title="@string/reference"
- summary="@string/reference"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_package.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_package.xml
deleted file mode 100644
index 2b40602..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_package.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_profile.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_profile.xml
deleted file mode 100644
index f54d940..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_profile.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_summary.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_summary.xml
deleted file mode 100644
index 0683f16..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_summary.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- title="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_title.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_title.xml
deleted file mode 100644
index 84f90e5..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_no_title.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_primary_hidden_with_work.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_primary_hidden_with_work.xml
deleted file mode 100644
index ad7add5..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_primary_hidden_with_work.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- titleForWork="@string/reference"
- profile="primary_profile_only"
- initialDisplayState="hidden"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_primary_with_work.xml b/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_primary_with_work.xml
deleted file mode 100644
index 3ecf802..0000000
--- a/tests/tests/safetycenter/res/xml/config_dynamic_safety_source_primary_with_work.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- title="@string/reference"
- titleForWork="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_duplicate_key.xml b/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_duplicate_key.xml
deleted file mode 100644
index 9c00d57..0000000
--- a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_duplicate_key.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id">
- <issue-only-safety-source
- id="id"
- packageName="package"
- profile="primary_profile_only"/>
- <issue-only-safety-source
- id="id"
- packageName="package"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_invalid_profile.xml b/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_invalid_profile.xml
deleted file mode 100644
index dd85d55..0000000
--- a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_invalid_profile.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id">
- <issue-only-safety-source
- id="id"
- packageName="package"
- profile="invalid"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_no_id.xml b/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_no_id.xml
deleted file mode 100644
index d57db8e..0000000
--- a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_no_id.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id">
- <issue-only-safety-source
- packageName="package"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_no_package.xml b/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_no_package.xml
deleted file mode 100644
index d68b557..0000000
--- a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_no_package.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id">
- <issue-only-safety-source
- id="id"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_no_profile.xml b/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_no_profile.xml
deleted file mode 100644
index 7e7b6ef..0000000
--- a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_no_profile.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id">
- <issue-only-safety-source
- id="id"
- packageName="package"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_display.xml b/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_display.xml
deleted file mode 100644
index 1fab839..0000000
--- a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_display.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id">
- <issue-only-safety-source
- id="id"
- packageName="package"
- profile="primary_profile_only"
- initialDisplayState="disabled"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_intent.xml b/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_intent.xml
deleted file mode 100644
index 9a7fa6b..0000000
--- a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_intent.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id">
- <issue-only-safety-source
- id="id"
- packageName="package"
- profile="primary_profile_only"
- intentAction="intent"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_search.xml b/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_search.xml
deleted file mode 100644
index b065a38..0000000
--- a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_search.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id">
- <issue-only-safety-source
- id="id"
- packageName="package"
- profile="primary_profile_only"
- searchTerms="@string/reference"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_summary.xml b/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_summary.xml
deleted file mode 100644
index 7d01001..0000000
--- a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_summary.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id">
- <issue-only-safety-source
- id="id"
- packageName="package"
- profile="primary_profile_only"
- summary="@string/reference"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_title.xml b/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_title.xml
deleted file mode 100644
index 3b46eea..0000000
--- a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_title.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id">
- <issue-only-safety-source
- id="id"
- packageName="package"
- profile="primary_profile_only"
- title="@string/reference"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_work.xml b/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_work.xml
deleted file mode 100644
index e501490..0000000
--- a/tests/tests/safetycenter/res/xml/config_issue_only_safety_source_with_work.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id">
- <issue-only-safety-source
- id="id"
- packageName="package"
- profile="all_profiles"
- titleForWork="@string/reference"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_mixed_safety_source_duplicate_key.xml b/tests/tests/safetycenter/res/xml/config_mixed_safety_source_duplicate_key.xml
deleted file mode 100644
index e939a9c..0000000
--- a/tests/tests/safetycenter/res/xml/config_mixed_safety_source_duplicate_key.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id1"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- <safety-sources-group
- id="id2"
- title="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_reference_invalid.xml b/tests/tests/safetycenter/res/xml/config_reference_invalid.xml
deleted file mode 100644
index 7431729..0000000
--- a/tests/tests/safetycenter/res/xml/config_reference_invalid.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="title"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="1"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_safety_center_config_missing.xml b/tests/tests/safetycenter/res/xml/config_safety_center_config_missing.xml
deleted file mode 100644
index 4757916..0000000
--- a/tests/tests/safetycenter/res/xml/config_safety_center_config_missing.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<other-root>
-</other-root>
diff --git a/tests/tests/safetycenter/res/xml/config_safety_sources_config_empty.xml b/tests/tests/safetycenter/res/xml/config_safety_sources_config_empty.xml
deleted file mode 100644
index b26ffc0..0000000
--- a/tests/tests/safetycenter/res/xml/config_safety_sources_config_empty.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_safety_sources_config_missing.xml b/tests/tests/safetycenter/res/xml/config_safety_sources_config_missing.xml
deleted file mode 100644
index 1254575..0000000
--- a/tests/tests/safetycenter/res/xml/config_safety_sources_config_missing.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<safety-center-config>
- <other-internal-config>
- </other-internal-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_safety_sources_group_duplicate_id.xml b/tests/tests/safetycenter/res/xml/config_safety_sources_group_duplicate_id.xml
deleted file mode 100644
index 0ce7337..0000000
--- a/tests/tests/safetycenter/res/xml/config_safety_sources_group_duplicate_id.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id1"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id2"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_safety_sources_group_empty.xml b/tests/tests/safetycenter/res/xml/config_safety_sources_group_empty.xml
deleted file mode 100644
index a395152..0000000
--- a/tests/tests/safetycenter/res/xml/config_safety_sources_group_empty.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_safety_sources_group_invalid_icon.xml b/tests/tests/safetycenter/res/xml/config_safety_sources_group_invalid_icon.xml
deleted file mode 100644
index 42b4c47..0000000
--- a/tests/tests/safetycenter/res/xml/config_safety_sources_group_invalid_icon.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference"
- statelessIconType="invalid">
- <static-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_safety_sources_group_no_id.xml b/tests/tests/safetycenter/res/xml/config_safety_sources_group_no_id.xml
deleted file mode 100644
index eaee673..0000000
--- a/tests/tests/safetycenter/res/xml/config_safety_sources_group_no_id.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_safety_sources_group_no_title.xml b/tests/tests/safetycenter/res/xml/config_safety_sources_group_no_title.xml
deleted file mode 100644
index de3ce82..0000000
--- a/tests/tests/safetycenter/res/xml/config_safety_sources_group_no_title.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- summary="@string/reference">
- <dynamic-safety-source
- id="id"
- packageName="package"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_static_safety_source_duplicate_key.xml b/tests/tests/safetycenter/res/xml/config_static_safety_source_duplicate_key.xml
deleted file mode 100644
index 4fe5e1e..0000000
--- a/tests/tests/safetycenter/res/xml/config_static_safety_source_duplicate_key.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id1"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- <safety-sources-group
- id="id2"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_static_safety_source_invalid_profile.xml b/tests/tests/safetycenter/res/xml/config_static_safety_source_invalid_profile.xml
deleted file mode 100644
index 7c135e7..0000000
--- a/tests/tests/safetycenter/res/xml/config_static_safety_source_invalid_profile.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="invalid"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_static_safety_source_no_id.xml b/tests/tests/safetycenter/res/xml/config_static_safety_source_no_id.xml
deleted file mode 100644
index 7b91934..0000000
--- a/tests/tests/safetycenter/res/xml/config_static_safety_source_no_id.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_static_safety_source_no_intent.xml b/tests/tests/safetycenter/res/xml/config_static_safety_source_no_intent.xml
deleted file mode 100644
index 9e97efb..0000000
--- a/tests/tests/safetycenter/res/xml/config_static_safety_source_no_intent.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_static_safety_source_no_profile.xml b/tests/tests/safetycenter/res/xml/config_static_safety_source_no_profile.xml
deleted file mode 100644
index 32d23c7..0000000
--- a/tests/tests/safetycenter/res/xml/config_static_safety_source_no_profile.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_static_safety_source_no_summary.xml b/tests/tests/safetycenter/res/xml/config_static_safety_source_no_summary.xml
deleted file mode 100644
index fa92f0bd..0000000
--- a/tests/tests/safetycenter/res/xml/config_static_safety_source_no_summary.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_static_safety_source_no_title.xml b/tests/tests/safetycenter/res/xml/config_static_safety_source_no_title.xml
deleted file mode 100644
index 654a486..0000000
--- a/tests/tests/safetycenter/res/xml/config_static_safety_source_no_title.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_static_safety_source_with_broadcast.xml b/tests/tests/safetycenter/res/xml/config_static_safety_source_with_broadcast.xml
deleted file mode 100644
index 090bd57..0000000
--- a/tests/tests/safetycenter/res/xml/config_static_safety_source_with_broadcast.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"
- broadcastReceiverClassName="broadcast"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_static_safety_source_with_display.xml b/tests/tests/safetycenter/res/xml/config_static_safety_source_with_display.xml
deleted file mode 100644
index 69c9ca2..0000000
--- a/tests/tests/safetycenter/res/xml/config_static_safety_source_with_display.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"
- initialDisplayState="disabled"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_static_safety_source_with_logging.xml b/tests/tests/safetycenter/res/xml/config_static_safety_source_with_logging.xml
deleted file mode 100644
index 090554b..0000000
--- a/tests/tests/safetycenter/res/xml/config_static_safety_source_with_logging.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"
- loggingAllowed="false"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_static_safety_source_with_package.xml b/tests/tests/safetycenter/res/xml/config_static_safety_source_with_package.xml
deleted file mode 100644
index 2a982b4..0000000
--- a/tests/tests/safetycenter/res/xml/config_static_safety_source_with_package.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"
- packageName="package"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_static_safety_source_with_primary_and_work.xml b/tests/tests/safetycenter/res/xml/config_static_safety_source_with_primary_and_work.xml
deleted file mode 100644
index 296e2bc..0000000
--- a/tests/tests/safetycenter/res/xml/config_static_safety_source_with_primary_and_work.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- titleForWork="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_static_safety_source_with_refresh.xml b/tests/tests/safetycenter/res/xml/config_static_safety_source_with_refresh.xml
deleted file mode 100644
index caaeee6..0000000
--- a/tests/tests/safetycenter/res/xml/config_static_safety_source_with_refresh.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"
- refreshOnPageOpenAllowed="true"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_static_safety_source_with_severity.xml b/tests/tests/safetycenter/res/xml/config_static_safety_source_with_severity.xml
deleted file mode 100644
index a9f5d9b..0000000
--- a/tests/tests/safetycenter/res/xml/config_static_safety_source_with_severity.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="id"
- title="@string/reference"
- summary="@string/reference">
- <static-safety-source
- id="id"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"
- maxSeverityLevel="300"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/res/xml/config_valid.xml b/tests/tests/safetycenter/res/xml/config_valid.xml
deleted file mode 100644
index e2f9e77..0000000
--- a/tests/tests/safetycenter/res/xml/config_valid.xml
+++ /dev/null
@@ -1,97 +0,0 @@
-<safety-center-config>
- <safety-sources-config>
- <safety-sources-group
- id="dynamic"
- title="@string/reference"
- summary="@string/reference"
- statelessIconType="privacy">
- <dynamic-safety-source
- id="dynamic_barebone"
- packageName="package"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- <dynamic-safety-source
- id="dynamic_all_optional"
- packageName="package"
- title="@string/reference"
- titleForWork="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="all_profiles"
- initialDisplayState="disabled"
- maxSeverityLevel="300"
- searchTerms="@string/reference"
- broadcastReceiverClassName="broadcast"
- loggingAllowed="false"
- refreshOnPageOpenAllowed="true"/>
- <dynamic-safety-source
- id="dynamic_disabled"
- packageName="package"
- title="@string/reference"
- summary="@string/reference"
- profile="primary_profile_only"
- initialDisplayState="disabled"/>
- <dynamic-safety-source
- id="dynamic_hidden"
- packageName="package"
- profile="all_profiles"
- initialDisplayState="hidden"/>
- </safety-sources-group>
- <safety-sources-group
- id="static"
- title="@string/reference">
- <static-safety-source
- id="static_barebone"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- <static-safety-source
- id="static_all_optional"
- title="@string/reference"
- titleForWork="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="all_profiles"
- searchTerms="@string/reference"/>
- </safety-sources-group>
- <safety-sources-group
- id="issue_only">
- <issue-only-safety-source
- id="issue_only_barebone"
- packageName="package"
- profile="primary_profile_only"/>
- <issue-only-safety-source
- id="issue_only_all_optional"
- packageName="package"
- profile="all_profiles"
- maxSeverityLevel="300"
- broadcastReceiverClassName="broadcast"
- loggingAllowed="false"
- refreshOnPageOpenAllowed="true"/>
- </safety-sources-group>
- <safety-sources-group
- id="mixed"
- title="@string/reference">
- <dynamic-safety-source
- id="mixed_dynamic_barebone"
- packageName="package"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- <issue-only-safety-source
- id="mixed_issue_only_barebone"
- packageName="package"
- profile="primary_profile_only"/>
- <static-safety-source
- id="mixed_static_barebone"
- title="@string/reference"
- summary="@string/reference"
- intentAction="intent"
- profile="primary_profile_only"/>
- </safety-sources-group>
- </safety-sources-config>
-</safety-center-config>
diff --git a/tests/tests/safetycenter/src/android/safetycenter/config/cts/ParserConfigInvalidTest.kt b/tests/tests/safetycenter/src/android/safetycenter/config/cts/ParserConfigInvalidTest.kt
deleted file mode 100644
index d276865..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/config/cts/ParserConfigInvalidTest.kt
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.config.cts
-
-import android.content.Context
-import android.safetycenter.config.ParseException
-import android.safetycenter.config.SafetyCenterConfig
-import android.safetycenter.cts.R
-import androidx.test.core.app.ApplicationProvider.getApplicationContext
-import com.google.common.truth.Truth.assertThat
-import org.junit.Assert.assertThrows
-import org.junit.Test
-import org.junit.runners.Parameterized
-import org.junit.runner.RunWith
-
-@RunWith(Parameterized::class)
-class ParserConfigInvalidTest {
- private val context: Context = getApplicationContext()
-
- data class Params(
- private val testName: String,
- val configResourceId: Int,
- val errorMessage: String,
- val causeErrorMessage: String?
- ) {
- override fun toString() = testName
- }
-
- @Parameterized.Parameter
- lateinit var params: Params
-
- @Test
- fun invalidConfig_throws() {
- val parser = context.resources.getXml(params.configResourceId)
- val thrown = assertThrows(ParseException::class.java) {
- SafetyCenterConfig.fromXml(parser)
- }
- assertThat(thrown).hasMessageThat().isEqualTo(params.errorMessage)
- if (params.causeErrorMessage != null) {
- assertThat(thrown.cause).hasMessageThat().isEqualTo(params.causeErrorMessage)
- }
- }
-
- companion object {
- @JvmStatic
- @Parameterized.Parameters(name = "{0}")
- fun parameters() = arrayOf(
- Params(
- "ConfigDynamicSafetySourceAllDisabledNoWork",
- R.xml.config_dynamic_safety_source_all_disabled_no_work,
- "Element dynamic-safety-source invalid",
- "Required attribute titleForWork missing"
- ),
- Params(
- "ConfigDynamicSafetySourceAllNoWork",
- R.xml.config_dynamic_safety_source_all_no_work,
- "Element dynamic-safety-source invalid",
- "Required attribute titleForWork missing"
- ),
- Params(
- "ConfigDynamicSafetySourceDisabledNoSummary",
- R.xml.config_dynamic_safety_source_disabled_no_summary,
- "Element dynamic-safety-source invalid",
- "Required attribute summary missing"
- ),
- Params(
- "ConfigDynamicSafetySourceDisabledNoTitle",
- R.xml.config_dynamic_safety_source_disabled_no_title,
- "Element dynamic-safety-source invalid",
- "Required attribute title missing"
- ),
- Params(
- "ConfigDynamicSafetySourceDuplicateKey",
- R.xml.config_dynamic_safety_source_duplicate_key,
- "Element safety-sources-config invalid",
- "Duplicate id id among safety sources"
- ),
- Params(
- "ConfigDynamicSafetySourceHiddenWithIntent",
- R.xml.config_dynamic_safety_source_hidden_with_intent,
- "Element dynamic-safety-source invalid",
- "Prohibited attribute intentAction present"
- ),
- Params(
- "ConfigDynamicSafetySourceHiddenWithSummary",
- R.xml.config_dynamic_safety_source_hidden_with_summary,
- "Element dynamic-safety-source invalid",
- "Prohibited attribute summary present"
- ),
- Params(
- "ConfigDynamicSafetySourceHiddenWithTitle",
- R.xml.config_dynamic_safety_source_hidden_with_title,
- "Element dynamic-safety-source invalid",
- "Prohibited attribute title present"
- ),
- Params(
- "ConfigDynamicSafetySourceInvalidDisplay",
- R.xml.config_dynamic_safety_source_invalid_display,
- "Attribute dynamic-safety-source.initialDisplayState invalid",
- null
- ),
- Params(
- "ConfigDynamicSafetySourceInvalidProfile",
- R.xml.config_dynamic_safety_source_invalid_profile,
- "Attribute dynamic-safety-source.profile invalid",
- null
- ),
- Params(
- "ConfigDynamicSafetySourceNoId",
- R.xml.config_dynamic_safety_source_no_id,
- "Element dynamic-safety-source invalid",
- "Required attribute id missing"
- ),
- Params(
- "ConfigDynamicSafetySourceNoIntent",
- R.xml.config_dynamic_safety_source_no_intent,
- "Element dynamic-safety-source invalid",
- "Required attribute intentAction missing"
- ),
- Params(
- "ConfigDynamicSafetySourceNoPackage",
- R.xml.config_dynamic_safety_source_no_package,
- "Element dynamic-safety-source invalid",
- "Required attribute packageName missing"
- ),
- Params(
- "ConfigDynamicSafetySourceNoProfile",
- R.xml.config_dynamic_safety_source_no_profile,
- "Element dynamic-safety-source invalid",
- "Required attribute profile missing"
- ),
- Params(
- "ConfigDynamicSafetySourceNoSummary",
- R.xml.config_dynamic_safety_source_no_summary,
- "Element dynamic-safety-source invalid",
- "Required attribute summary missing"
- ),
- Params(
- "ConfigDynamicSafetySourceNoTitle",
- R.xml.config_dynamic_safety_source_no_title,
- "Element dynamic-safety-source invalid",
- "Required attribute title missing"
- ),
- Params(
- "ConfigDynamicSafetySourcePrimaryHiddenWithWork",
- R.xml.config_dynamic_safety_source_primary_hidden_with_work,
- "Element dynamic-safety-source invalid",
- "Prohibited attribute titleForWork present"
- ),
- Params(
- "ConfigDynamicSafetySourcePrimaryWithWork",
- R.xml.config_dynamic_safety_source_primary_with_work,
- "Element dynamic-safety-source invalid",
- "Prohibited attribute titleForWork present"
- ),
- Params(
- "ConfigIssueOnlySafetySourceDuplicateKey",
- R.xml.config_issue_only_safety_source_duplicate_key,
- "Element safety-sources-config invalid",
- "Duplicate id id among safety sources"
- ),
- Params(
- "ConfigIssueOnlySafetySourceInvalidProfile",
- R.xml.config_issue_only_safety_source_invalid_profile,
- "Attribute issue-only-safety-source.profile invalid",
- null
- ),
- Params(
- "ConfigIssueOnlySafetySourceNoId",
- R.xml.config_issue_only_safety_source_no_id,
- "Element issue-only-safety-source invalid",
- "Required attribute id missing"
- ),
- Params(
- "ConfigIssueOnlySafetySourceNoPackage",
- R.xml.config_issue_only_safety_source_no_package,
- "Element issue-only-safety-source invalid",
- "Required attribute packageName missing"
- ),
- Params(
- "ConfigIssueOnlySafetySourceNoProfile",
- R.xml.config_issue_only_safety_source_no_profile,
- "Element issue-only-safety-source invalid",
- "Required attribute profile missing"
- ),
- Params(
- "ConfigIssueOnlySafetySourceWithDisplay",
- R.xml.config_issue_only_safety_source_with_display,
- "Element issue-only-safety-source invalid",
- "Prohibited attribute initialDisplayState present"
- ),
- Params(
- "ConfigIssueOnlySafetySourceWithIntent",
- R.xml.config_issue_only_safety_source_with_intent,
- "Element issue-only-safety-source invalid",
- "Prohibited attribute intentAction present"
- ),
- Params(
- "ConfigIssueOnlySafetySourceWithSearch",
- R.xml.config_issue_only_safety_source_with_search,
- "Element issue-only-safety-source invalid",
- "Prohibited attribute searchTerms present"
- ),
- Params(
- "ConfigIssueOnlySafetySourceWithSummary",
- R.xml.config_issue_only_safety_source_with_summary,
- "Element issue-only-safety-source invalid",
- "Prohibited attribute summary present"
- ),
- Params(
- "ConfigIssueOnlySafetySourceWithTitle",
- R.xml.config_issue_only_safety_source_with_title,
- "Element issue-only-safety-source invalid",
- "Prohibited attribute title present"
- ),
- Params(
- "ConfigIssueOnlySafetySourceWithWork",
- R.xml.config_issue_only_safety_source_with_work,
- "Element issue-only-safety-source invalid",
- "Prohibited attribute titleForWork present"
- ),
- Params(
- "ConfigMixedSafetySourceDuplicateKey",
- R.xml.config_mixed_safety_source_duplicate_key,
- "Element safety-sources-config invalid",
- "Duplicate id id among safety sources"
- ),
- Params(
- "ConfigReferenceInvalid",
- R.xml.config_reference_invalid,
- "Reference title in safety-sources-group.title missing or invalid",
- null
- ),
- Params(
- "ConfigSafetyCenterConfigMissing",
- R.xml.config_safety_center_config_missing,
- "Element safety-center-config missing",
- null
- ),
- Params(
- "ConfigSafetySourcesConfigEmpty",
- R.xml.config_safety_sources_config_empty,
- "Element safety-sources-config invalid",
- "No safety sources groups present"
- ),
- Params(
- "ConfigSafetySourcesConfigMissing",
- R.xml.config_safety_sources_config_missing,
- "Element safety-sources-config missing",
- null
- ),
- Params(
- "ConfigSafetySourcesGroupDuplicateId",
- R.xml.config_safety_sources_group_duplicate_id,
- "Element safety-sources-config invalid",
- "Duplicate id id among safety sources groups"
- ),
- Params(
- "ConfigSafetySourcesGroupEmpty",
- R.xml.config_safety_sources_group_empty,
- "Element safety-sources-group invalid",
- "Safety sources group empty"
- ),
- Params(
- "ConfigSafetySourcesGroupInvalidIcon",
- R.xml.config_safety_sources_group_invalid_icon,
- "Attribute safety-sources-group.statelessIconType invalid",
- null
- ),
- Params(
- "ConfigSafetySourcesGroupNoId",
- R.xml.config_safety_sources_group_no_id,
- "Element safety-sources-group invalid",
- "Required attribute id missing"
- ),
- Params(
- "ConfigSafetySourcesGroupNoTitle",
- R.xml.config_safety_sources_group_no_title,
- "Element safety-sources-group invalid",
- "Required attribute title missing"
- ),
- Params(
- "ConfigStaticSafetySourceDuplicateKey",
- R.xml.config_static_safety_source_duplicate_key,
- "Element safety-sources-config invalid",
- "Duplicate id id among safety sources"
- ),
- Params(
- "ConfigStaticSafetySourceInvalidProfile",
- R.xml.config_static_safety_source_invalid_profile,
- "Attribute static-safety-source.profile invalid",
- null
- ),
- Params(
- "ConfigStaticSafetySourceNoId",
- R.xml.config_static_safety_source_no_id,
- "Element static-safety-source invalid",
- "Required attribute id missing"
- ),
- Params(
- "ConfigStaticSafetySourceNoIntent",
- R.xml.config_static_safety_source_no_intent,
- "Element static-safety-source invalid",
- "Required attribute intentAction missing"
- ),
- Params(
- "ConfigStaticSafetySourceNoProfile",
- R.xml.config_static_safety_source_no_profile,
- "Element static-safety-source invalid",
- "Required attribute profile missing"
- ),
- Params(
- "ConfigStaticSafetySourceNoSummary",
- R.xml.config_static_safety_source_no_summary,
- "Element static-safety-source invalid",
- "Required attribute summary missing"
- ),
- Params(
- "ConfigStaticSafetySourceNoTitle",
- R.xml.config_static_safety_source_no_title,
- "Element static-safety-source invalid",
- "Required attribute title missing"
- ),
- Params(
- "ConfigStaticSafetySourceWithBroadcast",
- R.xml.config_static_safety_source_with_broadcast,
- "Element static-safety-source invalid",
- "Prohibited attribute broadcastReceiverClassName present"
- ),
- Params(
- "ConfigStaticSafetySourceWithDisplay",
- R.xml.config_static_safety_source_with_display,
- "Element static-safety-source invalid",
- "Prohibited attribute initialDisplayState present"
- ),
- Params(
- "ConfigStaticSafetySourceWithLogging",
- R.xml.config_static_safety_source_with_logging,
- "Element static-safety-source invalid",
- "Prohibited attribute loggingAllowed present"
- ),
- Params(
- "ConfigStaticSafetySourceWithPackage",
- R.xml.config_static_safety_source_with_package,
- "Element static-safety-source invalid",
- "Prohibited attribute packageName present"
- ),
- Params(
- "ConfigStaticSafetySourceWithPrimaryAndWork",
- R.xml.config_static_safety_source_with_primary_and_work,
- "Element static-safety-source invalid",
- "Prohibited attribute titleForWork present"
- ),
- Params(
- "ConfigStaticSafetySourceWithRefresh",
- R.xml.config_static_safety_source_with_refresh,
- "Element static-safety-source invalid",
- "Prohibited attribute refreshOnPageOpenAllowed present"
- ),
- Params(
- "ConfigStaticSafetySourceWithSeverity",
- R.xml.config_static_safety_source_with_severity,
- "Element static-safety-source invalid",
- "Prohibited attribute maxSeverityLevel present"
- )
- )
- }
-}
diff --git a/tests/tests/safetycenter/src/android/safetycenter/config/cts/ParserConfigValidTest.kt b/tests/tests/safetycenter/src/android/safetycenter/config/cts/ParserConfigValidTest.kt
deleted file mode 100644
index 9190b6d..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/config/cts/ParserConfigValidTest.kt
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.config.cts
-
-import android.content.Context
-import android.safetycenter.config.SafetyCenterConfig
-import android.safetycenter.config.SafetySource
-import android.safetycenter.config.SafetySourcesGroup
-import android.safetycenter.cts.R
-import androidx.test.core.app.ApplicationProvider.getApplicationContext
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class ParserConfigValidTest {
- private val context: Context = getApplicationContext()
-
- @Test
- fun validConfig_matchesExpected() {
- val parser = context.resources.getXml(R.xml.config_valid)
- val expected = SafetyCenterConfig.Builder()
- .addSafetySourcesGroup(SafetySourcesGroup.Builder()
- .setId("dynamic")
- .setTitleResId(R.string.reference)
- .setSummaryResId(R.string.reference)
- .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
- .addSafetySource(SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId("dynamic_barebone")
- .setPackageName("package")
- .setTitleResId(R.string.reference)
- .setSummaryResId(R.string.reference)
- .setIntentAction("intent")
- .setProfile(SafetySource.PROFILE_PRIMARY)
- .build())
- .addSafetySource(SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId("dynamic_all_optional")
- .setPackageName("package")
- .setTitleResId(R.string.reference)
- .setTitleForWorkResId(R.string.reference)
- .setSummaryResId(R.string.reference)
- .setIntentAction("intent")
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .setMaxSeverityLevel(300)
- .setSearchTermsResId(R.string.reference)
- .setBroadcastReceiverClassName("broadcast")
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(true)
- .build())
- .addSafetySource(SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId("dynamic_disabled")
- .setPackageName("package")
- .setTitleResId(R.string.reference)
- .setSummaryResId(R.string.reference)
- .setProfile(SafetySource.PROFILE_PRIMARY)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .build())
- .addSafetySource(SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId("dynamic_hidden")
- .setPackageName("package")
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
- .build())
- .build())
- .addSafetySourcesGroup(SafetySourcesGroup.Builder()
- .setId("static")
- .setTitleResId(R.string.reference)
- .addSafetySource(SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_STATIC)
- .setId("static_barebone")
- .setTitleResId(R.string.reference)
- .setSummaryResId(R.string.reference)
- .setIntentAction("intent")
- .setProfile(SafetySource.PROFILE_PRIMARY)
- .build())
- .addSafetySource(SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_STATIC)
- .setId("static_all_optional")
- .setTitleResId(R.string.reference)
- .setTitleForWorkResId(R.string.reference)
- .setSummaryResId(R.string.reference)
- .setIntentAction("intent")
- .setProfile(SafetySource.PROFILE_ALL)
- .setSearchTermsResId(R.string.reference)
- .build())
- .build())
- .addSafetySourcesGroup(SafetySourcesGroup.Builder()
- .setId("issue_only")
- .addSafetySource(SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY)
- .setId("issue_only_barebone")
- .setPackageName("package")
- .setProfile(SafetySource.PROFILE_PRIMARY)
- .build())
- .addSafetySource(SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY)
- .setId("issue_only_all_optional")
- .setPackageName("package")
- .setProfile(SafetySource.PROFILE_ALL)
- .setMaxSeverityLevel(300)
- .setBroadcastReceiverClassName("broadcast")
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(true)
- .build())
- .build())
- .addSafetySourcesGroup(SafetySourcesGroup.Builder()
- .setId("mixed")
- .setTitleResId(R.string.reference)
- .addSafetySource(SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId("mixed_dynamic_barebone")
- .setPackageName("package")
- .setTitleResId(R.string.reference)
- .setSummaryResId(R.string.reference)
- .setIntentAction("intent")
- .setProfile(SafetySource.PROFILE_PRIMARY)
- .build())
- .addSafetySource(SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY)
- .setId("mixed_issue_only_barebone")
- .setPackageName("package")
- .setProfile(SafetySource.PROFILE_PRIMARY)
- .build())
- .addSafetySource(SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_STATIC)
- .setId("mixed_static_barebone")
- .setTitleResId(R.string.reference)
- .setSummaryResId(R.string.reference)
- .setIntentAction("intent")
- .setProfile(SafetySource.PROFILE_PRIMARY)
- .build())
- .build())
- .build()
- assertEquals(expected, SafetyCenterConfig.fromXml(parser))
- }
-}
diff --git a/tests/tests/safetycenter/src/android/safetycenter/config/cts/SafetyCenterConfigTest.kt b/tests/tests/safetycenter/src/android/safetycenter/config/cts/SafetyCenterConfigTest.kt
deleted file mode 100644
index 4c57233..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/config/cts/SafetyCenterConfigTest.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.config.cts
-
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.safetycenter.config.SafetyCenterConfig
-import android.safetycenter.testers.AnyTester
-import android.safetycenter.testers.ParcelableTester
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/** CTS tests for [SafetyCenterConfig]. */
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetyCenterConfigTest {
- @Test
- fun getSafetySources_returnsSafetySources() {
- assertThat(BASE.safetySourcesGroups)
- .containsExactly(
- SafetySourcesGroupTest.RIGID,
- SafetySourcesGroupTest.HIDDEN
- ).inOrder()
- }
-
- @Test
- fun describeContents_returns0() {
- assertThat(BASE.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsOriginalSafetyCenterConfig() {
- ParcelableTester.assertThatRoundTripReturnsOriginal(BASE, SafetyCenterConfig.CREATOR)
- }
-
- // TODO(b/208473675): Use `EqualsTester` for testing `hashcode` and `equals`.
- @Test
- fun hashCode_equals_toString_withEqualByReference_areEqual() {
- AnyTester.assertThatRepresentationsAreEqual(BASE, BASE)
- }
-
- @Test
- fun hashCode_equals_toString_withAllFieldsEqual_areEqual() {
- val baseAlt = SafetyCenterConfig.Builder()
- .addSafetySourcesGroup(SafetySourcesGroupTest.RIGID)
- .addSafetySourcesGroup(SafetySourcesGroupTest.HIDDEN)
- .build()
- AnyTester.assertThatRepresentationsAreEqual(BASE, baseAlt)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentSafetySources_areNotEqual() {
- val baseAlt = SafetyCenterConfig.Builder()
- .addSafetySourcesGroup(SafetySourcesGroupTest.HIDDEN)
- .addSafetySourcesGroup(SafetySourcesGroupTest.RIGID)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(BASE, baseAlt)
- }
-
- companion object {
- private val BASE = SafetyCenterConfig.Builder()
- .addSafetySourcesGroup(SafetySourcesGroupTest.RIGID)
- .addSafetySourcesGroup(SafetySourcesGroupTest.HIDDEN)
- .build()
- }
-}
diff --git a/tests/tests/safetycenter/src/android/safetycenter/config/cts/SafetySourceTest.kt b/tests/tests/safetycenter/src/android/safetycenter/config/cts/SafetySourceTest.kt
deleted file mode 100644
index f2a96df..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/config/cts/SafetySourceTest.kt
+++ /dev/null
@@ -1,699 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.config.cts
-
-import android.content.res.Resources
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.safetycenter.config.SafetySource
-import android.safetycenter.testers.AnyTester
-import android.safetycenter.testers.ParcelableTester
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Assert.assertThrows
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/** CTS tests for [SafetySource]. */
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetySourceTest {
- @Test
- fun getType_returnsType() {
- assertThat(DYNAMIC_BAREBONE.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- assertThat(DYNAMIC_ALL_OPTIONAL.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- assertThat(DYNAMIC_HIDDEN.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- assertThat(DYNAMIC_DISABLED.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- assertThat(STATIC_BAREBONE.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_STATIC)
- assertThat(STATIC_ALL_OPTIONAL.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_STATIC)
- assertThat(ISSUE_ONLY_BAREBONE.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.type)
- .isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY)
- }
-
- @Test
- fun getId_returnsId() {
- assertThat(DYNAMIC_BAREBONE.id).isEqualTo(DYNAMIC_BAREBONE_ID)
- assertThat(DYNAMIC_ALL_OPTIONAL.id).isEqualTo(DYNAMIC_ALL_OPTIONAL_ID)
- assertThat(DYNAMIC_HIDDEN.id).isEqualTo(DYNAMIC_HIDDEN_ID)
- assertThat(DYNAMIC_DISABLED.id).isEqualTo(DYNAMIC_DISABLED_ID)
- assertThat(STATIC_BAREBONE.id).isEqualTo(STATIC_BAREBONE_ID)
- assertThat(STATIC_ALL_OPTIONAL.id).isEqualTo(STATIC_ALL_OPTIONAL_ID)
- assertThat(ISSUE_ONLY_BAREBONE.id).isEqualTo(ISSUE_ONLY_BAREBONE_ID)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.id).isEqualTo(ISSUE_ONLY_ALL_OPTIONAL_ID)
- }
-
- @Test
- fun getPackageName_returnsPackageNameOrThrows() {
- assertThat(DYNAMIC_BAREBONE.packageName).isEqualTo(PACKAGE_NAME)
- assertThat(DYNAMIC_ALL_OPTIONAL.packageName).isEqualTo(PACKAGE_NAME)
- assertThat(DYNAMIC_HIDDEN.packageName).isEqualTo(PACKAGE_NAME)
- assertThat(DYNAMIC_DISABLED.packageName).isEqualTo(PACKAGE_NAME)
- assertThrows(UnsupportedOperationException::class.java) {
- STATIC_BAREBONE.packageName
- }
- assertThrows(UnsupportedOperationException::class.java) {
- STATIC_ALL_OPTIONAL.packageName
- }
- assertThat(ISSUE_ONLY_BAREBONE.packageName).isEqualTo(PACKAGE_NAME)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.packageName).isEqualTo(PACKAGE_NAME)
- }
-
- @Test
- fun getTitleResId_returnsTitleResIdOrThrows() {
- assertThat(DYNAMIC_BAREBONE.titleResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(DYNAMIC_ALL_OPTIONAL.titleResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(DYNAMIC_DISABLED.titleResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(DYNAMIC_HIDDEN.titleResId).isEqualTo(Resources.ID_NULL)
- assertThat(STATIC_BAREBONE.titleResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(STATIC_ALL_OPTIONAL.titleResId).isEqualTo(REFERENCE_RES_ID)
- assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_BAREBONE.titleResId
- }
- assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_ALL_OPTIONAL.titleResId
- }
- }
-
- @Test
- fun getTitleForWorkResId_returnsTitleForWorkResIdOrThrows() {
- assertThrows(UnsupportedOperationException::class.java) {
- DYNAMIC_BAREBONE.titleForWorkResId
- }
- assertThat(DYNAMIC_ALL_OPTIONAL.titleForWorkResId).isEqualTo(REFERENCE_RES_ID)
- assertThrows(UnsupportedOperationException::class.java) {
- DYNAMIC_DISABLED.titleForWorkResId
- }
- assertThat(DYNAMIC_HIDDEN.titleForWorkResId).isEqualTo(Resources.ID_NULL)
- assertThrows(UnsupportedOperationException::class.java) {
- STATIC_BAREBONE.titleForWorkResId
- }
- assertThat(STATIC_ALL_OPTIONAL.titleForWorkResId).isEqualTo(REFERENCE_RES_ID)
- assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_BAREBONE.titleForWorkResId
- }
- assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_ALL_OPTIONAL.titleForWorkResId
- }
- }
-
- @Test
- fun getSummaryResId_returnsSummaryResIdOrThrows() {
- assertThat(DYNAMIC_BAREBONE.summaryResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(DYNAMIC_ALL_OPTIONAL.summaryResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(DYNAMIC_DISABLED.summaryResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(DYNAMIC_HIDDEN.summaryResId).isEqualTo(Resources.ID_NULL)
- assertThat(STATIC_BAREBONE.summaryResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(STATIC_ALL_OPTIONAL.summaryResId).isEqualTo(REFERENCE_RES_ID)
- assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_BAREBONE.summaryResId
- }
- assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_ALL_OPTIONAL.summaryResId
- }
- }
-
- @Test
- fun getIntentAction_returnsIntentActionOrThrows() {
- assertThat(DYNAMIC_BAREBONE.intentAction).isEqualTo(INTENT_ACTION)
- assertThat(DYNAMIC_ALL_OPTIONAL.intentAction).isEqualTo(INTENT_ACTION)
- assertThat(DYNAMIC_DISABLED.intentAction).isNull()
- assertThat(DYNAMIC_HIDDEN.intentAction).isNull()
- assertThat(STATIC_BAREBONE.intentAction).isEqualTo(INTENT_ACTION)
- assertThat(STATIC_ALL_OPTIONAL.intentAction).isEqualTo(INTENT_ACTION)
- assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_BAREBONE.intentAction
- }
- assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_ALL_OPTIONAL.intentAction
- }
- }
-
- @Test
- fun getProfile_returnsProfile() {
- assertThat(DYNAMIC_BAREBONE.profile).isEqualTo(SafetySource.PROFILE_PRIMARY)
- assertThat(DYNAMIC_ALL_OPTIONAL.profile).isEqualTo(SafetySource.PROFILE_ALL)
- assertThat(DYNAMIC_DISABLED.profile).isEqualTo(SafetySource.PROFILE_PRIMARY)
- assertThat(DYNAMIC_HIDDEN.profile).isEqualTo(SafetySource.PROFILE_ALL)
- assertThat(STATIC_BAREBONE.profile).isEqualTo(SafetySource.PROFILE_PRIMARY)
- assertThat(STATIC_ALL_OPTIONAL.profile).isEqualTo(SafetySource.PROFILE_ALL)
- assertThat(ISSUE_ONLY_BAREBONE.profile).isEqualTo(SafetySource.PROFILE_PRIMARY)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.profile).isEqualTo(SafetySource.PROFILE_ALL)
- }
-
- @Test
- fun getInitialDisplayState_returnsInitialDisplayStateOrThrows() {
- assertThat(DYNAMIC_BAREBONE.initialDisplayState)
- .isEqualTo(SafetySource.INITIAL_DISPLAY_STATE_ENABLED)
- assertThat(DYNAMIC_ALL_OPTIONAL.initialDisplayState)
- .isEqualTo(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- assertThat(DYNAMIC_DISABLED.initialDisplayState)
- .isEqualTo(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- assertThat(DYNAMIC_HIDDEN.initialDisplayState)
- .isEqualTo(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
- assertThrows(UnsupportedOperationException::class.java) {
- STATIC_BAREBONE.initialDisplayState
- }
- assertThrows(UnsupportedOperationException::class.java) {
- STATIC_ALL_OPTIONAL.initialDisplayState
- }
- assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_BAREBONE.initialDisplayState
- }
- assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_ALL_OPTIONAL.initialDisplayState
- }
- }
-
- @Test
- fun getMaxSeverityLevel_returnsMaxSeverityLevelOrThrows() {
- assertThat(DYNAMIC_BAREBONE.maxSeverityLevel).isEqualTo(Integer.MAX_VALUE)
- assertThat(DYNAMIC_ALL_OPTIONAL.maxSeverityLevel).isEqualTo(MAX_SEVERITY_LEVEL)
- assertThat(DYNAMIC_DISABLED.maxSeverityLevel).isEqualTo(Integer.MAX_VALUE)
- assertThat(DYNAMIC_HIDDEN.maxSeverityLevel).isEqualTo(Integer.MAX_VALUE)
- assertThrows(UnsupportedOperationException::class.java) {
- STATIC_BAREBONE.maxSeverityLevel
- }
- assertThrows(UnsupportedOperationException::class.java) {
- STATIC_ALL_OPTIONAL.maxSeverityLevel
- }
- assertThat(ISSUE_ONLY_BAREBONE.maxSeverityLevel).isEqualTo(Integer.MAX_VALUE)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.maxSeverityLevel).isEqualTo(MAX_SEVERITY_LEVEL)
- }
-
- @Test
- fun getSearchTermsResId_returnsSearchTermsResIdOrThrows() {
- assertThat(DYNAMIC_BAREBONE.searchTermsResId).isEqualTo(Resources.ID_NULL)
- assertThat(DYNAMIC_ALL_OPTIONAL.searchTermsResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(DYNAMIC_DISABLED.searchTermsResId).isEqualTo(Resources.ID_NULL)
- assertThat(DYNAMIC_HIDDEN.searchTermsResId).isEqualTo(Resources.ID_NULL)
- assertThat(STATIC_BAREBONE.searchTermsResId).isEqualTo(Resources.ID_NULL)
- assertThat(STATIC_ALL_OPTIONAL.searchTermsResId).isEqualTo(REFERENCE_RES_ID)
- assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_BAREBONE.searchTermsResId
- }
- assertThrows(UnsupportedOperationException::class.java) {
- ISSUE_ONLY_ALL_OPTIONAL.searchTermsResId
- }
- }
-
- @Test
- fun getBroadcastReceiverClassName_returnsBroadcastReceiverClassNameOrThrows() {
- assertThat(DYNAMIC_BAREBONE.broadcastReceiverClassName).isNull()
- assertThat(DYNAMIC_ALL_OPTIONAL.broadcastReceiverClassName)
- .isEqualTo(BROADCAST_RECEIVER_CLASS_NAME)
- assertThat(DYNAMIC_DISABLED.broadcastReceiverClassName).isNull()
- assertThat(DYNAMIC_HIDDEN.broadcastReceiverClassName).isNull()
- assertThrows(UnsupportedOperationException::class.java) {
- STATIC_BAREBONE.broadcastReceiverClassName
- }
- assertThrows(UnsupportedOperationException::class.java) {
- STATIC_ALL_OPTIONAL.broadcastReceiverClassName
- }
- assertThat(ISSUE_ONLY_BAREBONE.broadcastReceiverClassName).isNull()
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.broadcastReceiverClassName)
- .isEqualTo(BROADCAST_RECEIVER_CLASS_NAME)
- }
-
- @Test
- fun isLoggingAllowed_returnsLoggingAllowedOrThrows() {
- assertThat(DYNAMIC_BAREBONE.isLoggingAllowed).isEqualTo(true)
- assertThat(DYNAMIC_ALL_OPTIONAL.isLoggingAllowed).isEqualTo(false)
- assertThat(DYNAMIC_DISABLED.isLoggingAllowed).isEqualTo(true)
- assertThat(DYNAMIC_HIDDEN.isLoggingAllowed).isEqualTo(true)
- assertThrows(UnsupportedOperationException::class.java) {
- STATIC_BAREBONE.isLoggingAllowed
- }
- assertThrows(UnsupportedOperationException::class.java) {
- STATIC_ALL_OPTIONAL.isLoggingAllowed
- }
- assertThat(ISSUE_ONLY_BAREBONE.isLoggingAllowed).isEqualTo(true)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.isLoggingAllowed).isEqualTo(false)
- }
-
- @Test
- fun isRefreshOnPageOpenAllowed_returnsRefreshOnPageOpenAllowedOrThrows() {
- assertThat(DYNAMIC_BAREBONE.isRefreshOnPageOpenAllowed).isEqualTo(false)
- assertThat(DYNAMIC_ALL_OPTIONAL.isRefreshOnPageOpenAllowed).isEqualTo(true)
- assertThat(DYNAMIC_DISABLED.isRefreshOnPageOpenAllowed).isEqualTo(false)
- assertThat(DYNAMIC_HIDDEN.isRefreshOnPageOpenAllowed).isEqualTo(false)
- assertThrows(UnsupportedOperationException::class.java) {
- STATIC_BAREBONE.isRefreshOnPageOpenAllowed
- }
- assertThrows(UnsupportedOperationException::class.java) {
- STATIC_ALL_OPTIONAL.isRefreshOnPageOpenAllowed
- }
- assertThat(ISSUE_ONLY_BAREBONE.isRefreshOnPageOpenAllowed).isEqualTo(false)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.isRefreshOnPageOpenAllowed).isEqualTo(true)
- }
-
- @Test
- fun describeContents_returns0() {
- assertThat(DYNAMIC_BAREBONE.describeContents()).isEqualTo(0)
- assertThat(DYNAMIC_ALL_OPTIONAL.describeContents()).isEqualTo(0)
- assertThat(DYNAMIC_HIDDEN.describeContents()).isEqualTo(0)
- assertThat(DYNAMIC_DISABLED.describeContents()).isEqualTo(0)
- assertThat(STATIC_BAREBONE.describeContents()).isEqualTo(0)
- assertThat(STATIC_ALL_OPTIONAL.describeContents()).isEqualTo(0)
- assertThat(ISSUE_ONLY_BAREBONE.describeContents()).isEqualTo(0)
- assertThat(ISSUE_ONLY_ALL_OPTIONAL.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsOriginalSafetySource() {
- ParcelableTester.assertThatRoundTripReturnsOriginal(DYNAMIC_BAREBONE, SafetySource.CREATOR)
- ParcelableTester.assertThatRoundTripReturnsOriginal(
- DYNAMIC_ALL_OPTIONAL,
- SafetySource.CREATOR
- )
- ParcelableTester.assertThatRoundTripReturnsOriginal(DYNAMIC_HIDDEN, SafetySource.CREATOR)
- ParcelableTester.assertThatRoundTripReturnsOriginal(DYNAMIC_DISABLED, SafetySource.CREATOR)
- ParcelableTester.assertThatRoundTripReturnsOriginal(STATIC_BAREBONE, SafetySource.CREATOR)
- ParcelableTester.assertThatRoundTripReturnsOriginal(
- STATIC_ALL_OPTIONAL,
- SafetySource.CREATOR
- )
- ParcelableTester.assertThatRoundTripReturnsOriginal(
- ISSUE_ONLY_BAREBONE,
- SafetySource.CREATOR
- )
- ParcelableTester.assertThatRoundTripReturnsOriginal(
- ISSUE_ONLY_ALL_OPTIONAL,
- SafetySource.CREATOR
- )
- }
-
- // TODO(b/208473675): Use `EqualsTester` for testing `hashcode` and `equals`.
- @Test
- fun hashCode_equals_toString_withEqualByReference_areEqual() {
- AnyTester.assertThatRepresentationsAreEqual(DYNAMIC_BAREBONE, DYNAMIC_BAREBONE)
- AnyTester.assertThatRepresentationsAreEqual(DYNAMIC_ALL_OPTIONAL, DYNAMIC_ALL_OPTIONAL)
- AnyTester.assertThatRepresentationsAreEqual(DYNAMIC_HIDDEN, DYNAMIC_HIDDEN)
- AnyTester.assertThatRepresentationsAreEqual(DYNAMIC_DISABLED, DYNAMIC_DISABLED)
- AnyTester.assertThatRepresentationsAreEqual(STATIC_BAREBONE, STATIC_BAREBONE)
- AnyTester.assertThatRepresentationsAreEqual(STATIC_ALL_OPTIONAL, STATIC_ALL_OPTIONAL)
- AnyTester.assertThatRepresentationsAreEqual(ISSUE_ONLY_BAREBONE, ISSUE_ONLY_BAREBONE)
- AnyTester.assertThatRepresentationsAreEqual(
- ISSUE_ONLY_ALL_OPTIONAL,
- ISSUE_ONLY_ALL_OPTIONAL
- )
- }
-
- @Test
- fun hashCode_equals_toString_withAllFieldsEqual_areEqual() {
- val dynamicAllOptionalCopy = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_ALL_OPTIONAL_ID)
- .setPackageName(PACKAGE_NAME)
- .setTitleResId(REFERENCE_RES_ID)
- .setTitleForWorkResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
- .setSearchTermsResId(REFERENCE_RES_ID)
- .setBroadcastReceiverClassName(BROADCAST_RECEIVER_CLASS_NAME)
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(true)
- .build()
- AnyTester.assertThatRepresentationsAreEqual(DYNAMIC_ALL_OPTIONAL, dynamicAllOptionalCopy)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentTypes_areNotEqual() {
- AnyTester.assertThatRepresentationsAreNotEqual(DYNAMIC_BAREBONE, STATIC_BAREBONE)
- AnyTester.assertThatRepresentationsAreNotEqual(STATIC_BAREBONE, ISSUE_ONLY_BAREBONE)
- AnyTester.assertThatRepresentationsAreNotEqual(ISSUE_ONLY_BAREBONE, DYNAMIC_BAREBONE)
- AnyTester.assertThatRepresentationsAreNotEqual(DYNAMIC_ALL_OPTIONAL, STATIC_ALL_OPTIONAL)
- AnyTester.assertThatRepresentationsAreNotEqual(STATIC_ALL_OPTIONAL, ISSUE_ONLY_ALL_OPTIONAL)
- AnyTester.assertThatRepresentationsAreNotEqual(
- ISSUE_ONLY_ALL_OPTIONAL,
- DYNAMIC_ALL_OPTIONAL
- )
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentIds_areNotEqual() {
- val dynamicAllOptionalAlt = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId("other")
- .setPackageName(PACKAGE_NAME)
- .setTitleResId(REFERENCE_RES_ID)
- .setTitleForWorkResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
- .setSearchTermsResId(REFERENCE_RES_ID)
- .setBroadcastReceiverClassName(BROADCAST_RECEIVER_CLASS_NAME)
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(true)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(DYNAMIC_ALL_OPTIONAL, dynamicAllOptionalAlt)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentPackageNames_areNotEqual() {
- val dynamicAllOptionalAlt = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_ALL_OPTIONAL_ID)
- .setPackageName("other")
- .setTitleResId(REFERENCE_RES_ID)
- .setTitleForWorkResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
- .setSearchTermsResId(REFERENCE_RES_ID)
- .setBroadcastReceiverClassName(BROADCAST_RECEIVER_CLASS_NAME)
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(true)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(DYNAMIC_ALL_OPTIONAL, dynamicAllOptionalAlt)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentTitleResIds_areNotEqual() {
- val dynamicAllOptionalAlt = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_ALL_OPTIONAL_ID)
- .setPackageName(PACKAGE_NAME)
- .setTitleResId(-1)
- .setTitleForWorkResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
- .setSearchTermsResId(REFERENCE_RES_ID)
- .setBroadcastReceiverClassName(BROADCAST_RECEIVER_CLASS_NAME)
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(true)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(DYNAMIC_ALL_OPTIONAL, dynamicAllOptionalAlt)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentTitleForWorkResIds_areNotEqual() {
- val dynamicAllOptionalAlt = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_ALL_OPTIONAL_ID)
- .setPackageName(PACKAGE_NAME)
- .setTitleResId(REFERENCE_RES_ID)
- .setTitleForWorkResId(-1)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
- .setSearchTermsResId(REFERENCE_RES_ID)
- .setBroadcastReceiverClassName(BROADCAST_RECEIVER_CLASS_NAME)
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(true)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(DYNAMIC_ALL_OPTIONAL, dynamicAllOptionalAlt)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentSummaryResIds_areNotEqual() {
- val dynamicAllOptionalAlt = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_ALL_OPTIONAL_ID)
- .setPackageName(PACKAGE_NAME)
- .setTitleResId(REFERENCE_RES_ID)
- .setTitleForWorkResId(REFERENCE_RES_ID)
- .setSummaryResId(-1)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
- .setSearchTermsResId(REFERENCE_RES_ID)
- .setBroadcastReceiverClassName(BROADCAST_RECEIVER_CLASS_NAME)
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(true)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(DYNAMIC_ALL_OPTIONAL, dynamicAllOptionalAlt)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentIntentActions_areNotEqual() {
- val dynamicAllOptionalAlt = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_ALL_OPTIONAL_ID)
- .setPackageName(PACKAGE_NAME)
- .setTitleResId(REFERENCE_RES_ID)
- .setTitleForWorkResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction("other")
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
- .setSearchTermsResId(REFERENCE_RES_ID)
- .setBroadcastReceiverClassName(BROADCAST_RECEIVER_CLASS_NAME)
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(true)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(DYNAMIC_ALL_OPTIONAL, dynamicAllOptionalAlt)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentProfiles_areNotEqual() {
- val dynamicHiddenAlt = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_HIDDEN_ID)
- .setPackageName(PACKAGE_NAME)
- .setProfile(SafetySource.PROFILE_PRIMARY)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(DYNAMIC_HIDDEN, dynamicHiddenAlt)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentInitialDisplayStates_areNotEqual() {
- val dynamicAllOptionalAlt = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_ALL_OPTIONAL_ID)
- .setPackageName(PACKAGE_NAME)
- .setTitleResId(REFERENCE_RES_ID)
- .setTitleForWorkResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_ENABLED)
- .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
- .setSearchTermsResId(REFERENCE_RES_ID)
- .setBroadcastReceiverClassName(BROADCAST_RECEIVER_CLASS_NAME)
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(true)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(DYNAMIC_ALL_OPTIONAL, dynamicAllOptionalAlt)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentMaxSeverityLevel_areNotEqual() {
- val dynamicAllOptionalAlt = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_ALL_OPTIONAL_ID)
- .setPackageName(PACKAGE_NAME)
- .setTitleResId(REFERENCE_RES_ID)
- .setTitleForWorkResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .setMaxSeverityLevel(-1)
- .setSearchTermsResId(REFERENCE_RES_ID)
- .setBroadcastReceiverClassName(BROADCAST_RECEIVER_CLASS_NAME)
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(true)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(DYNAMIC_ALL_OPTIONAL, dynamicAllOptionalAlt)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentSearchTermsResIds_areNotEqual() {
- val dynamicAllOptionalAlt = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_ALL_OPTIONAL_ID)
- .setPackageName(PACKAGE_NAME)
- .setTitleResId(REFERENCE_RES_ID)
- .setTitleForWorkResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
- .setSearchTermsResId(-1)
- .setBroadcastReceiverClassName(BROADCAST_RECEIVER_CLASS_NAME)
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(true)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(DYNAMIC_ALL_OPTIONAL, dynamicAllOptionalAlt)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentBroadcastReceiverClassNames_areNotEqual() {
- val dynamicAllOptionalAlt = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_ALL_OPTIONAL_ID)
- .setPackageName(PACKAGE_NAME)
- .setTitleResId(REFERENCE_RES_ID)
- .setTitleForWorkResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
- .setSearchTermsResId(REFERENCE_RES_ID)
- .setBroadcastReceiverClassName("other")
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(true)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(DYNAMIC_ALL_OPTIONAL, dynamicAllOptionalAlt)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentLoggingAlloweds_areNotEqual() {
- val dynamicAllOptionalAlt = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_ALL_OPTIONAL_ID)
- .setPackageName(PACKAGE_NAME)
- .setTitleResId(REFERENCE_RES_ID)
- .setTitleForWorkResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
- .setSearchTermsResId(REFERENCE_RES_ID)
- .setBroadcastReceiverClassName(BROADCAST_RECEIVER_CLASS_NAME)
- .setLoggingAllowed(true)
- .setRefreshOnPageOpenAllowed(true)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(DYNAMIC_ALL_OPTIONAL, dynamicAllOptionalAlt)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentRefreshOnPageOpenAlloweds_areNotEqual() {
- val dynamicAllOptionalAlt = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_ALL_OPTIONAL_ID)
- .setPackageName(PACKAGE_NAME)
- .setTitleResId(REFERENCE_RES_ID)
- .setTitleForWorkResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
- .setSearchTermsResId(REFERENCE_RES_ID)
- .setBroadcastReceiverClassName(BROADCAST_RECEIVER_CLASS_NAME)
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(false)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(DYNAMIC_ALL_OPTIONAL, dynamicAllOptionalAlt)
- }
-
- companion object {
- private const val PACKAGE_NAME = "package"
- private const val REFERENCE_RES_ID = 9999
- private const val INTENT_ACTION = "intent"
- private const val BROADCAST_RECEIVER_CLASS_NAME = "broadcast"
- private const val MAX_SEVERITY_LEVEL = 300
-
- private const val DYNAMIC_BAREBONE_ID = "dynamic_barebone"
- private const val DYNAMIC_ALL_OPTIONAL_ID = "dynamic_all_optional"
- private const val DYNAMIC_DISABLED_ID = "dynamic_disabled"
- private const val DYNAMIC_HIDDEN_ID = "dynamic_hidden"
- private const val STATIC_BAREBONE_ID = "static_barebone"
- private const val STATIC_ALL_OPTIONAL_ID = "static_all_optional"
- private const val ISSUE_ONLY_BAREBONE_ID = "issue_only_barebone"
- private const val ISSUE_ONLY_ALL_OPTIONAL_ID = "issue_only_all_optional"
-
- internal val DYNAMIC_BAREBONE =
- SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_BAREBONE_ID)
- .setPackageName(PACKAGE_NAME)
- .setTitleResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_PRIMARY)
- .build()
-
- private val DYNAMIC_ALL_OPTIONAL =
- SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_ALL_OPTIONAL_ID)
- .setPackageName(PACKAGE_NAME)
- .setTitleResId(REFERENCE_RES_ID)
- .setTitleForWorkResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
- .setSearchTermsResId(REFERENCE_RES_ID)
- .setBroadcastReceiverClassName(BROADCAST_RECEIVER_CLASS_NAME)
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(true)
- .build()
-
- private val DYNAMIC_DISABLED =
- SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_DISABLED_ID)
- .setPackageName(PACKAGE_NAME)
- .setTitleResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setProfile(SafetySource.PROFILE_PRIMARY)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED)
- .build()
-
- private val DYNAMIC_HIDDEN =
- SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(DYNAMIC_HIDDEN_ID)
- .setPackageName(PACKAGE_NAME)
- .setProfile(SafetySource.PROFILE_ALL)
- .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
- .build()
-
- internal val STATIC_BAREBONE =
- SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_STATIC)
- .setId(STATIC_BAREBONE_ID)
- .setTitleResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_PRIMARY)
- .build()
-
- private val STATIC_ALL_OPTIONAL =
- SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_STATIC)
- .setId(STATIC_ALL_OPTIONAL_ID)
- .setTitleResId(REFERENCE_RES_ID)
- .setTitleForWorkResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setIntentAction(INTENT_ACTION)
- .setProfile(SafetySource.PROFILE_ALL)
- .setSearchTermsResId(REFERENCE_RES_ID)
- .build()
-
- internal val ISSUE_ONLY_BAREBONE =
- SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY)
- .setId(ISSUE_ONLY_BAREBONE_ID)
- .setPackageName(PACKAGE_NAME)
- .setProfile(SafetySource.PROFILE_PRIMARY)
- .build()
-
- private val ISSUE_ONLY_ALL_OPTIONAL =
- SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY)
- .setId(ISSUE_ONLY_ALL_OPTIONAL_ID)
- .setPackageName(PACKAGE_NAME)
- .setProfile(SafetySource.PROFILE_ALL)
- .setMaxSeverityLevel(MAX_SEVERITY_LEVEL)
- .setBroadcastReceiverClassName(BROADCAST_RECEIVER_CLASS_NAME)
- .setLoggingAllowed(false)
- .setRefreshOnPageOpenAllowed(true)
- .build()
- }
-}
diff --git a/tests/tests/safetycenter/src/android/safetycenter/config/cts/SafetySourcesGroupTest.kt b/tests/tests/safetycenter/src/android/safetycenter/config/cts/SafetySourcesGroupTest.kt
deleted file mode 100644
index 2e61411..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/config/cts/SafetySourcesGroupTest.kt
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.config.cts
-
-import android.content.res.Resources
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.safetycenter.config.SafetySourcesGroup
-import android.safetycenter.testers.AnyTester
-import android.safetycenter.testers.ParcelableTester
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/** CTS tests for [SafetySourcesGroup]. */
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetySourcesGroupTest {
- @Test
- fun getType_returnsType() {
- assertThat(COLLAPSIBLE_WITH_SUMMARY.type)
- .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_COLLAPSIBLE)
- assertThat(COLLAPSIBLE_WITH_ICON.type)
- .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_COLLAPSIBLE)
- assertThat(COLLAPSIBLE_WITH_BOTH.type)
- .isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_COLLAPSIBLE)
- assertThat(RIGID.type).isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_RIGID)
- assertThat(HIDDEN.type).isEqualTo(SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN)
- }
-
- @Test
- fun getId_returnsId() {
- assertThat(COLLAPSIBLE_WITH_SUMMARY.id).isEqualTo(COLLAPSIBLE_WITH_SUMMARY_ID)
- assertThat(COLLAPSIBLE_WITH_ICON.id).isEqualTo(COLLAPSIBLE_WITH_ICON_ID)
- assertThat(COLLAPSIBLE_WITH_BOTH.id).isEqualTo(COLLAPSIBLE_WITH_BOTH_ID)
- assertThat(RIGID.id).isEqualTo(RIGID_ID)
- assertThat(HIDDEN.id).isEqualTo(HIDDEN_ID)
- }
-
- @Test
- fun getTitleResId_returnsTitleResId() {
- assertThat(COLLAPSIBLE_WITH_SUMMARY.titleResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(COLLAPSIBLE_WITH_ICON.titleResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(COLLAPSIBLE_WITH_BOTH.titleResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(RIGID.titleResId).isEqualTo(REFERENCE_RES_ID)
- // This is not an enforced invariant, titleResId should just be ignored for hidden groups
- assertThat(HIDDEN.titleResId).isEqualTo(Resources.ID_NULL)
- }
-
- @Test
- fun getSummaryResId_returnsSummaryResId() {
- assertThat(COLLAPSIBLE_WITH_SUMMARY.summaryResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(COLLAPSIBLE_WITH_ICON.summaryResId).isEqualTo(Resources.ID_NULL)
- assertThat(COLLAPSIBLE_WITH_BOTH.summaryResId).isEqualTo(REFERENCE_RES_ID)
- assertThat(RIGID.summaryResId).isEqualTo(Resources.ID_NULL)
- // This is not an enforced invariant, summaryResId should just be ignored for hidden groups
- assertThat(HIDDEN.summaryResId).isEqualTo(Resources.ID_NULL)
- }
-
- @Test
- fun getStatelessIconType_returnsStatelessIconType() {
- assertThat(COLLAPSIBLE_WITH_SUMMARY.statelessIconType)
- .isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_NONE)
- assertThat(COLLAPSIBLE_WITH_ICON.statelessIconType)
- .isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
- assertThat(COLLAPSIBLE_WITH_BOTH.statelessIconType)
- .isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
- assertThat(RIGID.statelessIconType).isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_NONE)
- // This is not an enforced invariant
- // statelessIconType should just be ignored for hidden groups
- assertThat(HIDDEN.statelessIconType).isEqualTo(SafetySourcesGroup.STATELESS_ICON_TYPE_NONE)
- }
-
- @Test
- fun getSafetySources_returnsSafetySources() {
- assertThat(COLLAPSIBLE_WITH_SUMMARY.safetySources)
- .containsExactly(SafetySourceTest.DYNAMIC_BAREBONE)
- assertThat(COLLAPSIBLE_WITH_ICON.safetySources)
- .containsExactly(SafetySourceTest.STATIC_BAREBONE)
- assertThat(COLLAPSIBLE_WITH_BOTH.safetySources)
- .containsExactly(
- SafetySourceTest.DYNAMIC_BAREBONE,
- SafetySourceTest.STATIC_BAREBONE,
- SafetySourceTest.ISSUE_ONLY_BAREBONE
- ).inOrder()
- assertThat(RIGID.safetySources).containsExactly(SafetySourceTest.STATIC_BAREBONE)
- assertThat(HIDDEN.safetySources).containsExactly(SafetySourceTest.ISSUE_ONLY_BAREBONE)
- }
-
- @Test
- fun describeContents_returns0() {
- assertThat(COLLAPSIBLE_WITH_SUMMARY.describeContents()).isEqualTo(0)
- assertThat(COLLAPSIBLE_WITH_ICON.describeContents()).isEqualTo(0)
- assertThat(COLLAPSIBLE_WITH_BOTH.describeContents()).isEqualTo(0)
- assertThat(RIGID.describeContents()).isEqualTo(0)
- assertThat(HIDDEN.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsOriginalSafetySourcesGroup() {
- ParcelableTester.assertThatRoundTripReturnsOriginal(
- COLLAPSIBLE_WITH_SUMMARY,
- SafetySourcesGroup.CREATOR
- )
- ParcelableTester.assertThatRoundTripReturnsOriginal(
- COLLAPSIBLE_WITH_ICON,
- SafetySourcesGroup.CREATOR
- )
- ParcelableTester.assertThatRoundTripReturnsOriginal(
- COLLAPSIBLE_WITH_BOTH,
- SafetySourcesGroup.CREATOR
- )
- ParcelableTester.assertThatRoundTripReturnsOriginal(RIGID, SafetySourcesGroup.CREATOR)
- ParcelableTester.assertThatRoundTripReturnsOriginal(HIDDEN, SafetySourcesGroup.CREATOR)
- }
-
- // TODO(b/208473675): Use `EqualsTester` for testing `hashcode` and `equals`.
- @Test
- fun hashCode_equals_toString_withEqualByReference_areEqual() {
- AnyTester.assertThatRepresentationsAreEqual(
- COLLAPSIBLE_WITH_SUMMARY,
- COLLAPSIBLE_WITH_SUMMARY
- )
- AnyTester.assertThatRepresentationsAreEqual(COLLAPSIBLE_WITH_ICON, COLLAPSIBLE_WITH_ICON)
- AnyTester.assertThatRepresentationsAreEqual(COLLAPSIBLE_WITH_BOTH, COLLAPSIBLE_WITH_BOTH)
- AnyTester.assertThatRepresentationsAreEqual(RIGID, RIGID)
- AnyTester.assertThatRepresentationsAreEqual(HIDDEN, HIDDEN)
- }
-
- @Test
- fun hashCode_equals_toString_withAllFieldsEqual_areEqual() {
- val collapsibleWithBothCopy = SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_BOTH_ID)
- .setTitleResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
- .addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
- .addSafetySource(SafetySourceTest.STATIC_BAREBONE)
- .addSafetySource(SafetySourceTest.ISSUE_ONLY_BAREBONE)
- .build()
- AnyTester.assertThatRepresentationsAreEqual(COLLAPSIBLE_WITH_BOTH, collapsibleWithBothCopy)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentTypes_areNotEqual() {
- AnyTester.assertThatRepresentationsAreNotEqual(COLLAPSIBLE_WITH_BOTH, RIGID)
- AnyTester.assertThatRepresentationsAreNotEqual(RIGID, HIDDEN)
- AnyTester.assertThatRepresentationsAreNotEqual(HIDDEN, COLLAPSIBLE_WITH_BOTH)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentIds_areNotEqual() {
- val collapsibleWithBothAlt = SafetySourcesGroup.Builder()
- .setId("other")
- .setTitleResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
- .addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(
- COLLAPSIBLE_WITH_BOTH,
- collapsibleWithBothAlt
- )
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentTitleResIds_areNotEqual() {
- val collapsibleWithBothAlt = SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_BOTH_ID)
- .setTitleResId(-1)
- .setSummaryResId(REFERENCE_RES_ID)
- .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
- .addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(
- COLLAPSIBLE_WITH_BOTH,
- collapsibleWithBothAlt
- )
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentSummaryResIds_areNotEqual() {
- val collapsibleWithBothAlt = SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_BOTH_ID)
- .setTitleResId(REFERENCE_RES_ID)
- .setSummaryResId(-1)
- .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
- .addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(
- COLLAPSIBLE_WITH_BOTH,
- collapsibleWithBothAlt
- )
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentInitialDisplayStates_areNotEqual() {
- val collapsibleWithBothAlt = SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_BOTH_ID)
- .setTitleResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_NONE)
- .addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(
- COLLAPSIBLE_WITH_BOTH,
- collapsibleWithBothAlt
- )
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentSafetySources_areNotEqual() {
- val collapsibleWithBothAlt = SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_BOTH_ID)
- .setTitleResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
- .addSafetySource(SafetySourceTest.STATIC_BAREBONE)
- .build()
- AnyTester.assertThatRepresentationsAreNotEqual(
- COLLAPSIBLE_WITH_BOTH,
- collapsibleWithBothAlt
- )
- }
-
- companion object {
- private const val REFERENCE_RES_ID = 9999
-
- private const val COLLAPSIBLE_WITH_SUMMARY_ID = "collapsible_with_summary"
- private const val COLLAPSIBLE_WITH_ICON_ID = "collapsible_with_icon"
- private const val COLLAPSIBLE_WITH_BOTH_ID = "collapsible_with_both"
- private const val RIGID_ID = "rigid"
- private const val HIDDEN_ID = "hidden"
-
- private val COLLAPSIBLE_WITH_SUMMARY = SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_SUMMARY_ID)
- .setTitleResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
- .build()
-
- private val COLLAPSIBLE_WITH_ICON = SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_ICON_ID)
- .setTitleResId(REFERENCE_RES_ID)
- .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
- .addSafetySource(SafetySourceTest.STATIC_BAREBONE)
- .build()
-
- private val COLLAPSIBLE_WITH_BOTH = SafetySourcesGroup.Builder()
- .setId(COLLAPSIBLE_WITH_BOTH_ID)
- .setTitleResId(REFERENCE_RES_ID)
- .setSummaryResId(REFERENCE_RES_ID)
- .setStatelessIconType(SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY)
- .addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE)
- .addSafetySource(SafetySourceTest.STATIC_BAREBONE)
- .addSafetySource(SafetySourceTest.ISSUE_ONLY_BAREBONE)
- .build()
-
- internal val RIGID = SafetySourcesGroup.Builder()
- .setId(RIGID_ID)
- .setTitleResId(REFERENCE_RES_ID)
- .addSafetySource(SafetySourceTest.STATIC_BAREBONE)
- .build()
-
- internal val HIDDEN = SafetySourcesGroup.Builder()
- .setId(HIDDEN_ID)
- .addSafetySource(SafetySourceTest.ISSUE_ONLY_BAREBONE)
- .build()
- }
-}
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterActivityTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterActivityTest.kt
deleted file mode 100644
index 0adf458..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterActivityTest.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.content.Context
-import android.content.Intent
-import android.content.Intent.ACTION_SAFETY_CENTER
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.support.test.uiautomator.By
-import androidx.test.core.app.ApplicationProvider.getApplicationContext
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetyCenterActivityTest {
- private val context: Context = getApplicationContext()
-
- @Test
- fun launchActivity_showsSecurityAndPrivacyTitle() {
- context.startActivity(
- Intent(ACTION_SAFETY_CENTER).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- )
-
- // CollapsingToolbar title can't be found by text, so using description instead.
- waitFindObject(By.desc("Security & Privacy"))
- }
-}
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterApisWithShellPermissions.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterApisWithShellPermissions.kt
deleted file mode 100644
index c3c7e726..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterApisWithShellPermissions.kt
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.Manifest.permission.MANAGE_SAFETY_CENTER
-import android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE
-import android.safetycenter.SafetyCenterData
-import android.safetycenter.SafetyCenterManager
-import android.safetycenter.SafetyCenterManager.OnSafetyCenterDataChangedListener
-import android.safetycenter.SafetySourceData
-import android.safetycenter.SafetyEvent
-import android.safetycenter.config.SafetyCenterConfig
-import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
-import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
-import java.util.concurrent.Executor
-
-/**
- * Call {@link SafetyCenterManager#setSafetySourceData} adopting Shell's
- * {@link SEND_SAFETY_CENTER_UPDATE} permission.
- */
-fun SafetyCenterManager.setSafetySourceDataWithPermission(
- safetySourceId: String,
- safetySourceData: SafetySourceData,
- safetyEvent: SafetyEvent
-) =
- runWithShellPermissionIdentity({
- setSafetySourceData(safetySourceId, safetySourceData, safetyEvent)
- }, SEND_SAFETY_CENTER_UPDATE)
-
-/**
- * Call {@link SafetyCenterManager#getSafetySourceData} adopting Shell's
- * {@link SEND_SAFETY_CENTER_UPDATE} permission.
- */
-fun SafetyCenterManager.getSafetySourceDataWithPermission(id: String): SafetySourceData? =
- callWithShellPermissionIdentity({
- getSafetySourceData(id)
- }, SEND_SAFETY_CENTER_UPDATE)
-
-/**
- * Call {@link SafetyCenterManager#isSafetyCenterEnabled} adopting Shell's
- * {@link SEND_SAFETY_CENTER_UPDATE} permission.
- */
-fun SafetyCenterManager.isSafetyCenterEnabledWithPermission(): Boolean =
- callWithShellPermissionIdentity({
- isSafetyCenterEnabled
- }, SEND_SAFETY_CENTER_UPDATE)
-
-/**
- * Call {@link SafetyCenterManager#refreshSafetySources} adopting Shell's
- * {@link MANAGE_SAFETY_CENTER} permission (required for
- * {@link SafetyCenterManager#refreshSafetySources}).
- */
-fun SafetyCenterManager.refreshSafetySourcesWithPermission(refreshReason: Int) =
- runWithShellPermissionIdentity({
- refreshSafetySources(refreshReason)
- }, MANAGE_SAFETY_CENTER)
-
-fun SafetyCenterManager.getSafetyCenterDataWithPermission(): SafetyCenterData =
- runWithShellPermissionIdentity(::getSafetyCenterData, MANAGE_SAFETY_CENTER)
-
-fun SafetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- executor: Executor,
- listener: OnSafetyCenterDataChangedListener
-) =
- runWithShellPermissionIdentity({
- addOnSafetyCenterDataChangedListener(executor, listener)
- }, MANAGE_SAFETY_CENTER)
-
-fun SafetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(
- listener: OnSafetyCenterDataChangedListener
-) =
- runWithShellPermissionIdentity({
- removeOnSafetyCenterDataChangedListener(listener)
- }, MANAGE_SAFETY_CENTER)
-
-/**
- * Call {@link SafetyCenterManager#clearAllSafetySourceData} adopting Shell's
- * {@link MANAGE_SAFETY_CENTER} permission.
- */
-fun SafetyCenterManager.clearAllSafetySourceDataWithPermission() =
- runWithShellPermissionIdentity({
- clearAllSafetySourceData()
- }, MANAGE_SAFETY_CENTER)
-
-fun SafetyCenterManager.setSafetyCenterConfigOverrideWithPermission(
- safetyCenterConfig: SafetyCenterConfig
-) =
- runWithShellPermissionIdentity({
- setSafetyCenterConfigOverride(safetyCenterConfig)
- }, MANAGE_SAFETY_CENTER)
-
-fun SafetyCenterManager.clearSafetyCenterConfigOverrideWithPermission() =
- runWithShellPermissionIdentity({
- clearSafetyCenterConfigOverride()
- }, MANAGE_SAFETY_CENTER)
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt
deleted file mode 100644
index 5d3df89..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.app.PendingIntent
-import android.content.Context
-import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.os.Parcel
-import android.safetycenter.SafetyCenterData
-import android.safetycenter.SafetyCenterEntry
-import android.safetycenter.SafetyCenterEntryGroup
-import android.safetycenter.SafetyCenterEntryOrGroup
-import android.safetycenter.SafetyCenterIssue
-import android.safetycenter.SafetyCenterStaticEntry
-import android.safetycenter.SafetyCenterStaticEntryGroup
-import android.safetycenter.SafetyCenterStatus
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetyCenterDataTest {
- private val context: Context = ApplicationProvider.getApplicationContext()
-
- private val pendingIntent = PendingIntent.getActivity(
- context,
- /* requestCode= */ 0,
- Intent("Fake Data"),
- PendingIntent.FLAG_IMMUTABLE)
-
- val status1 = SafetyCenterStatus.Builder()
- .setTitle("This is my title")
- .setSummary("This is my summary")
- .setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION)
- .build()
- val status2 = SafetyCenterStatus.Builder()
- .setTitle("This is also my title")
- .setSummary("This is also my summary")
- .setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK)
- .build()
-
- val issue1 = SafetyCenterIssue.Builder("iSsUe_iD_oNe")
- .setTitle("An issue title")
- .setSummary("An issue summary")
- .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK)
- .build()
- val issue2 = SafetyCenterIssue.Builder("iSsUe_iD_tWo")
- .setTitle("Another issue title")
- .setSummary("Another issue summary")
- .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION)
- .build()
-
- val entry1 = SafetyCenterEntry.Builder("eNtRy_iD_OnE")
- .setTitle("An entry title")
- .setPendingIntent(pendingIntent)
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
- .build()
- val entry2 = SafetyCenterEntry.Builder("eNtRy_iD_TwO")
- .setTitle("Another entry title")
- .setPendingIntent(pendingIntent)
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
- .build()
-
- val entryGroup1 = SafetyCenterEntryGroup.Builder("eNtRy_gRoUp_iD")
- .setTitle("An entry group title")
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
- .setEntries(listOf(entry2))
- .build()
-
- val entryOrGroup1 = SafetyCenterEntryOrGroup(entry1)
- val entryOrGroup2 = SafetyCenterEntryOrGroup(entryGroup1)
-
- val staticEntry1 = SafetyCenterStaticEntry(
- "A static entry title",
- "A static entry summary",
- pendingIntent)
- val staticEntry2 = SafetyCenterStaticEntry(
- "Another static entry title",
- "Another static entry summary",
- pendingIntent)
-
- val staticEntryGroup1 = SafetyCenterStaticEntryGroup(
- "A static entry group title", listOf(staticEntry1))
- val staticEntryGroup2 = SafetyCenterStaticEntryGroup(
- "Another static entry group title", listOf(staticEntry2))
-
- val data1 = SafetyCenterData(
- status1, listOf(issue1), listOf(entryOrGroup1), listOf(staticEntryGroup1))
- val data2 = SafetyCenterData(
- status2, listOf(issue2), listOf(entryOrGroup2), listOf(staticEntryGroup2))
-
- @Test
- fun getStatus_returnsStatus() {
- assertThat(data1.status).isEqualTo(status1)
- assertThat(data2.status).isEqualTo(status2)
- }
-
- @Test
- fun getIssues_returnsIssues() {
- assertThat(data1.issues).containsExactly(issue1)
- assertThat(data2.issues).containsExactly(issue2)
- }
-
- @Test
- fun getIssues_mutationsAreNotReflected() {
- val mutatedIssues = data1.issues
- mutatedIssues.add(issue2)
-
- assertThat(mutatedIssues).containsExactly(issue1, issue2)
- assertThat(data1.issues).doesNotContain(issue2)
- }
-
- @Test
- fun getEntriesOrGroups_returnsEntriesOrGroups() {
- assertThat(data1.entriesOrGroups).containsExactly(entryOrGroup1)
- assertThat(data2.entriesOrGroups).containsExactly(entryOrGroup2)
- }
-
- @Test
- fun getEntriesOrGroups_mutationsAreNotReflected() {
- val mutatedEntriesOrGroups = data1.entriesOrGroups
- mutatedEntriesOrGroups.add(entryOrGroup2)
-
- assertThat(mutatedEntriesOrGroups).containsExactly(entryOrGroup1, entryOrGroup2)
- assertThat(data1.entriesOrGroups).doesNotContain(entryOrGroup2)
- }
-
- @Test
- fun getStaticEntryGroups_returnsStaticEntryGroups() {
- assertThat(data1.staticEntryGroups).containsExactly(staticEntryGroup1)
- assertThat(data2.staticEntryGroups).containsExactly(staticEntryGroup2)
- }
-
- @Test
- fun getStaticEntryGroups_mutationsAreNotReflected() {
- val mutatedStaticEntryGroups = data1.staticEntryGroups
- mutatedStaticEntryGroups.add(staticEntryGroup2)
-
- assertThat(mutatedStaticEntryGroups).containsExactly(staticEntryGroup1, staticEntryGroup2)
- assertThat(data1.staticEntryGroups).doesNotContain(staticEntryGroup2)
- }
-
- @Test
- fun describeContents_returns0() {
- assertThat(data1.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsEquivalentObject() {
- val parcel: Parcel = Parcel.obtain()
-
- data1.writeToParcel(parcel, 0 /* flags */)
- parcel.setDataPosition(0)
- val fromParcel = SafetyCenterData.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(fromParcel).isEqualTo(data1)
- }
-
- @Test
- fun equals_hashCode_toString_equalByReference_areEqual() {
- assertThat(data1).isEqualTo(data1)
- assertThat(data1.hashCode()).isEqualTo(data1.hashCode())
- assertThat(data1.toString()).isEqualTo(data1.toString())
- }
-
- @Test
- fun equals_hashCode_toString_equalByValue_areEqual() {
- val data = SafetyCenterData(
- status1, listOf(issue1), listOf(entryOrGroup1), listOf(staticEntryGroup1))
- val equivalentData = SafetyCenterData(
- status1, listOf(issue1), listOf(entryOrGroup1), listOf(staticEntryGroup1))
-
- assertThat(data).isEqualTo(equivalentData)
- assertThat(data.hashCode()).isEqualTo(equivalentData.hashCode())
- assertThat(data.toString()).isEqualTo(equivalentData.toString())
- }
-
- @Test
- fun equals_hashCode_toString_withEmptyLists_equalByValue_areEqual() {
- val data = SafetyCenterData(status1, listOf(), listOf(), listOf())
- val equivalentData = SafetyCenterData(status1, listOf(), listOf(), listOf())
-
- assertThat(data).isEqualTo(equivalentData)
- assertThat(data.hashCode()).isEqualTo(equivalentData.hashCode())
- assertThat(data.toString()).isEqualTo(equivalentData.toString())
- }
-
- @Test
- fun equals_toString_withDifferentStatuses_areNotEqual() {
- val data = SafetyCenterData(
- status1, listOf(issue1), listOf(entryOrGroup1), listOf(staticEntryGroup1))
- val differentData = SafetyCenterData(
- status2, listOf(issue1), listOf(entryOrGroup1), listOf(staticEntryGroup1))
-
- assertThat(data).isNotEqualTo(differentData)
- assertThat(data.toString()).isNotEqualTo(differentData.toString())
- }
-
- @Test
- fun equals_toString_withDifferentIssues_areNotEqual() {
- val data = SafetyCenterData(
- status1, listOf(issue1), listOf(entryOrGroup1), listOf(staticEntryGroup1))
- val differentData = SafetyCenterData(
- status1, listOf(issue2), listOf(entryOrGroup1), listOf(staticEntryGroup1))
-
- assertThat(data).isNotEqualTo(differentData)
- assertThat(data.toString()).isNotEqualTo(differentData.toString())
- }
-
- @Test
- fun equals_toString_withDifferentEntriesOrGroups_areNotEqual() {
- val data = SafetyCenterData(
- status1, listOf(issue1), listOf(entryOrGroup1), listOf(staticEntryGroup1))
- val differentData = SafetyCenterData(
- status1, listOf(issue1), listOf(entryOrGroup2), listOf(staticEntryGroup1))
-
- assertThat(data).isNotEqualTo(differentData)
- assertThat(data.toString()).isNotEqualTo(differentData.toString())
- }
-
- @Test
- fun equals_toString_withDifferentStaticEntryGroups_areNotEqual() {
- val data = SafetyCenterData(
- status1, listOf(issue1), listOf(entryOrGroup1), listOf(staticEntryGroup1))
- val differentData = SafetyCenterData(
- status1, listOf(issue1), listOf(entryOrGroup1), listOf(staticEntryGroup2))
-
- assertThat(data).isNotEqualTo(differentData)
- assertThat(data.toString()).isNotEqualTo(differentData.toString())
- }
-}
\ No newline at end of file
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryGroupTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryGroupTest.kt
deleted file mode 100644
index 4140e40..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryGroupTest.kt
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.app.PendingIntent
-import android.content.Context
-import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.os.Parcel
-import android.safetycenter.SafetyCenterEntry
-import android.safetycenter.SafetyCenterEntryGroup
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetyCenterEntryGroupTest {
- private val context: Context = ApplicationProvider.getApplicationContext()
-
- private val pendingIntent = PendingIntent.getActivity(
- context,
- /* requestCode= */ 0,
- Intent("Fake Data"),
- PendingIntent.FLAG_IMMUTABLE)
-
- val entry1 = SafetyCenterEntry.Builder("eNtRy_iD_OnE")
- .setTitle("An entry title")
- .setPendingIntent(pendingIntent)
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
- .build()
- val entry2 = SafetyCenterEntry.Builder("eNtRy_iD_TwO")
- .setTitle("Another entry title")
- .setPendingIntent(pendingIntent)
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
- .build()
-
- val groupId1 = "gRoUp_iD_oNe"
- val groupId2 = "gRoUp_iD_tWo"
-
- val entryGroup1 = SafetyCenterEntryGroup.Builder(groupId1)
- .setTitle("A group title")
- .setSummary("A group summary")
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
- .setEntries(listOf(entry1))
- .build()
- val entryGroup2 = SafetyCenterEntryGroup.Builder(groupId2)
- .setTitle("Another group title")
- .setSummary("Another group summary")
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
- .setEntries(listOf(entry2))
- .build()
-
- @Test
- fun getId_returnsId() {
- assertThat(entryGroup1.id).isEqualTo(groupId1)
- assertThat(entryGroup2.id).isEqualTo(groupId2)
- }
-
- @Test
- fun getTitle_returnsTitle() {
- assertThat(SafetyCenterEntryGroup.Builder(entryGroup1).setTitle("title one").build().title)
- .isEqualTo("title one")
- assertThat(SafetyCenterEntryGroup.Builder(entryGroup1).setTitle("title two").build().title)
- .isEqualTo("title two")
- }
-
- @Test
- fun getSummary_returnsSummary() {
- assertThat(SafetyCenterEntryGroup.Builder(entryGroup1).setSummary("one").build().summary)
- .isEqualTo("one")
- assertThat(SafetyCenterEntryGroup.Builder(entryGroup1).setSummary("two").build().summary)
- .isEqualTo("two")
- assertThat(SafetyCenterEntryGroup.Builder(entryGroup1).setSummary(null).build().summary)
- .isNull()
- }
-
- @Test
- fun getSeverityLevel_returnsSeverityLevel() {
- assertThat(SafetyCenterEntryGroup.Builder(entryGroup1)
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
- .build()
- .severityLevel)
- .isEqualTo(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
- assertThat(SafetyCenterEntryGroup.Builder(entryGroup1)
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_NONE)
- .build()
- .severityLevel)
- .isEqualTo(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_NONE)
- }
-
- @Test
- fun getSeverityNoneIconType_returnsSeverityNoneIconType() {
- assertThat(entryGroup1.severityNoneIconType)
- .isEqualTo(SafetyCenterEntry.SEVERITY_NONE_ICON_TYPE_NO_ICON)
- assertThat(SafetyCenterEntryGroup.Builder(entryGroup1)
- .setSeverityNoneIconType(SafetyCenterEntry.SEVERITY_NONE_ICON_TYPE_PRIVACY)
- .build()
- .severityNoneIconType)
- .isEqualTo(SafetyCenterEntry.SEVERITY_NONE_ICON_TYPE_PRIVACY)
- }
-
- @Test
- fun getEntries_returnsEntries() {
- assertThat(entryGroup1.entries).containsExactly(entry1)
- assertThat(entryGroup2.entries).containsExactly(entry2)
- }
-
- @Test
- fun getEntries_mutationsAreNotReflected() {
- val mutatedEntries = entryGroup1.entries
- mutatedEntries.add(entry2)
-
- assertThat(mutatedEntries).containsExactly(entry1, entry2)
- assertThat(entryGroup1.entries).doesNotContain(entry2)
- }
-
- @Test
- fun describeContents_returns0() {
- assertThat(entryGroup1.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsEquivalentObject() {
- val parcel = Parcel.obtain()
-
- entryGroup1.writeToParcel(parcel, /* flags= */ 0)
- parcel.setDataPosition(0)
-
- val fromParcel = SafetyCenterEntryGroup.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(fromParcel).isEqualTo(entryGroup1)
- }
-
- @Test
- fun equals_hashCode_toString_equalByReference_areEqual() {
- assertThat(entryGroup1).isEqualTo(entryGroup1)
- assertThat(entryGroup1.hashCode()).isEqualTo(entryGroup1.hashCode())
- assertThat(entryGroup1.toString()).isEqualTo(entryGroup1.toString())
- }
-
- @Test
- fun equals_hashCode_toString_equalByValue_areEqual() {
- val entry = SafetyCenterEntryGroup.Builder(groupId1)
- .setTitle("A group title")
- .setSummary("A group summary")
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
- .setEntries(listOf(entry1))
- .build()
- val equivalentEntry = SafetyCenterEntryGroup.Builder(groupId1)
- .setTitle("A group title")
- .setSummary("A group summary")
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
- .setEntries(listOf(entry1))
- .build()
-
- assertThat(entry).isEqualTo(equivalentEntry)
- assertThat(entry.hashCode()).isEqualTo(equivalentEntry.hashCode())
- assertThat(entry.toString()).isEqualTo(equivalentEntry.toString())
- }
-
- @Test
- fun equals_hashCode_toString_fromCopyBuilder_areEqual() {
- val equivalentToEntryGroup1 = SafetyCenterEntryGroup.Builder(entryGroup1).build()
-
- assertThat(equivalentToEntryGroup1).isEqualTo(entryGroup1)
- assertThat(equivalentToEntryGroup1.hashCode()).isEqualTo(entryGroup1.hashCode())
- assertThat(equivalentToEntryGroup1.toString()).isEqualTo(entryGroup1.toString())
- }
-
- @Test
- fun equals_toString_withDifferentIds_areNotEqual() {
- val differentFromEntryGroup1 = SafetyCenterEntryGroup.Builder(entryGroup1)
- .setId("different!")
- .build()
-
- assertThat(differentFromEntryGroup1).isNotEqualTo(entryGroup1)
- assertThat(differentFromEntryGroup1.toString()).isNotEqualTo(entryGroup1.toString())
- }
-
- @Test
- fun equals_toString_withDifferentTitles_areNotEqual() {
- val differentFromEntryGroup1 = SafetyCenterEntryGroup.Builder(entryGroup1)
- .setTitle("different!")
- .build()
-
- assertThat(differentFromEntryGroup1).isNotEqualTo(entryGroup1)
- assertThat(differentFromEntryGroup1.toString()).isNotEqualTo(entryGroup1.toString())
- }
-
- @Test
- fun equals_toString_withDifferentSummaries_areNotEqual() {
- val differentFromEntryGroup1 = SafetyCenterEntryGroup.Builder(entryGroup1)
- .setSummary("different!")
- .build()
-
- assertThat(differentFromEntryGroup1).isNotEqualTo(entryGroup1)
- assertThat(differentFromEntryGroup1.toString()).isNotEqualTo(entryGroup1.toString())
- }
-
- @Test
- fun equals_toString_withDifferentSeverityLevels_areNotEqual() {
- val differentFromEntryGroup1 = SafetyCenterEntryGroup.Builder(entryGroup1)
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN)
- .build()
-
- assertThat(differentFromEntryGroup1).isNotEqualTo(entryGroup1)
- assertThat(differentFromEntryGroup1.toString()).isNotEqualTo(entryGroup1.toString())
- }
-
- @Test
- fun equals_toString_withDifferentSeverityNoneIconTypes_areNotEqual() {
- val differentFromEntryGroup1 = SafetyCenterEntryGroup.Builder(entryGroup1)
- .setSeverityNoneIconType(SafetyCenterEntry.SEVERITY_NONE_ICON_TYPE_PRIVACY)
- .build()
-
- assertThat(differentFromEntryGroup1).isNotEqualTo(entryGroup1)
- assertThat(differentFromEntryGroup1.toString()).isNotEqualTo(entryGroup1.toString())
- }
-
- @Test
- fun equals_toString_withDifferentEntries_areNotEqual() {
- val differentFromEntryGroup1 = SafetyCenterEntryGroup.Builder(entryGroup1)
- .setEntries(listOf(entry2))
- .build()
-
- assertThat(differentFromEntryGroup1).isNotEqualTo(entryGroup1)
- assertThat(differentFromEntryGroup1.toString()).isNotEqualTo(entryGroup1.toString())
- }
-
- @Test
- fun equals_toString_withDifferentEntries_emptyList_areNotEqual() {
- val differentFromEntryGroup1 = SafetyCenterEntryGroup.Builder(entryGroup1)
- .setEntries(listOf())
- .build()
-
- assertThat(differentFromEntryGroup1).isNotEqualTo(entryGroup1)
- assertThat(differentFromEntryGroup1.toString()).isNotEqualTo(entryGroup1.toString())
- }
-}
\ No newline at end of file
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryOrGroupTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryOrGroupTest.kt
deleted file mode 100644
index 193643b..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryOrGroupTest.kt
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.app.PendingIntent
-import android.content.Context
-import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.os.Parcel
-import android.safetycenter.SafetyCenterEntry
-import android.safetycenter.SafetyCenterEntryGroup
-import android.safetycenter.SafetyCenterEntryOrGroup
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetyCenterEntryOrGroupTest {
- private val context: Context = ApplicationProvider.getApplicationContext()
-
- private val pendingIntent = PendingIntent.getActivity(
- context,
- /* requestCode= */ 0,
- Intent("Fake Data"),
- PendingIntent.FLAG_IMMUTABLE)
-
- val entry1 = SafetyCenterEntry.Builder("eNtRy_iD_OnE")
- .setTitle("An entry title")
- .setPendingIntent(pendingIntent)
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
- .build()
- val entry2 = SafetyCenterEntry.Builder("eNtRy_iD_TwO")
- .setTitle("Another entry title")
- .setPendingIntent(pendingIntent)
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
- .build()
-
- val entryGroup1 = SafetyCenterEntryGroup.Builder("gRoUp_iD_oNe")
- .setTitle("A group title")
- .setSummary("A group summary")
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
- .setEntries(listOf(entry1))
- .build()
- val entryGroup2 = SafetyCenterEntryGroup.Builder("gRoUp_iD_tWo")
- .setTitle("Another group title")
- .setSummary("Another group summary")
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
- .setEntries(listOf(entry2))
- .build()
-
- val entryOrGroupWithEntry = SafetyCenterEntryOrGroup(entry1)
- val entryOrGroupWithGroup = SafetyCenterEntryOrGroup(entryGroup1)
-
- @Test
- fun getEntry_returnsEntry() {
- assertThat(entryOrGroupWithEntry.entry).isEqualTo(entry1)
- }
-
- @Test
- fun getEntry_returnsEntry_whenNull() {
- assertThat(entryOrGroupWithGroup.entry).isNull()
- }
-
- @Test
- fun getEntryGroup_returnsEntryGroup() {
- assertThat(entryOrGroupWithGroup.entryGroup).isEqualTo(entryGroup1)
- }
-
- @Test
- fun getEntryGroup_returnsEntryGroup_whenNull() {
- assertThat(entryOrGroupWithEntry.entryGroup).isNull()
- }
-
- @Test
- fun describeContents_returns0() {
- assertThat(entryOrGroupWithEntry.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_withEntry_returnsEquivalentObject() {
- runCreateFromParcel_withWriteToParcel_withGroup_returnsEquivalentObjectTest(
- entryOrGroupWithEntry)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_withGroup_returnsEquivalentObject() {
- runCreateFromParcel_withWriteToParcel_withGroup_returnsEquivalentObjectTest(
- entryOrGroupWithGroup)
- }
-
- fun runCreateFromParcel_withWriteToParcel_withGroup_returnsEquivalentObjectTest(
- entryOrGroup: SafetyCenterEntryOrGroup
- ) {
- val parcel: Parcel = Parcel.obtain()
-
- entryOrGroup.writeToParcel(parcel, 0 /* flags */)
- parcel.setDataPosition(0)
- val fromParcel = SafetyCenterEntryOrGroup.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(fromParcel).isEqualTo(entryOrGroup)
- }
-
- @Test
- fun equals_hashCode_toString_whenEqualByReference_areEqual() {
- assertThat(entryOrGroupWithEntry).isEqualTo(entryOrGroupWithEntry)
- assertThat(entryOrGroupWithEntry.hashCode()).isEqualTo(entryOrGroupWithEntry.hashCode())
- assertThat(entryOrGroupWithEntry.toString()).isEqualTo(entryOrGroupWithEntry.toString())
- }
-
- @Test
- fun equals_hashCode_toString_whenEqualByValue_withEntry_areEqual() {
- val entryOrGroup = SafetyCenterEntryOrGroup(entry1)
- val equivalentEntryOrGroup = SafetyCenterEntryOrGroup(entry1)
-
- assertThat(entryOrGroup).isEqualTo(equivalentEntryOrGroup)
- assertThat(entryOrGroup.hashCode()).isEqualTo(equivalentEntryOrGroup.hashCode())
- assertThat(entryOrGroup.toString()).isEqualTo(equivalentEntryOrGroup.toString())
- }
-
- @Test
- fun equals_hashCode_toString_whenEqualByValue_withGroup_areEqual() {
- val entryOrGroup = SafetyCenterEntryOrGroup(entryGroup1)
- val equivalentEntryOrGroup = SafetyCenterEntryOrGroup(entryGroup1)
-
- assertThat(entryOrGroup).isEqualTo(equivalentEntryOrGroup)
- assertThat(entryOrGroup.hashCode()).isEqualTo(equivalentEntryOrGroup.hashCode())
- assertThat(entryOrGroup.toString()).isEqualTo(equivalentEntryOrGroup.toString())
- }
-
- @Test
- fun equals_toString_withDifferentEntryAndGroup_areNotEqual() {
- assertThat(entryOrGroupWithEntry).isNotEqualTo(entryOrGroupWithGroup)
- assertThat(entryOrGroupWithEntry.toString()).isNotEqualTo(entryOrGroupWithGroup.toString())
- }
-
- @Test
- fun equals_toString_withDifferentEntries_areNotEqual() {
- val entryOrGroup = SafetyCenterEntryOrGroup(entry1)
- val differentEntryOrGroup = SafetyCenterEntryOrGroup(entry2)
-
- assertThat(entryOrGroup).isNotEqualTo(differentEntryOrGroup)
- assertThat(entryOrGroup.toString()).isNotEqualTo(differentEntryOrGroup.toString())
- }
-
- @Test
- fun equals_toString_withDifferentGroups_areNotEqual() {
- val entryOrGroup = SafetyCenterEntryOrGroup(entryGroup1)
- val differentEntryOrGroup = SafetyCenterEntryOrGroup(entryGroup2)
-
- assertThat(entryOrGroup).isNotEqualTo(differentEntryOrGroup)
- assertThat(entryOrGroup.toString()).isNotEqualTo(differentEntryOrGroup.toString())
- }
-}
\ No newline at end of file
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryTest.kt
deleted file mode 100644
index 94fea00..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryTest.kt
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.app.PendingIntent
-import android.content.Context
-import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.os.Parcel
-import android.safetycenter.SafetyCenterEntry
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetyCenterEntryTest {
- private val context: Context = ApplicationProvider.getApplicationContext()
-
- private val pendingIntent1 = PendingIntent.getActivity(
- context,
- /* requestCode= */ 0,
- Intent("Fake Data"),
- PendingIntent.FLAG_IMMUTABLE)
- private val pendingIntent2 = PendingIntent.getActivity(
- context,
- /* requestCode= */ 0,
- Intent("Fake Different Data"),
- PendingIntent.FLAG_IMMUTABLE)
-
- private val iconAction1 = SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, pendingIntent1)
- private val iconAction2 = SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, pendingIntent2)
-
- private val entry1 = SafetyCenterEntry.Builder("eNtRy_iD")
- .setTitle("a title")
- .setSummary("a summary")
- .setPendingIntent(pendingIntent1)
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN)
- .setIconAction(iconAction1)
- .build()
-
- @Test
- fun getId_returnsId() {
- assertThat(SafetyCenterEntry.Builder(entry1).setId("id_one").build().id)
- .isEqualTo("id_one")
- assertThat(SafetyCenterEntry.Builder(entry1).setId("id_two").build().id)
- .isEqualTo("id_two")
- }
-
- @Test
- fun getTitle_returnsTitle() {
- assertThat(SafetyCenterEntry.Builder(entry1).setTitle("a title").build().title)
- .isEqualTo("a title")
- assertThat(SafetyCenterEntry.Builder(entry1).setTitle("another title").build().title)
- .isEqualTo("another title")
- }
-
- @Test
- fun getSummary_returnsSummary() {
- assertThat(SafetyCenterEntry.Builder(entry1).setSummary("a summary").build().summary)
- .isEqualTo("a summary")
- assertThat(SafetyCenterEntry.Builder(entry1).setSummary("another summary").build().summary)
- .isEqualTo("another summary")
- assertThat(SafetyCenterEntry.Builder(entry1).setSummary(null).build().summary)
- .isNull()
- }
-
- @Test
- fun getSeverityLevel_returnsSeverityLevel() {
- assertThat(SafetyCenterEntry.Builder(entry1)
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
- .build()
- .severityLevel)
- .isEqualTo(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
- assertThat(SafetyCenterEntry.Builder(entry1)
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
- .build()
- .severityLevel)
- .isEqualTo(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
- }
-
- @Test
- fun getSeverityNoneIconType_returnsSeverityNoneIconType() {
- assertThat(entry1.severityNoneIconType).isEqualTo(
- SafetyCenterEntry.SEVERITY_NONE_ICON_TYPE_NO_ICON)
- assertThat(SafetyCenterEntry.Builder(entry1)
- .setSeverityNoneIconType(SafetyCenterEntry.SEVERITY_NONE_ICON_TYPE_PRIVACY)
- .build()
- .severityNoneIconType)
- .isEqualTo(SafetyCenterEntry.SEVERITY_NONE_ICON_TYPE_PRIVACY)
- }
-
- @Test
- fun isEnabled_returnsIsEnabled() {
- assertThat(SafetyCenterEntry.Builder(entry1).setEnabled(true).build().isEnabled)
- .isTrue()
- assertThat(SafetyCenterEntry.Builder(entry1).setEnabled(false).build().isEnabled)
- .isFalse()
- }
-
- @Test
- fun isEnabled_defaultTrue() {
- assertThat(SafetyCenterEntry.Builder("eNtRy_iD")
- .setTitle("a title")
- .setPendingIntent(pendingIntent1)
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN)
- .build()
- .isEnabled)
- .isTrue()
- }
-
- @Test
- fun getPendingIntent_returnsPendingIntent() {
- assertThat(SafetyCenterEntry.Builder(entry1)
- .setPendingIntent(pendingIntent1)
- .build()
- .pendingIntent)
- .isEqualTo(pendingIntent1)
- assertThat(SafetyCenterEntry.Builder(entry1)
- .setPendingIntent(pendingIntent2)
- .build()
- .pendingIntent)
- .isEqualTo(pendingIntent2)
- }
-
- @Test
- fun getIconAction_returnsIconAction() {
- assertThat(SafetyCenterEntry.Builder(entry1).setIconAction(iconAction1).build().iconAction)
- .isEqualTo(iconAction1)
- assertThat(SafetyCenterEntry.Builder(entry1).setIconAction(iconAction2).build().iconAction)
- .isEqualTo(iconAction2)
- assertThat(SafetyCenterEntry.Builder(entry1).setIconAction(null).build().iconAction)
- .isNull()
- }
-
- @Test
- fun describeContents_returns0() {
- assertThat(entry1.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsEquivalentObject() {
- val parcel = Parcel.obtain()
-
- entry1.writeToParcel(parcel, /* flags= */ 0)
- parcel.setDataPosition(0)
-
- val fromParcel = SafetyCenterEntry.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(fromParcel).isEqualTo(entry1)
- }
-
- @Test
- fun equals_hashCode_toString_equalByReference_areEqual() {
- assertThat(entry1).isEqualTo(entry1)
- assertThat(entry1.hashCode()).isEqualTo(entry1.hashCode())
- assertThat(entry1.toString()).isEqualTo(entry1.toString())
- }
-
- @Test
- fun equals_hashCode_toString_equalByValue_areEqual() {
- val entry = SafetyCenterEntry.Builder("id")
- .setTitle("a title")
- .setSummary("a summary")
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
- .setSeverityNoneIconType(SafetyCenterEntry.SEVERITY_NONE_ICON_TYPE_PRIVACY)
- .setPendingIntent(pendingIntent1)
- .setIconAction(SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, pendingIntent2)
- .build()
- val equivalentEntry = SafetyCenterEntry.Builder("id")
- .setTitle("a title")
- .setSummary("a summary")
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK)
- .setSeverityNoneIconType(SafetyCenterEntry.SEVERITY_NONE_ICON_TYPE_PRIVACY)
- .setPendingIntent(pendingIntent1)
- .setIconAction(SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, pendingIntent2)
- .build()
-
- assertThat(entry).isEqualTo(equivalentEntry)
- assertThat(entry.hashCode()).isEqualTo(equivalentEntry.hashCode())
- assertThat(entry.toString()).isEqualTo(equivalentEntry.toString())
- }
-
- @Test
- fun equals_hashCode_toString_fromCopyBuilder_areEqual() {
- val copyOfEntry1 = SafetyCenterEntry.Builder(entry1).build()
-
- assertThat(copyOfEntry1).isEqualTo(entry1)
- assertThat(copyOfEntry1.hashCode()).isEqualTo(entry1.hashCode())
- assertThat(copyOfEntry1.toString()).isEqualTo(entry1.toString())
- }
-
- @Test
- fun equals_toString_withDifferentIds_areNotEqual() {
- val differentFromEntry1 = SafetyCenterEntry.Builder(entry1)
- .setId("a different id")
- .build()
-
- assertThat(differentFromEntry1).isNotEqualTo(entry1)
- assertThat(differentFromEntry1.toString()).isNotEqualTo(entry1.toString())
- }
-
- @Test
- fun equals_toString_withDifferentTitles_areNotEqual() {
- val differentFromEntry1 = SafetyCenterEntry.Builder(entry1)
- .setTitle("a different title")
- .build()
-
- assertThat(differentFromEntry1).isNotEqualTo(entry1)
- assertThat(differentFromEntry1.toString()).isNotEqualTo(entry1.toString())
- }
-
- @Test
- fun equals_toString_withDifferentSummaries_areNotEqual() {
- val differentFromEntry1 = SafetyCenterEntry.Builder(entry1)
- .setSummary("a different summary")
- .build()
-
- assertThat(differentFromEntry1).isNotEqualTo(entry1)
- assertThat(differentFromEntry1.toString()).isNotEqualTo(entry1.toString())
- }
-
- @Test
- fun equals_toString_withDifferentSeverityLevels_areNotEqual() {
- val differentFromEntry1 = SafetyCenterEntry.Builder(entry1)
- .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING)
- .build()
-
- assertThat(differentFromEntry1).isNotEqualTo(entry1)
- assertThat(differentFromEntry1.toString()).isNotEqualTo(entry1.toString())
- }
-
- @Test
- fun equals_toString_withDifferentSeverityNoneIconTypes_areNotEqual() {
- val differentFromEntry1 = SafetyCenterEntry.Builder(entry1)
- .setSeverityNoneIconType(SafetyCenterEntry.SEVERITY_NONE_ICON_TYPE_PRIVACY)
- .build()
-
- assertThat(differentFromEntry1).isNotEqualTo(entry1)
- assertThat(differentFromEntry1.toString()).isNotEqualTo(entry1.toString())
- }
-
- @Test
- fun equals_toString_withDifferentEnabledValues_areNotEqual() {
- val differentFromEntry1 = SafetyCenterEntry.Builder(entry1)
- .setEnabled(false)
- .build()
-
- assertThat(differentFromEntry1).isNotEqualTo(entry1)
- assertThat(differentFromEntry1.toString()).isNotEqualTo(entry1.toString())
- }
-
- @Test
- fun equals_toString_withDifferentPendingIntents_areNotEqual() {
- val differentFromEntry1 = SafetyCenterEntry.Builder(entry1)
- .setPendingIntent(pendingIntent2)
- .build()
-
- assertThat(differentFromEntry1).isNotEqualTo(entry1)
- assertThat(differentFromEntry1.toString()).isNotEqualTo(entry1.toString())
- }
-
- @Test
- fun equals_toString_withDifferentIconActions_areNotEqual() {
- val differentFromEntry1 = SafetyCenterEntry.Builder(entry1)
- .setIconAction(iconAction2)
- .build()
-
- assertThat(differentFromEntry1).isNotEqualTo(entry1)
- assertThat(differentFromEntry1.toString()).isNotEqualTo(entry1.toString())
- }
-
- @Test
- fun iconAction_getType_returnsType() {
- assertThat(SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, pendingIntent1)
- .type)
- .isEqualTo(SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR)
- assertThat(SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, pendingIntent1)
- .type)
- .isEqualTo(SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO)
- }
-
- @Test
- fun iconAction_getPendingIntent_returnsPendingIntent() {
- assertThat(SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, pendingIntent1)
- .pendingIntent)
- .isEqualTo(pendingIntent1)
- assertThat(SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, pendingIntent2)
- .pendingIntent)
- .isEqualTo(pendingIntent2)
- }
-
- @Test
- fun iconAction_describeContents_returns0() {
- assertThat(iconAction1.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun iconAction_createFromParcel_withWriteToParcel_returnsEquivalentObject() {
- val parcel = Parcel.obtain()
-
- iconAction1.writeToParcel(parcel, /* flags= */ 0)
- parcel.setDataPosition(0)
-
- val fromParcel = SafetyCenterEntry.IconAction.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(fromParcel).isEqualTo(iconAction1)
- }
-
- @Test
- fun iconAction_equals_hashCode_toString_equalByReference_areEqual() {
- assertThat(iconAction1).isEqualTo(iconAction1)
- assertThat(iconAction1.hashCode()).isEqualTo(iconAction1.hashCode())
- assertThat(iconAction1.toString()).isEqualTo(iconAction1.toString())
- }
-
- @Test
- fun iconAction_equals_hashCode_toString_equalByValue_areEqual() {
- val iconAction = SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, pendingIntent1)
- val equivalentIconAction = SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, pendingIntent1)
-
- assertThat(iconAction).isEqualTo(equivalentIconAction)
- assertThat(iconAction.hashCode()).isEqualTo(equivalentIconAction.hashCode())
- assertThat(iconAction.toString()).isEqualTo(equivalentIconAction.toString())
- }
-
- @Test
- fun iconAction_equals_toString_differentTypes_areNotEqual() {
- val iconAction = SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, pendingIntent1)
- val differentIconAction = SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, pendingIntent1)
-
- assertThat(iconAction).isNotEqualTo(differentIconAction)
- assertThat(iconAction.toString()).isNotEqualTo(differentIconAction.toString())
- }
-
- @Test
- fun intentAction_equals_toString_differentPendingIntents_areNotEqual() {
- val iconAction = SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, pendingIntent1)
- val differentIconAction = SafetyCenterEntry.IconAction(
- SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, pendingIntent2)
-
- assertThat(iconAction).isNotEqualTo(differentIconAction)
- assertThat(iconAction.toString()).isNotEqualTo(differentIconAction.toString())
- }
-}
\ No newline at end of file
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterErrorTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterErrorTest.kt
deleted file mode 100644
index 06fd6d5..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterErrorTest.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.os.Parcel
-import android.safetycenter.SafetyCenterError
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class SafetyCenterErrorTest {
-
- val error1 = SafetyCenterError("an error message")
- val error2 = SafetyCenterError("another error message")
-
- @Test
- fun getErrorMessage_returnsErrorMessage() {
- assertThat(error1.errorMessage).isEqualTo("an error message")
- assertThat(error2.errorMessage).isEqualTo("another error message")
- }
-
- @Test
- fun describeContents_returns0() {
- assertThat(error1.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsEquivalentObject() {
- val parcel = Parcel.obtain()
-
- error1.writeToParcel(parcel, /* flags= */ 0)
- parcel.setDataPosition(0)
-
- val fromParcel = SafetyCenterError.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(fromParcel).isEqualTo(error1)
- }
-
- @Test
- fun equals_hashCode_toString_equalByReference_areEqual() {
- assertThat(error1).isEqualTo(error1)
- assertThat(error1.hashCode()).isEqualTo(error1.hashCode())
- assertThat(error1.toString()).isEqualTo(error1.toString())
- }
-
- @Test
- fun equals_hashCode_toString_equalByValue_areEqual() {
- val error = SafetyCenterError("an error message")
- val equivalentError = SafetyCenterError("an error message")
-
- assertThat(error).isEqualTo(equivalentError)
- assertThat(error.hashCode()).isEqualTo(equivalentError.hashCode())
- assertThat(error.toString()).isEqualTo(equivalentError.toString())
- }
-
- @Test
- fun equals_toString_withDifferentErrorMessages_areNotEqual() {
- val error = SafetyCenterError("an error message")
- val differentError = SafetyCenterError("a different error message")
-
- assertThat(error).isNotEqualTo(differentError)
- assertThat(error.toString()).isNotEqualTo(differentError.toString())
- }
-}
\ No newline at end of file
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt
deleted file mode 100644
index a842804..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.app.PendingIntent
-import android.content.Context
-import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.os.Parcel
-import android.safetycenter.SafetyCenterIssue
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetyCenterIssueTest {
- private val context: Context = ApplicationProvider.getApplicationContext()
-
- private val pendingIntent1 = PendingIntent.getActivity(
- context,
- /* requestCode= */ 0,
- Intent("Fake Data"),
- PendingIntent.FLAG_IMMUTABLE)
- private val pendingIntent2 = PendingIntent.getActivity(
- context,
- /* requestCode= */ 0,
- Intent("Fake Different Data"),
- PendingIntent.FLAG_IMMUTABLE)
-
- val action1 = SafetyCenterIssue.Action.Builder("action_id_1")
- .setLabel("an action")
- .setPendingIntent(pendingIntent1)
- .setResolving(true)
- .setInFlight(true)
- .setSuccessMessage("a success message")
- .build()
- val action2 = SafetyCenterIssue.Action.Builder("action_id_2")
- .setLabel("another action")
- .setPendingIntent(pendingIntent2)
- .setResolving(false)
- .setInFlight(false)
- .build()
-
- val issue1 = SafetyCenterIssue.Builder("issue_id")
- .setTitle("Everything's good")
- .setSubtitle("In the neighborhood")
- .setSummary("Please acknowledge this")
- .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK)
- .setDismissible(true)
- .setShouldConfirmDismissal(true)
- .setActions(listOf(action1))
- .build()
-
- val issueWithRequiredFieldsOnly = SafetyCenterIssue.Builder("issue_id")
- .setTitle("Everything's good")
- .setSummary("Please acknowledge this")
- .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK)
- .build()
-
- @Test
- fun getId_returnsId() {
- assertThat(SafetyCenterIssue.Builder(issue1).setId("an id").build().id)
- .isEqualTo("an id")
- assertThat(SafetyCenterIssue.Builder(issue1).setId("another id").build().id)
- .isEqualTo("another id")
- }
-
- @Test
- fun getTitle_returnsTitle() {
- assertThat(SafetyCenterIssue.Builder(issue1).setTitle("a title").build().title)
- .isEqualTo("a title")
- assertThat(SafetyCenterIssue.Builder(issue1).setTitle("another title").build().title)
- .isEqualTo("another title")
- }
-
- @Test
- fun getSubtitle_returnsSubtitle() {
- assertThat(SafetyCenterIssue.Builder(issue1).setSubtitle("a subtitle").build().subtitle)
- .isEqualTo("a subtitle")
- assertThat(
- SafetyCenterIssue.Builder(issue1).setSubtitle("another subtitle").build().subtitle)
- .isEqualTo("another subtitle")
- }
-
- @Test
- fun getSummary_returnsSummary() {
- assertThat(SafetyCenterIssue.Builder(issue1).setSummary("a summary").build().summary)
- .isEqualTo("a summary")
- assertThat(SafetyCenterIssue.Builder(issue1).setSummary("another summary").build().summary)
- .isEqualTo("another summary")
- }
-
- @Test
- fun getSeverityLevel_returnsSeverityLevel() {
- assertThat(SafetyCenterIssue.Builder(issue1)
- .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION)
- .build()
- .severityLevel)
- .isEqualTo(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION)
- assertThat(SafetyCenterIssue.Builder(issue1)
- .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING)
- .build()
- .severityLevel)
- .isEqualTo(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING)
- }
-
- @Test
- fun isDismissible_returnsIsDismissible() {
- assertThat(SafetyCenterIssue.Builder(issue1).setDismissible(true).build().isDismissible)
- .isTrue()
- assertThat(SafetyCenterIssue.Builder(issue1).setDismissible(false).build().isDismissible)
- .isFalse()
- }
-
- @Test
- fun isDismissible_defaultsToTrue() {
- assertThat(issueWithRequiredFieldsOnly.isDismissible).isTrue()
- }
-
- @Test
- fun shouldConfirmDismissal_returnsShouldConfirmDismissal() {
- assertThat(SafetyCenterIssue.Builder(issue1)
- .setShouldConfirmDismissal(true)
- .build()
- .shouldConfirmDismissal())
- .isTrue()
- assertThat(SafetyCenterIssue.Builder(issue1)
- .setShouldConfirmDismissal(false)
- .build()
- .shouldConfirmDismissal())
- .isFalse()
- }
-
- @Test
- fun shouldConfirmDismissal_defaultsToTrue() {
- assertThat(issueWithRequiredFieldsOnly.shouldConfirmDismissal()).isTrue()
- }
-
- @Test
- fun getActions_returnsActions() {
- assertThat(SafetyCenterIssue.Builder(issue1)
- .setActions(listOf(action1, action2))
- .build().actions)
- .containsExactly(action1, action2)
- assertThat(SafetyCenterIssue.Builder(issue1).setActions(listOf(action2)).build().actions)
- .containsExactly(action2)
- assertThat(SafetyCenterIssue.Builder(issue1).setActions(listOf()).build().actions)
- .isEmpty()
- }
-
- @Test
- fun getActions_mutationsAreNotReflected() {
- val mutatedActions = issue1.actions
- mutatedActions.add(action2)
-
- assertThat(mutatedActions).containsExactly(action1, action2)
- assertThat(issue1.actions).doesNotContain(action2)
- }
-
- @Test
- fun describeContents_returns0() {
- assertThat(issue1.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsEquivalentObject() {
- val parcel = Parcel.obtain()
-
- issue1.writeToParcel(parcel, /* flags= */ 0)
- parcel.setDataPosition(0)
-
- val fromParcel = SafetyCenterIssue.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(fromParcel).isEqualTo(issue1)
- }
-
- @Test
- fun equals_hashCode_toString_equalByReference_areEqual() {
- assertThat(issue1).isEqualTo(issue1)
- assertThat(issue1.hashCode()).isEqualTo(issue1.hashCode())
- assertThat(issue1.toString()).isEqualTo(issue1.toString())
- }
-
- @Test
- fun equals_hashCode_toString_equalByValue_areEqual() {
- val issue = SafetyCenterIssue.Builder("an id")
- .setTitle("a title")
- .setSubtitle("In the neighborhood")
- .setSummary("Please acknowledge this")
- .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK)
- .setActions(listOf(action1))
- .build()
- val equivalentIssue = SafetyCenterIssue.Builder("an id")
- .setTitle("a title")
- .setSubtitle("In the neighborhood")
- .setSummary("Please acknowledge this")
- .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK)
- .setActions(listOf(action1))
- .build()
-
- assertThat(issue).isEqualTo(equivalentIssue)
- assertThat(issue.hashCode()).isEqualTo(equivalentIssue.hashCode())
- assertThat(issue.toString()).isEqualTo(equivalentIssue.toString())
- }
-
- @Test
- fun equals_hashCode_toString_fromCopyBuilder() {
- val copyOfIssue1 = SafetyCenterIssue.Builder(issue1).build()
-
- assertThat(copyOfIssue1).isEqualTo(issue1)
- assertThat(copyOfIssue1.hashCode()).isEqualTo(issue1.hashCode())
- assertThat(copyOfIssue1.toString()).isEqualTo(issue1.toString())
- }
-
- @Test
- fun equals_toString_differentIds_areNotEqual() {
- val differentFromIssue1 = SafetyCenterIssue.Builder(issue1)
- .setId("a different id")
- .build()
-
- assertThat(differentFromIssue1).isNotEqualTo(issue1)
- assertThat(differentFromIssue1.toString()).isNotEqualTo(issue1.toString())
- }
-
- @Test
- fun equals_toString_differentTitles_areNotEqual() {
- val differentFromIssue1 = SafetyCenterIssue.Builder(issue1)
- .setTitle("a different title")
- .build()
-
- assertThat(differentFromIssue1).isNotEqualTo(issue1)
- assertThat(differentFromIssue1.toString()).isNotEqualTo(issue1.toString())
- }
-
- @Test
- fun equals_toString_differentSubtitles_areNotEqual() {
- val differentFromIssue1 = SafetyCenterIssue.Builder(issue1)
- .setSubtitle("a different subtitle")
- .build()
-
- assertThat(differentFromIssue1).isNotEqualTo(issue1)
- assertThat(differentFromIssue1.toString()).isNotEqualTo(issue1.toString())
- }
-
- @Test
- fun equals_toString_differentSummaries_areNotEqual() {
- val differentFromIssue1 = SafetyCenterIssue.Builder(issue1)
- .setSummary("a different summary")
- .build()
-
- assertThat(differentFromIssue1).isNotEqualTo(issue1)
- assertThat(differentFromIssue1.toString()).isNotEqualTo(issue1.toString())
- }
-
- @Test
- fun equals_toString_differentSeverityLevels_areNotEqual() {
- val differentFromIssue1 = SafetyCenterIssue.Builder(issue1)
- .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING)
- .build()
-
- assertThat(differentFromIssue1).isNotEqualTo(issue1)
- assertThat(differentFromIssue1.toString()).isNotEqualTo(issue1.toString())
- }
-
- @Test
- fun equals_toString_differentIsDismissibleValues_areNotEqual() {
- val differentFromIssue1 = SafetyCenterIssue.Builder(issue1)
- .setDismissible(false)
- .build()
-
- assertThat(differentFromIssue1).isNotEqualTo(issue1)
- assertThat(differentFromIssue1.toString()).isNotEqualTo(issue1.toString())
- }
-
- @Test
- fun equals_toString_differentShouldConfirmDismissalValues_areNotEqual() {
- val differentFromIssue1 = SafetyCenterIssue.Builder(issue1)
- .setShouldConfirmDismissal(false)
- .build()
-
- assertThat(differentFromIssue1).isNotEqualTo(issue1)
- assertThat(differentFromIssue1.toString()).isNotEqualTo(issue1.toString())
- }
-
- @Test
- fun equals_toString_differentActions_areNotEqual() {
- val differentFromIssue1 = SafetyCenterIssue.Builder(issue1)
- .setActions(listOf(action2))
- .build()
-
- assertThat(differentFromIssue1).isNotEqualTo(issue1)
- assertThat(differentFromIssue1.toString()).isNotEqualTo(issue1.toString())
- }
-
- @Test
- fun action_getId_returnsId() {
- assertThat(action1.id).isEqualTo("action_id_1")
- assertThat(action2.id).isEqualTo("action_id_2")
- }
-
- @Test
- fun action_getLabel_returnsLabel() {
- assertThat(action1.label).isEqualTo("an action")
- assertThat(action2.label).isEqualTo("another action")
- }
-
- @Test
- fun action_getPendingIntent_returnsPendingIntent() {
- assertThat(action1.pendingIntent).isEqualTo(pendingIntent1)
- assertThat(action2.pendingIntent).isEqualTo(pendingIntent2)
- }
-
- @Test
- fun action_isResolving_returnsIsResolving() {
- assertThat(action1.isResolving).isTrue()
- assertThat(action2.isResolving).isFalse()
- }
-
- @Test
- fun action_isInFlight_returnsIsInFlight() {
- assertThat(action1.isInFlight).isTrue()
- assertThat(action2.isInFlight).isFalse()
- }
-
- @Test
- fun action_getSuccessMessage_returnsSuccessMessage() {
- assertThat(action1.successMessage).isEqualTo("a success message")
- assertThat(action2.successMessage).isNull()
- }
-
- @Test
- fun action_describeContents_returns0() {
- assertThat(action1.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun action_createFromParcel_withWriteToParcel_returnsEquivalentObject() {
- val parcel = Parcel.obtain()
-
- action1.writeToParcel(parcel, /* flags= */ 0)
-
- parcel.setDataPosition(0)
- val fromParcel = SafetyCenterIssue.Action.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(fromParcel).isEqualTo(action1)
- }
-
- @Test
- fun action_equals_hashCode_toString_equalByReference_areEqual() {
- assertThat(action1).isEqualTo(action1)
- assertThat(action1.hashCode()).isEqualTo(action1.hashCode())
- assertThat(action1.toString()).isEqualTo(action1.toString())
- }
-
- @Test
- fun action_equals_hashCode_toString_equalByValue_areEqual() {
- val action = SafetyCenterIssue.Action.Builder("an_id")
- .setLabel("a label")
- .setPendingIntent(pendingIntent1)
- .setResolving(true)
- .setInFlight(true)
- .setSuccessMessage("a success message")
- .build()
- val equivalentAction = SafetyCenterIssue.Action.Builder("an_id")
- .setLabel("a label")
- .setPendingIntent(pendingIntent1)
- .setResolving(true)
- .setInFlight(true)
- .setSuccessMessage("a success message")
- .build()
-
- assertThat(action).isEqualTo(equivalentAction)
- assertThat(action.toString()).isEqualTo(equivalentAction.toString())
- }
-
- @Test
- fun action_equals_toString_differentIds_areNotEqual() {
- val action = SafetyCenterIssue.Action.Builder("an_id")
- .setLabel("a label")
- .setPendingIntent(pendingIntent1)
- .setSuccessMessage("a success message")
- .build()
- val differentAction = SafetyCenterIssue.Action.Builder("a_different_id")
- .setLabel("a label")
- .setPendingIntent(pendingIntent1)
- .setSuccessMessage("a success message")
- .build()
-
- assertThat(action).isNotEqualTo(differentAction)
- assertThat(action.toString()).isNotEqualTo(differentAction.toString())
- }
-
- @Test
- fun action_equals_toString_differentLabels_areNotEqual() {
- val action = SafetyCenterIssue.Action.Builder("an_id")
- .setLabel("a label")
- .setPendingIntent(pendingIntent1)
- .setSuccessMessage("a success message")
- .build()
- val differentAction = SafetyCenterIssue.Action.Builder("an_id")
- .setLabel("a different label")
- .setPendingIntent(pendingIntent1)
- .setSuccessMessage("a success message")
- .build()
-
- assertThat(action).isNotEqualTo(differentAction)
- assertThat(action.toString()).isNotEqualTo(differentAction.toString())
- }
-
- @Test
- fun action_equals_toString_differentPendingIntents_areNotEqual() {
- val action = SafetyCenterIssue.Action.Builder("an_id")
- .setLabel("a label")
- .setPendingIntent(pendingIntent1)
- .setSuccessMessage("a success message")
- .build()
- val differentAction = SafetyCenterIssue.Action.Builder("an_id")
- .setLabel("a label")
- .setPendingIntent(pendingIntent2)
- .setSuccessMessage("a success message")
- .build()
-
- assertThat(action).isNotEqualTo(differentAction)
- assertThat(action.toString()).isNotEqualTo(differentAction.toString())
- }
-
- @Test
- fun action_equals_toString_differentResovlingValues_areNotEqual() {
- val action = SafetyCenterIssue.Action.Builder("an_id")
- .setLabel("a label")
- .setPendingIntent(pendingIntent1)
- .setResolving(true)
- .setSuccessMessage("a success message")
- .build()
- val differentAction = SafetyCenterIssue.Action.Builder("an_id")
- .setLabel("a label")
- .setPendingIntent(pendingIntent1)
- .setResolving(false)
- .setSuccessMessage("a success message")
- .build()
-
- assertThat(action).isNotEqualTo(differentAction)
- assertThat(action.toString()).isNotEqualTo(differentAction.toString())
- }
-
- @Test
- fun action_equals_toString_differentInFlightValues_areNotEqual() {
- val action = SafetyCenterIssue.Action.Builder("an_id")
- .setLabel("a label")
- .setPendingIntent(pendingIntent1)
- .setResolving(true)
- .setInFlight(true)
- .setSuccessMessage("a success message")
- .build()
- val differentAction = SafetyCenterIssue.Action.Builder("an_id")
- .setLabel("a label")
- .setPendingIntent(pendingIntent1)
- .setResolving(true)
- .setInFlight(false)
- .setSuccessMessage("a success message")
- .build()
-
- assertThat(action).isNotEqualTo(differentAction)
- assertThat(action.toString()).isNotEqualTo(differentAction.toString())
- }
-
- @Test
- fun action_equals_toString_differentSuccessMessages_areNotEqual() {
- val action = SafetyCenterIssue.Action.Builder("an_id")
- .setLabel("a label")
- .setPendingIntent(pendingIntent1)
- .setSuccessMessage("a success message")
- .build()
- val differentAction = SafetyCenterIssue.Action.Builder("an_id")
- .setLabel("a label")
- .setPendingIntent(pendingIntent1)
- .setSuccessMessage("a different success message")
- .build()
-
- assertThat(action).isNotEqualTo(differentAction)
- assertThat(action.toString()).isNotEqualTo(differentAction.toString())
- }
-}
\ No newline at end of file
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt
deleted file mode 100644
index bd58849..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt
+++ /dev/null
@@ -1,498 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.Manifest.permission.MANAGE_SAFETY_CENTER
-import android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE
-import android.app.PendingIntent
-import android.app.PendingIntent.FLAG_IMMUTABLE
-import android.content.Context
-import android.content.Intent
-import android.content.Intent.ACTION_SAFETY_CENTER
-import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
-import android.content.res.Resources
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.provider.DeviceConfig
-import android.safetycenter.SafetyCenterData
-import android.safetycenter.SafetyCenterManager
-import android.safetycenter.SafetyCenterManager.REFRESH_REASON_PAGE_OPEN
-import android.safetycenter.SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLICK
-import android.safetycenter.SafetyCenterManager.OnSafetyCenterDataChangedListener
-import android.safetycenter.SafetySourceData
-import android.safetycenter.SafetySourceIssue
-import android.safetycenter.SafetyEvent
-import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
-import android.safetycenter.SafetySourceIssue.SEVERITY_LEVEL_CRITICAL_WARNING
-import android.safetycenter.SafetySourceStatus
-import android.safetycenter.SafetySourceStatus.STATUS_LEVEL_CRITICAL_WARNING
-import android.safetycenter.config.SafetyCenterConfig
-import android.safetycenter.config.SafetySource
-import android.safetycenter.config.SafetySourcesGroup
-import androidx.test.core.app.ApplicationProvider.getApplicationContext
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
-import com.google.common.truth.Truth.assertThat
-import com.google.common.util.concurrent.MoreExecutors.directExecutor
-import kotlinx.coroutines.TimeoutCancellationException
-import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.withTimeout
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import java.time.Duration
-import kotlin.test.assertFailsWith
-
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetyCenterManagerTest {
- private val context: Context = getApplicationContext()
- private val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
- private val somePendingIntent = PendingIntent.getActivity(
- context, 0 /* requestCode */,
- Intent(ACTION_SAFETY_CENTER).addFlags(FLAG_ACTIVITY_NEW_TASK),
- FLAG_IMMUTABLE
- )
- private val safetySourceDataOnPageOpen = SafetySourceData.Builder()
- .setStatus(
- SafetySourceStatus.Builder(
- "safetySourceDataOnPageOpen status title",
- "safetySourceDataOnPageOpen status summary",
- SafetySourceStatus.STATUS_LEVEL_NONE,
- somePendingIntent
- )
- .build()
- )
- .build()
- private val safetySourceDataOnRescanClick = SafetySourceData.Builder()
- .setStatus(
- SafetySourceStatus.Builder(
- "safetySourceDataOnRescanClick status title",
- "safetySourceDataOnRescanClick status summary",
- SafetySourceStatus.STATUS_LEVEL_RECOMMENDATION,
- somePendingIntent
- )
- .build()
- ).build()
- private val listenerChannel = Channel<SafetyCenterData>()
- // The lambda has to be wrapped to the right type because kotlin wraps lambdas in a new Java
- // functional interface implementation each time they are referenced/cast to a Java interface:
- // b/215569072.
- private val listener = OnSafetyCenterDataChangedListener {
- runBlockingWithTimeout {
- listenerChannel.send(it)
- }
- }
-
- @Before
- @After
- fun clearDataBetweenTest() {
- safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener)
- safetyCenterManager.clearAllSafetySourceDataWithPermission()
- SafetySourceBroadcastReceiver.reset()
- }
-
- @Before
- fun setSafetyCenterConfigOverrideBeforeTest() {
- safetyCenterManager.clearSafetyCenterConfigOverrideWithPermission()
- // TODO(b/217944317): When the test API impl is finalized to override XML config, only
- // override config in select test cases that require it. This is to ensure that we do have
- // some test cases running with the XML config.
- safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_ONLY_CONFIG)
- }
-
- @After
- fun clearSafetyCenterConfigOverrideAfterTest() {
- safetyCenterManager.clearSafetyCenterConfigOverrideWithPermission()
- }
-
- @Test
- fun getSafetySourceData_notSet_returnsNull() {
- val safetySourceData =
- safetyCenterManager.getSafetySourceDataWithPermission("some_unknown_id")
-
- assertThat(safetySourceData).isNull()
- }
-
- @Test
- fun setSafetySourceData_getSafetySourceDataReturnsNewValue() {
- val safetySourceData = SafetySourceData.Builder().build()
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID,
- safetySourceData,
- EVENT_SOURCE_STATE_CHANGED
- )
-
- val safetySourceDataResult =
- safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
-
- assertThat(safetySourceDataResult).isEqualTo(safetySourceData)
- }
-
- @Test
- fun setSafetySourceData_withSameId_replacesValue() {
- val firstSafetySourceData = SafetySourceData.Builder().build()
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID,
- firstSafetySourceData,
- EVENT_SOURCE_STATE_CHANGED
- )
-
- val secondSafetySourceData = SafetySourceData.Builder().setStatus(
- SafetySourceStatus.Builder(
- "Status title", "Summary of the status", STATUS_LEVEL_CRITICAL_WARNING,
- somePendingIntent
- ).build()
- ).addIssue(
- SafetySourceIssue.Builder(
- "Issue id", "Issue title", "Summary of the issue",
- SEVERITY_LEVEL_CRITICAL_WARNING,
- "issue_type_id"
- )
- .addAction(
- SafetySourceIssue.Action.Builder(
- "action_id",
- "Solve issue",
- somePendingIntent
- ).build()
- ).build()
- ).build()
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID,
- secondSafetySourceData,
- EVENT_SOURCE_STATE_CHANGED
- )
-
- val safetySourceData = safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
-
- assertThat(safetySourceData).isEqualTo(secondSafetySourceData)
- }
-
- @Test
- fun isSafetyCenterEnabled_whenConfigEnabled_andFlagEnabled_returnsTrue() {
- if (!deviceSupportsSafetyCenter()) {
- return
- }
-
- runWithShellPermissionIdentity {
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_SAFETY_CENTER_ENABLED,
- /* value = */ true.toString(),
- /* makeDefault = */ false
- )
- }
-
- val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
-
- assertThat(isSafetyCenterEnabled).isTrue()
- }
-
- @Test
- fun isSafetyCenterEnabled_whenConfigEnabled_andFlagDisabled_returnsFalse() {
- if (!deviceSupportsSafetyCenter()) {
- return
- }
-
- runWithShellPermissionIdentity {
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_SAFETY_CENTER_ENABLED,
- /* value = */ false.toString(),
- /* makeDefault = */ false
- )
- }
-
- val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
-
- assertThat(isSafetyCenterEnabled).isFalse()
- }
-
- @Test
- fun isSafetyCenterEnabled_whenConfigDisabled_andFlagEnabled_returnsFalse() {
- if (deviceSupportsSafetyCenter()) {
- return
- }
-
- runWithShellPermissionIdentity {
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_SAFETY_CENTER_ENABLED,
- /* value = */ true.toString(),
- /* makeDefault = */ false
- )
- }
-
- val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
-
- assertThat(isSafetyCenterEnabled).isFalse()
- }
-
- @Test
- fun isSafetyCenterEnabled_whenConfigDisabled_andFlagDisabled_returnsFalse() {
- if (deviceSupportsSafetyCenter()) {
- return
- }
-
- runWithShellPermissionIdentity {
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_SAFETY_CENTER_ENABLED,
- /* value = */ false.toString(),
- /* makeDefault = */ false
- )
- }
-
- val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
-
- assertThat(isSafetyCenterEnabled).isFalse()
- }
-
- @Test
- fun isSafetyCenterEnabled_whenAppDoesNotHoldPermission_methodThrows() {
- assertFailsWith(SecurityException::class) {
- safetyCenterManager.isSafetyCenterEnabled
- }
- }
-
- @Test
- fun refreshSafetySources_withoutManageSafetyCenterPermission_throwsSecurityException() {
- assertFailsWith(SecurityException::class) {
- safetyCenterManager.refreshSafetySources(REFRESH_REASON_RESCAN_BUTTON_CLICK)
- }
- }
-
- @Test
- fun refreshSafetySources_whenReceiverDoesNotHaveSendingPermission_sourceDoesNotSendData() {
- SafetySourceBroadcastReceiver.safetySourceId = CTS_SOURCE_ID
- SafetySourceBroadcastReceiver.safetySourceDataOnRescanClick = safetySourceDataOnRescanClick
-
- safetyCenterManager.refreshSafetySourcesWithPermission(
- REFRESH_REASON_RESCAN_BUTTON_CLICK
- )
-
- assertFailsWith(TimeoutCancellationException::class) {
- SafetySourceBroadcastReceiver.waitTillOnReceiveComplete(TIMEOUT_SHORT)
- }
- val safetySourceData =
- safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
- assertThat(safetySourceData).isNull()
- }
-
- @Test
- fun refreshSafetySources_withRefreshReasonRescanButtonClick_sourceSendsRescanData() {
- SafetySourceBroadcastReceiver.safetySourceId = CTS_SOURCE_ID
- SafetySourceBroadcastReceiver.safetySourceDataOnRescanClick = safetySourceDataOnRescanClick
-
- safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
- REFRESH_REASON_RESCAN_BUTTON_CLICK
- )
-
- val safetySourceData = safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
- assertThat(safetySourceData).isEqualTo(safetySourceDataOnRescanClick)
- }
-
- @Test
- fun refreshSafetySources_withRefreshReasonPageOpen_sourceSendsPageOpenData() {
- SafetySourceBroadcastReceiver.safetySourceId = CTS_SOURCE_ID
- SafetySourceBroadcastReceiver.safetySourceDataOnPageOpen = safetySourceDataOnPageOpen
-
- safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
- REFRESH_REASON_PAGE_OPEN
- )
-
- val safetySourceData = safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
- assertThat(safetySourceData).isEqualTo(safetySourceDataOnPageOpen)
- }
-
- @Test
- fun refreshSafetySources_withInvalidRefreshSeason_throwsIllegalArgumentException() {
- SafetySourceBroadcastReceiver.safetySourceId = CTS_SOURCE_ID
- SafetySourceBroadcastReceiver.safetySourceDataOnPageOpen = safetySourceDataOnPageOpen
- SafetySourceBroadcastReceiver.safetySourceDataOnRescanClick = safetySourceDataOnRescanClick
-
- assertFailsWith(IllegalArgumentException::class) {
- safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(500)
- }
- }
-
- @Test
- fun getSafetyCenterData_returnsSafetyCenterData() {
- val safetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
-
- // TODO(b/218830137): Assert on content.
- assertThat(safetyCenterData).isNotNull()
- }
-
- @Test
- fun getSafetyCenterData_whenAppDoesNotHoldPermission_methodThrows() {
- assertFailsWith(SecurityException::class) {
- safetyCenterManager.safetyCenterData
- }
- }
-
- @Test
- fun addOnSafetyCenterDataChangedListener_listenerCalledWithSafetyCenterData() {
- safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener
- )
- val safetyCenterDataFromListener = receiveListenerUpdate()
-
- // TODO(b/218830137): Assert on content.
- assertThat(safetyCenterDataFromListener).isNotNull()
- }
-
- @Test
- fun addOnSafetyCenterDataChangedListener_listenerCalledOnSafetySourceData() {
- safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener
- )
- // Receive initial data.
- receiveListenerUpdate()
-
- val safetySourceData = SafetySourceData.Builder().build()
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID,
- safetySourceData,
- EVENT_SOURCE_STATE_CHANGED
- )
- val safetyCenterDataFromListener = receiveListenerUpdate()
-
- // TODO(b/218830137): Assert on content.
- assertThat(safetyCenterDataFromListener).isNotNull()
- }
-
- @Test
- fun removeOnSafetyCenterDataChangedListener_listenerNotCalledOnSafetySourceData() {
- safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener
- )
- // Receive initial data.
- receiveListenerUpdate()
-
- safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener)
- val safetySourceData = SafetySourceData.Builder().build()
- safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID,
- safetySourceData,
- EVENT_SOURCE_STATE_CHANGED
- )
-
- assertFailsWith(TimeoutCancellationException::class) {
- receiveListenerUpdate(TIMEOUT_SHORT)
- }
- }
-
- @Test
- fun addOnSafetyCenterDataChangedListener_whenAppDoesNotHoldPermission_methodThrows() {
- assertFailsWith(SecurityException::class) {
- safetyCenterManager.addOnSafetyCenterDataChangedListener(
- directExecutor(), listener
- )
- }
- }
-
- @Test
- fun removeOnSafetyCenterDataChangedListener_whenAppDoesNotHoldPermission_methodThrows() {
- safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener
- )
-
- assertFailsWith(SecurityException::class) {
- safetyCenterManager.removeOnSafetyCenterDataChangedListener(listener)
- }
- }
-
- @Test
- fun dismissSafetyIssue_whenAppDoesNotHoldPermission_methodThrows() {
- assertFailsWith(SecurityException::class) {
- safetyCenterManager.dismissSafetyIssue("bleh")
- }
- }
-
- private fun deviceSupportsSafetyCenter() =
- context.resources.getBoolean(
- Resources.getSystem().getIdentifier(
- "config_enableSafetyCenter",
- "bool",
- "android"
- )
- )
-
- private fun SafetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
- refreshReason: Int
- ) {
- try {
- runWithShellPermissionIdentity({
- refreshSafetySources(refreshReason)
- SafetySourceBroadcastReceiver.waitTillOnReceiveComplete(TIMEOUT_LONG)
- }, SEND_SAFETY_CENTER_UPDATE, MANAGE_SAFETY_CENTER)
- } catch (e: RuntimeException) {
- throw e.cause ?: e
- }
- }
-
- private fun receiveListenerUpdate(timeout: Duration = TIMEOUT_LONG): SafetyCenterData =
- runBlockingWithTimeout(timeout) {
- listenerChannel.receive()
- }
-
- private fun <T> runBlockingWithTimeout(
- timeout: Duration = TIMEOUT_LONG,
- block: suspend () -> T
- ) =
- runBlocking {
- withTimeout(timeout.toMillis()) {
- block()
- }
- }
-
- companion object {
- /** Name of the flag that determines whether SafetyCenter is enabled. */
- private const val PROPERTY_SAFETY_CENTER_ENABLED = "safety_center_is_enabled"
- private const val CTS_PACKAGE_NAME = "android.safetycenter.cts"
- private const val CTS_BROADCAST_RECEIVER_NAME =
- "android.safetycenter.cts.SafetySourceBroadcastReceiver"
- private val TIMEOUT_LONG: Duration = Duration.ofMillis(5000)
- private val TIMEOUT_SHORT: Duration = Duration.ofMillis(1000)
- private val EVENT_SOURCE_STATE_CHANGED =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
- private const val CTS_SOURCE_ID = "cts_source_id"
- // TODO(b/217944317): Consider moving the following to a file where they can be used by
- // other tests.
- private val CTS_SOURCE = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
- .setId(CTS_SOURCE_ID)
- .setPackageName(CTS_PACKAGE_NAME)
- .setTitleResId(R.string.reference)
- .setSummaryResId(R.string.reference)
- .setIntentAction("SafetyCenterManagerTest.INTENT_ACTION")
- .setBroadcastReceiverClassName(CTS_BROADCAST_RECEIVER_NAME)
- .setProfile(SafetySource.PROFILE_PRIMARY)
- .build()
- private val CTS_SOURCE_GROUP = SafetySourcesGroup.Builder()
- .setId("cts_source_group")
- .setTitleResId(R.string.reference)
- .setSummaryResId(R.string.reference)
- .addSafetySource(CTS_SOURCE)
- .build()
- private val CTS_ONLY_CONFIG = SafetyCenterConfig.Builder()
- .addSafetySourcesGroup(CTS_SOURCE_GROUP)
- .build()
- }
-}
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryGroupTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryGroupTest.kt
deleted file mode 100644
index 9557833..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryGroupTest.kt
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.app.PendingIntent
-import android.content.Context
-import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.os.Parcel
-import android.safetycenter.SafetyCenterStaticEntry
-import android.safetycenter.SafetyCenterStaticEntryGroup
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetyCenterStaticEntryGroupTest {
- private val context: Context = ApplicationProvider.getApplicationContext()
-
- private val pendingIntent1 = PendingIntent.getActivity(
- context,
- /* requestCode= */ 0,
- Intent("Fake Data"),
- PendingIntent.FLAG_IMMUTABLE)
- private val pendingIntent2 = PendingIntent.getActivity(
- context,
- /* requestCode= */ 0,
- Intent("Fake Different Data"),
- PendingIntent.FLAG_IMMUTABLE)
-
- private val staticEntry1 =
- SafetyCenterStaticEntry("an entry title", "an entry summary", pendingIntent1)
- private val staticEntry2 =
- SafetyCenterStaticEntry("another entry title", "another entry summary", pendingIntent2)
-
- private val staticEntryGroup =
- SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1, staticEntry2))
-
- @Test
- fun getTitle_returnsTitle() {
- assertThat(SafetyCenterStaticEntryGroup("a title", listOf()).title).isEqualTo("a title")
- assertThat(SafetyCenterStaticEntryGroup("another title", listOf()).title)
- .isEqualTo("another title")
- }
-
- @Test
- fun getStaticEntries_returnsStaticEntries() {
- assertThat(SafetyCenterStaticEntryGroup("", listOf(staticEntry1)).staticEntries)
- .containsExactly(staticEntry1)
- assertThat(
- SafetyCenterStaticEntryGroup("", listOf(staticEntry1, staticEntry2)).staticEntries)
- .containsExactly(staticEntry1, staticEntry2)
- assertThat(SafetyCenterStaticEntryGroup("", listOf()).staticEntries).isEmpty()
- }
-
- @Test
- fun describeContents_returns0() {
- assertThat(staticEntryGroup.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsEquivalentObject() {
- val parcel: Parcel = Parcel.obtain()
-
- staticEntryGroup.writeToParcel(parcel, 0 /* flags */)
- parcel.setDataPosition(0)
- val fromParcel = SafetyCenterStaticEntryGroup.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(fromParcel).isEqualTo(staticEntryGroup)
- }
-
- @Test
- fun equals_hashCode_toString_equalByReference_areEqual() {
- assertThat(staticEntryGroup).isEqualTo(staticEntryGroup)
- assertThat(staticEntryGroup.hashCode()).isEqualTo(staticEntryGroup.hashCode())
- assertThat(staticEntryGroup.toString()).isEqualTo(staticEntryGroup.toString())
- }
-
- @Test
- fun equals_hashCode_toString_equalByValue_areEqual() {
- val group = SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1))
- val equivalentGroup = SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1))
-
- assertThat(group).isEqualTo(equivalentGroup)
- assertThat(group.hashCode()).isEqualTo(equivalentGroup.hashCode())
- assertThat(group.toString()).isEqualTo(equivalentGroup.toString())
- }
-
- @Test
- fun equals_toString_withDifferentTitles_areNotEqual() {
- val group = SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1))
- val differentGroup = SafetyCenterStaticEntryGroup("a different title", listOf(staticEntry1))
-
- assertThat(group).isNotEqualTo(differentGroup)
- assertThat(group.toString()).isNotEqualTo(differentGroup.toString())
- }
-
- @Test
- fun equals_toString_withDifferentStaticEntries_areNotEqual() {
- val group = SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1))
- val differentGroup = SafetyCenterStaticEntryGroup("a different title", listOf(staticEntry2))
-
- assertThat(group).isNotEqualTo(differentGroup)
- assertThat(group.toString()).isNotEqualTo(differentGroup.toString())
- }
-}
\ No newline at end of file
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryTest.kt
deleted file mode 100644
index 8902aeb..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryTest.kt
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.app.PendingIntent
-import android.content.Context
-import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.os.Parcel
-import android.safetycenter.SafetyCenterStaticEntry
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetyCenterStaticEntryTest {
- private val context: Context = ApplicationProvider.getApplicationContext()
-
- private val pendingIntent1 = PendingIntent.getActivity(
- context,
- /* requestCode= */ 0,
- Intent("Fake Data"),
- PendingIntent.FLAG_IMMUTABLE)
- private val pendingIntent2 = PendingIntent.getActivity(
- context,
- /* requestCode= */ 0,
- Intent("Fake Different Data"),
- PendingIntent.FLAG_IMMUTABLE)
-
- private val title1 = "a title"
- private val title2 = "another title"
-
- private val summary1 = "a summary"
- private val summary2 = "another summary"
-
- private val staticEntry1 = SafetyCenterStaticEntry(title1, summary1, pendingIntent1)
- private val staticEntry2 = SafetyCenterStaticEntry(title2, summary2, pendingIntent2)
-
- @Test
- fun getTitle_returnsTitle() {
- assertThat(staticEntry1.title).isEqualTo(title1)
- assertThat(staticEntry2.title).isEqualTo(title2)
- }
-
- @Test
- fun getSummary_returnsSummary() {
- assertThat(staticEntry1.summary).isEqualTo(summary1)
- assertThat(staticEntry2.summary).isEqualTo(summary2)
- assertThat(SafetyCenterStaticEntry("", null, pendingIntent1).summary).isNull()
- }
-
- @Test
- fun getPendingIntent_returnsPendingIntent() {
- assertThat(staticEntry1.pendingIntent).isEqualTo(pendingIntent1)
- assertThat(staticEntry2.pendingIntent).isEqualTo(pendingIntent2)
- }
-
- @Test
- fun describeContents_returns0() {
- assertThat(staticEntry1.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsEquivalentObject() {
- val parcel: Parcel = Parcel.obtain()
-
- staticEntry1.writeToParcel(parcel, 0 /* flags */)
- parcel.setDataPosition(0)
- val fromParcel = SafetyCenterStaticEntry.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(fromParcel).isEqualTo(staticEntry1)
- }
-
- @Test
- fun equals_hashCode_toString_equalByReference_areEqual() {
- assertThat(staticEntry1).isEqualTo(staticEntry1)
- assertThat(staticEntry1.hashCode()).isEqualTo(staticEntry1.hashCode())
- assertThat(staticEntry1.toString()).isEqualTo(staticEntry1.toString())
- }
-
- @Test
- fun equals_hashCode_toString_equalByValue_areEqual() {
- val staticEntry = SafetyCenterStaticEntry("titlee", "sumaree", pendingIntent1)
- val equivalentStaticEntry = SafetyCenterStaticEntry("titlee", "sumaree", pendingIntent1)
-
- assertThat(staticEntry).isEqualTo(equivalentStaticEntry)
- assertThat(staticEntry.hashCode()).isEqualTo(equivalentStaticEntry.hashCode())
- assertThat(staticEntry.toString()).isEqualTo(equivalentStaticEntry.toString())
- }
-
- @Test
- fun equals_toString_withDifferentTitles_areNotEqual() {
- val staticEntry = SafetyCenterStaticEntry("a title", "a summary", pendingIntent1)
- val differentStaticEntry =
- SafetyCenterStaticEntry("a different title", "a summary", pendingIntent1)
-
- assertThat(staticEntry).isNotEqualTo(differentStaticEntry)
- assertThat(staticEntry.toString()).isNotEqualTo(differentStaticEntry.toString())
- }
-
- @Test
- fun equals_toString_withDifferentSummaries_areNotEqual() {
- val staticEntry = SafetyCenterStaticEntry("a title", "a summary", pendingIntent1)
- val differentStaticEntry =
- SafetyCenterStaticEntry("a title", "a different summary", pendingIntent1)
-
- assertThat(staticEntry).isNotEqualTo(differentStaticEntry)
- assertThat(staticEntry.toString()).isNotEqualTo(differentStaticEntry.toString())
- }
-
- @Test
- fun equals_toString_withDifferentPendingIntents_areNotEqual() {
- val staticEntry = SafetyCenterStaticEntry("a title", "a summary", pendingIntent1)
- val differentStaticEntry = SafetyCenterStaticEntry("a title", "a summary", pendingIntent2)
-
- assertThat(staticEntry).isNotEqualTo(differentStaticEntry)
- assertThat(staticEntry.toString()).isNotEqualTo(differentStaticEntry.toString())
- }
-}
\ No newline at end of file
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterStatusTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterStatusTest.kt
deleted file mode 100644
index 68edbf3..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyCenterStatusTest.kt
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.os.Parcel
-import android.safetycenter.SafetyCenterStatus
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetyCenterStatusTest {
-
- val baseStatus = SafetyCenterStatus.Builder()
- .setTitle("This is my title")
- .setSummary("This is my summary")
- .setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION)
- .setRefreshStatus(SafetyCenterStatus.REFRESH_STATUS_DATA_FETCH_IN_PROGRESS)
- .build()
-
- @Test
- fun getTitle_returnsTitle() {
- assertThat(SafetyCenterStatus.Builder(baseStatus).setTitle("title").build().title)
- .isEqualTo("title")
-
- assertThat(SafetyCenterStatus.Builder(baseStatus).setTitle("different title").build().title)
- .isEqualTo("different title")
- }
-
- @Test
- fun getSummary_returnsSummary() {
- assertThat(SafetyCenterStatus.Builder(baseStatus).setSummary("summary").build().summary)
- .isEqualTo("summary")
-
- assertThat(
- SafetyCenterStatus.Builder(baseStatus)
- .setSummary("different summary")
- .build()
- .summary)
- .isEqualTo("different summary")
- }
-
- @Test
- fun getSeverityLevel_returnsSeverityLevel() {
- assertThat(
- SafetyCenterStatus.Builder(baseStatus)
- .setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK)
- .build()
- .severityLevel)
- .isEqualTo(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK)
-
- assertThat(
- SafetyCenterStatus.Builder(baseStatus)
- .setSeverityLevel(
- SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
- .build()
- .severityLevel)
- .isEqualTo(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
- }
-
- @Test
- fun getSeverityLevel_defaultUnknown() {
- assertThat(
- SafetyCenterStatus.Builder()
- .setTitle("This is my title")
- .setSummary("This is my summary")
- .build()
- .severityLevel)
- .isEqualTo(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN)
- }
-
- @Test
- fun getRefreshStatus_returnsRefreshStatus() {
- assertThat(
- SafetyCenterStatus.Builder(baseStatus)
- .setRefreshStatus(SafetyCenterStatus.REFRESH_STATUS_NONE)
- .build()
- .refreshStatus)
- .isEqualTo(SafetyCenterStatus.REFRESH_STATUS_NONE)
-
- assertThat(
- SafetyCenterStatus.Builder(baseStatus)
- .setRefreshStatus(SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS)
- .build()
- .refreshStatus)
- .isEqualTo(SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS)
- }
-
- @Test
- fun getRefreshStatus_defaultNone() {
- assertThat(
- SafetyCenterStatus.Builder()
- .setTitle("This is my title")
- .setSummary("This is my summary")
- .build()
- .refreshStatus)
- .isEqualTo(SafetyCenterStatus.REFRESH_STATUS_NONE)
- }
-
- @Test
- fun describeContents_returns0() {
- assertThat(baseStatus.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsEquivalentObject() {
- val parcel: Parcel = Parcel.obtain()
- baseStatus.writeToParcel(parcel, 0 /* flags */)
- parcel.setDataPosition(0)
- val fromParcel = SafetyCenterStatus.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(fromParcel).isEqualTo(baseStatus)
- }
-
- @Test
- fun equals_hashCode_toString_equalByReference_areEqual() {
- assertThat(baseStatus).isEqualTo(baseStatus)
- assertThat(baseStatus.hashCode()).isEqualTo(baseStatus.hashCode())
- assertThat(baseStatus.toString()).isEqualTo(baseStatus.toString())
- }
-
- @Test
- fun equals_hashCode_toString_equalByValue_areEqual() {
- val status = SafetyCenterStatus.Builder()
- .setTitle("same title")
- .setSummary("same summary")
- .setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK)
- .build()
- val equivalentStatus = SafetyCenterStatus.Builder()
- .setTitle("same title")
- .setSummary("same summary")
- .setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK)
- .build()
-
- assertThat(status).isEqualTo(equivalentStatus)
- assertThat(status.hashCode()).isEqualTo(equivalentStatus.hashCode())
- assertThat(status.toString()).isEqualTo(equivalentStatus.toString())
- }
-
- @Test
- fun equals_hashCode_toString_fromCopyBuilder_areEqual() {
- val copyOfBaseStatus = SafetyCenterStatus.Builder(baseStatus).build()
-
- assertThat(copyOfBaseStatus).isEqualTo(baseStatus)
- assertThat(copyOfBaseStatus.hashCode()).isEqualTo(baseStatus.hashCode())
- assertThat(copyOfBaseStatus.toString()).isEqualTo(baseStatus.toString())
- }
-
- @Test
- fun equals_toString_withDifferentTitles_areNotEqual() {
- val unequalStatus = SafetyCenterStatus.Builder(baseStatus)
- .setTitle("that's discarsting")
- .build()
-
- assertThat(unequalStatus).isNotEqualTo(baseStatus)
- assertThat(unequalStatus.toString()).isNotEqualTo(baseStatus.toString())
- }
-
- @Test
- fun equals_toString_withDifferentSummaries_areNotEqual() {
- val unequalStatus = SafetyCenterStatus.Builder(baseStatus)
- .setSummary("discarsting sheet")
- .build()
-
- assertThat(unequalStatus).isNotEqualTo(baseStatus)
- assertThat(unequalStatus.toString()).isNotEqualTo(baseStatus.toString())
- }
-
- @Test
- fun equals_toString_withDifferentSeverityLevels_arNotEqual() {
- val unequalStatus = SafetyCenterStatus.Builder(baseStatus)
- .setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK)
- .build()
-
- assertThat(unequalStatus).isNotEqualTo(baseStatus)
- assertThat(unequalStatus.toString()).isNotEqualTo(baseStatus.toString())
- }
-
- @Test
- fun equals_toString_withDifferentRefreshStatuses_areNotEqual() {
- val unequalStatus = SafetyCenterStatus.Builder(baseStatus)
- .setRefreshStatus(SafetyCenterStatus.REFRESH_STATUS_NONE)
- .build()
-
- assertThat(unequalStatus).isNotEqualTo(baseStatus)
- assertThat(unequalStatus.toString()).isNotEqualTo(baseStatus.toString())
- }
-}
\ No newline at end of file
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt
deleted file mode 100644
index bc9d538..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.os.Build
-import android.safetycenter.SafetyEvent
-import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED
-import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED
-import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
-import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED
-import android.safetycenter.testers.AnyTester.assertThatRepresentationsAreEqual
-import android.safetycenter.testers.AnyTester.assertThatRepresentationsAreNotEqual
-import android.safetycenter.testers.ParcelableTester.assertThatRoundTripReturnsOriginal
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/** CTS tests for [SafetyEvent]. */
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
-class SafetyEventTest {
- @Test
- fun getSafetyEventType_returnsSafetyEventType() {
- val safetyEvent = SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
-
- assertThat(safetyEvent.safetyEventType).isEqualTo(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED)
- }
-
- @Test
- fun getRefreshBroadcastId_returnsRefreshBroadcastId() {
- val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .setRefreshBroadcastId(REFRESH_BROADCAST_ID)
- .build()
-
- assertThat(safetyEvent.refreshBroadcastId).isEqualTo(REFRESH_BROADCAST_ID)
- }
-
- @Test
- fun getSafetySourceIssueId_returnsSafetySourceIssueId() {
- val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .build()
-
- assertThat(safetyEvent.safetySourceIssueId).isEqualTo(SAFETY_SOURCE_ISSUE_ID)
- }
-
- @Test
- fun getSafetySourceIssueActionId_returnsSafetySourceIssueActionId() {
- val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build()
-
- assertThat(safetyEvent.safetySourceIssueActionId).isEqualTo(SAFETY_SOURCE_ISSUE_ACTION_ID)
- }
-
- @Test
- fun describeContents_returns0() {
- val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build()
-
- assertThat(safetyEvent.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsOriginalSafetySourceData() {
- val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build()
-
- assertThatRoundTripReturnsOriginal(safetyEvent, SafetyEvent.CREATOR)
- }
-
- // TODO(b/208473675): Use `EqualsTester` for testing `hashcode` and `equals`.
- @Test
- fun hashCode_equals_toString_withEqualByReference_areEqual() {
- val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .setRefreshBroadcastId(REFRESH_BROADCAST_ID)
- .build()
- val otherSafetyEvent = safetyEvent
-
- assertThatRepresentationsAreEqual(safetyEvent, otherSafetyEvent)
- }
-
- @Test
- fun hashCode_equals_toString_withAllFieldsEqual_areEqual() {
- val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build()
- val otherSafetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build()
-
- assertThatRepresentationsAreEqual(safetyEvent, otherSafetyEvent)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentSafetyEventTypes_areNotEqual() {
- val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .build()
- val otherSafetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED)
- .build()
-
- assertThatRepresentationsAreNotEqual(safetyEvent, otherSafetyEvent)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentRefreshBroadcastIds_areNotEqual() {
- val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .setRefreshBroadcastId(REFRESH_BROADCAST_ID)
- .build()
- val otherSafetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .setRefreshBroadcastId(OTHER_REFRESH_BROADCAST_ID)
- .build()
-
- assertThatRepresentationsAreNotEqual(safetyEvent, otherSafetyEvent)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentIssueIds_areNotEqual() {
- val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .build()
- val otherSafetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(OTHER_SAFETY_SOURCE_ISSUE_ID)
- .build()
-
- assertThatRepresentationsAreNotEqual(safetyEvent, otherSafetyEvent)
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentActionIds_areNotEqual() {
- val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build()
- val otherSafetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .setSafetySourceIssueActionId(OTHER_SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build()
-
- assertThatRepresentationsAreNotEqual(safetyEvent, otherSafetyEvent)
- }
-
- companion object {
- const val REFRESH_BROADCAST_ID = "refresh_broadcast_id"
- const val OTHER_REFRESH_BROADCAST_ID = "other_refresh_broadcast_id"
- const val SAFETY_SOURCE_ISSUE_ID = "safety_source_issue_id"
- const val OTHER_SAFETY_SOURCE_ISSUE_ID = "other_safety_source_issue_id"
- const val SAFETY_SOURCE_ISSUE_ACTION_ID = "safety_source_issue_action_id"
- const val OTHER_SAFETY_SOURCE_ISSUE_ACTION_ID = "other_safety_source_issue_action_id"
- }
-}
\ No newline at end of file
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetySourceBroadcastReceiver.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetySourceBroadcastReceiver.kt
deleted file mode 100644
index 5f8e8b8..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetySourceBroadcastReceiver.kt
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.safetycenter.SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES
-import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_GET_DATA
-import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA
-import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE
-import android.safetycenter.SafetyCenterManager
-import android.safetycenter.SafetySourceData
-import android.safetycenter.SafetyEvent
-import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED
-import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.withTimeout
-import java.time.Duration
-
-/** Broadcast receiver to be used for testing broadcasts sent to safety source apps. */
-class SafetySourceBroadcastReceiver : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent?) {
- if (intent == null) {
- throw IllegalArgumentException("Received null intent")
- }
-
- if (intent.action != ACTION_REFRESH_SAFETY_SOURCES) {
- throw IllegalArgumentException("Received intent with action: ${intent.action}")
- }
-
- val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
-
- when (intent.getIntExtra(EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE, -1)) {
- EXTRA_REFRESH_REQUEST_TYPE_GET_DATA ->
- safetyCenterManager.setSafetySourceDataWithPermission(
- safetySourceId!!,
- safetySourceDataOnPageOpen!!,
- EVENT_REFRESH_REQUESTED
- )
- EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA ->
- safetyCenterManager.setSafetySourceDataWithPermission(
- safetySourceId!!,
- safetySourceDataOnRescanClick!!,
- EVENT_REFRESH_REQUESTED
- )
- }
-
- runBlocking {
- updateChannel.send(Unit)
- }
- }
-
- companion object {
- private var updateChannel = Channel<Unit>()
- private val EVENT_REFRESH_REQUESTED =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .setRefreshBroadcastId("refresh_id")
- .build()
- var safetySourceId: String? = null
- var safetySourceDataOnPageOpen: SafetySourceData? = null
- var safetySourceDataOnRescanClick: SafetySourceData? = null
-
- fun reset() {
- safetySourceId = null
- safetySourceDataOnRescanClick = null
- safetySourceDataOnPageOpen = null
- updateChannel = Channel()
- }
-
- fun waitTillOnReceiveComplete(duration: Duration) {
- runBlocking {
- withTimeout(duration.toMillis()) {
- updateChannel.receive()
- }
- }
- }
- }
-}
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt
deleted file mode 100644
index 76090bf..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.app.PendingIntent
-import android.app.PendingIntent.FLAG_IMMUTABLE
-import android.content.Context
-import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.os.Parcel
-import android.safetycenter.SafetySourceData
-import android.safetycenter.SafetySourceIssue
-import android.safetycenter.SafetySourceIssue.ISSUE_CATEGORY_ACCOUNT
-import android.safetycenter.SafetySourceStatus
-import android.safetycenter.SafetySourceStatus.IconAction.ICON_TYPE_GEAR
-import androidx.test.core.app.ApplicationProvider.getApplicationContext
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/** CTS tests for [SafetySourceData]. */
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetySourceDataTest {
- private val context: Context = getApplicationContext()
-
- private val status1 = SafetySourceStatus.Builder(
- "Status title 1",
- "Status summary 1",
- SafetySourceStatus.STATUS_LEVEL_NONE,
- PendingIntent.getActivity(context, 0 /* requestCode= */,
- Intent("Status PendingIntent 1"), FLAG_IMMUTABLE))
- .setEnabled(false)
- .build()
- private val status2 = SafetySourceStatus.Builder(
- "Status title 2",
- "Status summary 2",
- SafetySourceStatus.STATUS_LEVEL_RECOMMENDATION,
- PendingIntent.getActivity(context, 0 /* requestCode= */,
- Intent("Status PendingIntent 2"), FLAG_IMMUTABLE))
- .setIconAction(SafetySourceStatus.IconAction(ICON_TYPE_GEAR,
- PendingIntent.getActivity(context, 0 /* requestCode= */,
- Intent("IconAction PendingIntent 2"), FLAG_IMMUTABLE)))
- .build()
- private val issue1 = SafetySourceIssue.Builder(
- "Issue id 1",
- "Issue summary 1",
- "Issue summary 1",
- SafetySourceIssue.SEVERITY_LEVEL_INFORMATION, "issue_type_id"
- )
- .setSubtitle("Issue subtitle 1")
- .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
- .addAction(
- SafetySourceIssue.Action.Builder(
- "action_id_1",
- "Action label 1",
- PendingIntent.getActivity(
- context, 0 /* requestCode= */,
- Intent("Issue PendingIntent 1"), FLAG_IMMUTABLE
- )
- )
- .build()
- )
- .build()
- private val issue2 = SafetySourceIssue.Builder(
- "Issue id 2",
- "Issue title 2",
- "Issue summary 2",
- SafetySourceIssue.SEVERITY_LEVEL_RECOMMENDATION, "issue_type_id"
- )
- .addAction(
- SafetySourceIssue.Action.Builder(
- "action_id_2",
- "Action label 2",
- PendingIntent.getService(
- context, 0 /* requestCode= */,
- Intent("Issue PendingIntent 2"), FLAG_IMMUTABLE
- )
- ).build()
- )
- .setOnDismissPendingIntent(
- PendingIntent.getService(
- context,
- 0 /* requestCode= */,
- Intent("Issue OnDismissPendingIntent 2"), FLAG_IMMUTABLE
- )
- )
- .build()
-
- @Test
- fun getStatus_withDefaultBuilder_returnsNull() {
- val safetySourceData = SafetySourceData.Builder().build()
-
- assertThat(safetySourceData.status).isNull()
- }
-
- @Test
- fun getStatus_whenSetExplicitly_returnsStatus() {
- val safetySourceData = SafetySourceData.Builder()
- .setStatus(status1)
- .build()
-
- assertThat(safetySourceData.status).isEqualTo(status1)
- }
-
- @Test
- fun getIssues_withDefaultBuilder_returnsEmptyList() {
- val safetySourceData = SafetySourceData.Builder().build()
-
- assertThat(safetySourceData.issues).isEmpty()
- }
-
- @Test
- fun getIssues_whenSetExplicitly_returnsIssues() {
- val safetySourceData = SafetySourceData.Builder()
- .addIssue(issue1)
- .addIssue(issue2)
- .build()
-
- assertThat(safetySourceData.issues).containsExactly(issue1, issue2).inOrder()
- }
-
- @Test
- fun clearIssues_removesAllIssues() {
- val safetySourceData = SafetySourceData.Builder()
- .addIssue(issue1)
- .addIssue(issue2)
- .clearIssues()
- .build()
-
- assertThat(safetySourceData.issues).isEmpty()
- }
-
- @Test
- fun describeContents_returns0() {
- val safetySourceData = SafetySourceData.Builder()
- .setStatus(status1)
- .addIssue(issue1)
- .addIssue(issue2)
- .build()
-
- assertThat(safetySourceData.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsOriginalSafetySourceData() {
- val safetySourceData = SafetySourceData.Builder()
- .setStatus(status1)
- .addIssue(issue1)
- .addIssue(issue2)
- .build()
-
- val parcel: Parcel = Parcel.obtain()
- safetySourceData.writeToParcel(parcel, 0 /* flags */)
- parcel.setDataPosition(0)
- val safetySourceDataFromParcel: SafetySourceData =
- SafetySourceData.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(safetySourceDataFromParcel).isEqualTo(safetySourceData)
- }
-
- // TODO(b/208473675): Use `EqualsTester` for testing `hashcode` and `equals`.
- @Test
- fun hashCode_equals_toString_withEqualByReference_withoutStatusAndIssues_areEqual() {
- val safetySourceData = SafetySourceData.Builder().build()
- val otherSafetySourceData = safetySourceData
-
- assertThat(safetySourceData.hashCode()).isEqualTo(otherSafetySourceData.hashCode())
- assertThat(safetySourceData).isEqualTo(otherSafetySourceData)
- assertThat(safetySourceData.toString()).isEqualTo(otherSafetySourceData.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withEqualByReference_withoutIssues_areEqual() {
- val safetySourceData = SafetySourceData.Builder()
- .setStatus(status1)
- .build()
- val otherSafetySourceData = safetySourceData
-
- assertThat(safetySourceData.hashCode()).isEqualTo(otherSafetySourceData.hashCode())
- assertThat(safetySourceData).isEqualTo(otherSafetySourceData)
- assertThat(safetySourceData.toString()).isEqualTo(otherSafetySourceData.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withEqualByReference_areEqual() {
- val safetySourceData = SafetySourceData.Builder()
- .setStatus(status1)
- .addIssue(issue1)
- .addIssue(issue2)
- .build()
- val otherSafetySourceData = safetySourceData
-
- assertThat(safetySourceData.hashCode()).isEqualTo(otherSafetySourceData.hashCode())
- assertThat(safetySourceData).isEqualTo(otherSafetySourceData)
- assertThat(safetySourceData.toString()).isEqualTo(otherSafetySourceData.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withAllFieldsEqual_areEqual() {
- val safetySourceData = SafetySourceData.Builder()
- .setStatus(status1)
- .addIssue(issue1)
- .addIssue(issue2)
- .build()
- val otherSafetySourceData = SafetySourceData.Builder()
- .setStatus(status1)
- .addIssue(issue1)
- .addIssue(issue2)
- .build()
-
- assertThat(safetySourceData.hashCode()).isEqualTo(otherSafetySourceData.hashCode())
- assertThat(safetySourceData).isEqualTo(otherSafetySourceData)
- assertThat(safetySourceData.toString()).isEqualTo(otherSafetySourceData.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentIssues_areNotEqual() {
- val safetySourceData = SafetySourceData.Builder()
- .setStatus(status1)
- .addIssue(issue1)
- .addIssue(issue2)
- .build()
- val otherSafetySourceData = SafetySourceData.Builder()
- .setStatus(status2)
- .addIssue(issue1)
- .addIssue(issue2)
- .build()
-
- assertThat(safetySourceData.hashCode()).isNotEqualTo(otherSafetySourceData.hashCode())
- assertThat(safetySourceData).isNotEqualTo(otherSafetySourceData)
- assertThat(safetySourceData.toString()).isNotEqualTo(otherSafetySourceData.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentStatuses_areNotEqual() {
- val safetySourceData = SafetySourceData.Builder()
- .setStatus(status1)
- .addIssue(issue1)
- .addIssue(issue2)
- .build()
- val otherSafetySourceData = SafetySourceData.Builder()
- .setStatus(status1)
- .addIssue(issue1)
- .build()
-
- assertThat(safetySourceData.hashCode()).isNotEqualTo(otherSafetySourceData.hashCode())
- assertThat(safetySourceData).isNotEqualTo(otherSafetySourceData)
- assertThat(safetySourceData.toString()).isNotEqualTo(otherSafetySourceData.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withStatusSetInOneAndNotOther_areNotEqual() {
- val safetySourceData = SafetySourceData.Builder()
- .setStatus(status1)
- .build()
- val otherSafetySourceData = SafetySourceData.Builder().build()
-
- assertThat(safetySourceData.hashCode()).isNotEqualTo(otherSafetySourceData.hashCode())
- assertThat(safetySourceData).isNotEqualTo(otherSafetySourceData)
- assertThat(safetySourceData.toString()).isNotEqualTo(otherSafetySourceData.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withIssuesSetInOneAndNotOther_areNotEqual() {
- val safetySourceData = SafetySourceData.Builder()
- .setStatus(status1)
- .addIssue(issue1)
- .addIssue(issue2)
- .build()
- val otherSafetySourceData = SafetySourceData.Builder()
- .setStatus(status1)
- .build()
-
- assertThat(safetySourceData.hashCode()).isNotEqualTo(otherSafetySourceData.hashCode())
- assertThat(safetySourceData).isNotEqualTo(otherSafetySourceData)
- assertThat(safetySourceData.toString()).isNotEqualTo(otherSafetySourceData.toString())
- }
-}
\ No newline at end of file
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetySourceErrorTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetySourceErrorTest.kt
deleted file mode 100644
index 0d69f2c..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetySourceErrorTest.kt
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.os.Build
-import android.safetycenter.SafetyEvent
-import android.safetycenter.SafetySourceError
-import android.safetycenter.testers.AnyTester.assertThatRepresentationsAreEqual
-import android.safetycenter.testers.AnyTester.assertThatRepresentationsAreNotEqual
-import android.safetycenter.testers.ParcelableTester.assertThatRoundTripReturnsOriginal
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/** CTS tests for [SafetySourceError]. */
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
-class SafetySourceErrorTest {
- @Test
- fun getSafetyEvent_returnsSafetyEvent() {
- val safetySourceError = SafetySourceError(SAFETY_EVENT)
-
- assertThat(safetySourceError.safetyEvent).isEqualTo(SAFETY_EVENT)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsEquivalentObject() {
- val safetySourceError = SafetySourceError(SAFETY_EVENT)
-
- assertThatRoundTripReturnsOriginal(safetySourceError, SafetySourceError.CREATOR)
- }
-
- @Test
- fun equals_hashCode_toString_equalByReference_areEqual() {
- val safetySourceError = SafetySourceError(SAFETY_EVENT)
-
- assertThatRepresentationsAreEqual(safetySourceError, safetySourceError)
- }
-
- @Test
- fun equals_hashCode_toString_equalByValue_areEqual() {
- val safetySourceError = SafetySourceError(SAFETY_EVENT)
- val equivalentSafetySourceError = SafetySourceError(SAFETY_EVENT)
-
- assertThatRepresentationsAreEqual(safetySourceError, equivalentSafetySourceError)
- }
-
- @Test
- fun equals_toString_withDifferentSafetyEvents_areNotEqual() {
- val safetySourceError = SafetySourceError(
- SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build())
- val otherSafetySourceError = SafetySourceError(
- SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build())
-
- assertThatRepresentationsAreNotEqual(safetySourceError, otherSafetySourceError)
- }
-
- companion object {
- private val SAFETY_EVENT =
- SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
- }
-}
\ No newline at end of file
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt
deleted file mode 100644
index ad3e441..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt
+++ /dev/null
@@ -1,785 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.app.PendingIntent
-import android.app.PendingIntent.FLAG_IMMUTABLE
-import android.content.Context
-import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.os.Parcel
-import android.safetycenter.SafetySourceIssue
-import android.safetycenter.SafetySourceIssue.ISSUE_CATEGORY_ACCOUNT
-import android.safetycenter.SafetySourceIssue.ISSUE_CATEGORY_DEVICE
-import android.safetycenter.SafetySourceIssue.ISSUE_CATEGORY_GENERAL
-import android.safetycenter.SafetySourceIssue.Action
-import android.safetycenter.SafetySourceIssue.SEVERITY_LEVEL_CRITICAL_WARNING
-import android.safetycenter.SafetySourceIssue.SEVERITY_LEVEL_INFORMATION
-import androidx.test.core.app.ApplicationProvider.getApplicationContext
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Assert.assertThrows
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/** CTS tests for [SafetySourceIssue]. */
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetySourceIssueTest {
- private val context: Context = getApplicationContext()
-
- private val pendingIntent1: PendingIntent = PendingIntent.getActivity(
- context,
- 0 /* requestCode= */, Intent("PendingIntent 1"), FLAG_IMMUTABLE
- )
- private val action1 = Action.Builder("action_id_1", "Action label 1", pendingIntent1).build()
- private val pendingIntent2: PendingIntent = PendingIntent.getActivity(
- context,
- 0 /* requestCode= */, Intent("PendingIntent 2"), FLAG_IMMUTABLE
- )
- private val action2 = Action.Builder("action_id_2", "Action label 2", pendingIntent2).build()
- private val action3 = Action.Builder("action_id_3", "Action label 3", pendingIntent1).build()
-
- @Test
- fun action_getId_returnsId() {
- val action = Action.Builder("action_id", "Action label", pendingIntent1).build()
-
- assertThat(action.id).isEqualTo("action_id")
- }
-
- @Test
- fun action_getLabel_returnsLabel() {
- val action = Action.Builder("action_id", "Action label", pendingIntent1).build()
-
- assertThat(action.label).isEqualTo("Action label")
- }
-
- @Test
- fun action_isResolving_withDefaultBuilder_returnsFalse() {
- val action = Action.Builder("action_id", "Action label", pendingIntent1).build()
-
- assertThat(action.isResolving).isFalse()
- }
-
- @Test
- fun action_isResolving_whenSetExplicitly_returnsResolving() {
- val action = Action.Builder("action_id", "Action label", pendingIntent1)
- .setResolving(true)
- .build()
-
- assertThat(action.isResolving).isTrue()
- }
-
- @Test
- fun action_getPendingIntent_returnsPendingIntent() {
- val action = Action.Builder("action_id", "Action label", pendingIntent1).build()
-
- assertThat(action.pendingIntent).isEqualTo(pendingIntent1)
- }
-
- @Test
- fun action_getSuccessMessage_withDefaultBuilder_returnsNull() {
- val action = Action.Builder("action_id", "Action label", pendingIntent1).build()
-
- assertThat(action.successMessage).isNull()
- }
-
- @Test
- fun action_getSuccessMessage_whenSetExplicitly_returnsSuccessMessage() {
- val action = Action.Builder("action_id", "Action label", pendingIntent1)
- .setSuccessMessage("Action successfully completed")
- .build()
-
- assertThat(action.successMessage).isEqualTo("Action successfully completed")
- }
-
- @Test
- fun action_describeContents_returns0() {
- val action = Action.Builder("action_id", "Action label", pendingIntent1).build()
-
- assertThat(action.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun action_createFromParcel_withWriteToParcel_returnsOriginalAction() {
- val action = Action.Builder("action_id", "Action label", pendingIntent1)
- .setSuccessMessage("Action successfully completed")
- .build()
-
- val parcel: Parcel = Parcel.obtain()
- action.writeToParcel(parcel, 0 /* flags */)
- parcel.setDataPosition(0)
- val actionFromParcel: Action = Action.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(actionFromParcel).isEqualTo(action)
- }
-
- // TODO(b/208473675): Use `EqualsTester` for testing `hashcode` and `equals`.
- @Test
- fun action_hashCode_equals_toString_withEqualByReferenceActions_areEqual() {
- val action = Action.Builder("action_id", "Action label", pendingIntent1).build()
- val otherAction = action
-
- assertThat(action.hashCode()).isEqualTo(otherAction.hashCode())
- assertThat(action).isEqualTo(otherAction)
- assertThat(action.toString()).isEqualTo(otherAction.toString())
- }
-
- @Test
- fun action_hashCode_equals_toString_withAllFieldsEqual_areEqual() {
- val action = Action.Builder("action_id", "Action label", pendingIntent1).build()
- val otherAction = Action.Builder("action_id", "Action label", pendingIntent1).build()
-
- assertThat(action.hashCode()).isEqualTo(otherAction.hashCode())
- assertThat(action).isEqualTo(otherAction)
- assertThat(action.toString()).isEqualTo(otherAction.toString())
- }
-
- @Test
- fun action_hashCode_equals_toString_withDifferentIds_areNotEqual() {
- val action = Action.Builder("action_id", "Action label", pendingIntent1).build()
- val otherAction = Action.Builder("other_action_id", "Action label", pendingIntent1).build()
-
- assertThat(action.hashCode()).isNotEqualTo(otherAction.hashCode())
- assertThat(action).isNotEqualTo(otherAction)
- assertThat(action.toString()).isNotEqualTo(otherAction.toString())
- }
-
- @Test
- fun action_hashCode_equals_toString_withDifferentLabels_areNotEqual() {
- val action = Action.Builder("action_id", "Action label", pendingIntent1).build()
- val otherAction = Action.Builder("action_id", "Other action label", pendingIntent1).build()
-
- assertThat(action.hashCode()).isNotEqualTo(otherAction.hashCode())
- assertThat(action).isNotEqualTo(otherAction)
- assertThat(action.toString()).isNotEqualTo(otherAction.toString())
- }
-
- @Test
- fun action_hashCode_equals_toString_withDifferentResolving_areNotEqual() {
- val action =
- Action.Builder("action_id", "Action label", pendingIntent1).setResolving(false)
- .build()
- val otherAction =
- Action.Builder("action_id", "Action label", pendingIntent1).setResolving(true).build()
-
- assertThat(action.hashCode()).isNotEqualTo(otherAction.hashCode())
- assertThat(action).isNotEqualTo(otherAction)
- assertThat(action.toString()).isNotEqualTo(otherAction.toString())
- }
-
- @Test
- fun action_hashCode_equals_toString_withDifferentPendingIntents_areNotEqual() {
- val action = Action.Builder(
- "action_id",
- "Action label",
- PendingIntent.getActivity(
- context, 0 /* requestCode= */,
- Intent("Action PendingIntent"), FLAG_IMMUTABLE
- )
- )
- .build()
- val otherAction = Action.Builder(
- "action_id",
- "Action label",
- PendingIntent.getActivity(
- context, 0 /* requestCode= */,
- Intent("Other action PendingIntent"), FLAG_IMMUTABLE
- )
- )
- .build()
-
- assertThat(action.hashCode()).isNotEqualTo(otherAction.hashCode())
- assertThat(action).isNotEqualTo(otherAction)
- assertThat(action.toString()).isNotEqualTo(otherAction.toString())
- }
-
- @Test
- fun action_hashCode_equals_toString_withDifferentSuccessMessages_areNotEqual() {
- val action =
- Action.Builder("action_id", "Action label", pendingIntent1)
- .setSuccessMessage("Action successfully completed")
- .build()
- val otherAction =
- Action.Builder("action_id", "Action label", pendingIntent1)
- .setSuccessMessage("Other action successfully completed")
- .build()
-
- assertThat(action.hashCode()).isNotEqualTo(otherAction.hashCode())
- assertThat(action).isNotEqualTo(otherAction)
- assertThat(action.toString()).isNotEqualTo(otherAction.toString())
- }
-
- @Test
- fun getId_returnsId() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- )
- .addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.id).isEqualTo("Issue id")
- }
-
- @Test
- fun getTitle_returnsTitle() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- )
- .addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.title).isEqualTo("Issue title")
- }
-
- @Test
- fun getSubtitle_withDefaultBuilder_returnsNull() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- )
- .addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.subtitle).isNull()
- }
-
- @Test
- fun getSubtitle_whenSetExplicitly_returnsSubtitle() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- )
- .setSubtitle("Issue subtitle")
- .addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.subtitle).isEqualTo("Issue subtitle")
- }
-
- @Test
- fun getSummary_returnsSummary() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- )
- .addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.summary).isEqualTo("Issue summary")
- }
-
- @Test
- fun getSeverityLevel_returnsSeverityLevel() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.severityLevel).isEqualTo(SEVERITY_LEVEL_INFORMATION)
- }
-
- @Test
- fun getIssueCategory_withDefaultBuilder_returnsGeneralCategory() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.issueCategory).isEqualTo(ISSUE_CATEGORY_GENERAL)
- }
-
- @Test
- fun getIssueCategory_whenSetExplicitly_returnsIssueCategory() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .setIssueCategory(ISSUE_CATEGORY_DEVICE)
- .build()
-
- assertThat(safetySourceIssue.issueCategory).isEqualTo(ISSUE_CATEGORY_DEVICE)
- }
-
- @Test
- fun getActions_returnsActions() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .addAction(action2)
- .build()
-
- assertThat(safetySourceIssue.actions).containsExactly(action1, action2).inOrder()
- }
-
- @Test
- fun clearActions_removesAllActions() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .addAction(action2)
- .clearActions()
- .addAction(action3)
- .build()
-
- assertThat(safetySourceIssue.actions).containsExactly(action3)
- }
-
- @Test
- fun getOnDismissPendingIntent_withDefaultBuilder_returnsNull() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.onDismissPendingIntent).isNull()
- }
-
- @Test
- fun getOnDismissPendingIntent_whenSetExplicitly_returnsOnDismissPendingIntent() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .setOnDismissPendingIntent(pendingIntent1)
- .build()
-
- assertThat(safetySourceIssue.onDismissPendingIntent).isEqualTo(pendingIntent1)
- }
-
- @Test
- fun getIssueTypeId_returnsIssueTypeId() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.issueTypeId).isEqualTo("issue_type_id")
- }
-
- @Test
- fun build_withNoActions_throwsIllegalArgumentException() {
- val safetySourceIssueBuilder = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- )
- assertThrows(
- "Safety source issue must contain at least 1 action",
- IllegalArgumentException::class.java
- ) { safetySourceIssueBuilder.build() }
- }
-
- @Test
- fun build_withMoreThanTwoActions_throwsIllegalArgumentException() {
- val safetySourceIssueBuilder = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .addAction(action2)
- .addAction(action1)
-
- assertThrows(
- "Safety source issue must not contain more than 2 actions",
- IllegalArgumentException::class.java
- ) { safetySourceIssueBuilder.build() }
- }
-
- @Test
- fun describeContents_returns0() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).setSubtitle("Issue subtitle")
- .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
- .addAction(action1)
- .addAction(action2)
- .setOnDismissPendingIntent(pendingIntent1)
- .build()
-
- assertThat(safetySourceIssue.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsOriginalSafetySourceIssue() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).setSubtitle("Issue subtitle")
- .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
- .addAction(action1)
- .addAction(action2)
- .setOnDismissPendingIntent(pendingIntent1)
- .build()
-
- val parcel: Parcel = Parcel.obtain()
- safetySourceIssue.writeToParcel(parcel, 0 /* flags */)
- parcel.setDataPosition(0)
- val safetySourceIssueFromParcel: SafetySourceIssue =
- SafetySourceIssue.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(safetySourceIssueFromParcel).isEqualTo(safetySourceIssue)
- }
-
- // TODO(b/208473675): Use `EqualsTester` for testing `hashcode` and `equals`.
- @Test
- fun hashCode_equals_toString_withEqualByReferenceSafetySourceIssues_areEqual() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).setSubtitle("Issue subtitle")
- .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
- .addAction(action1)
- .addAction(action2)
- .setOnDismissPendingIntent(pendingIntent1)
- .build()
- val otherSafetySourceIssue = safetySourceIssue
-
- assertThat(safetySourceIssue.hashCode()).isEqualTo(otherSafetySourceIssue.hashCode())
- assertThat(safetySourceIssue).isEqualTo(otherSafetySourceIssue)
- assertThat(safetySourceIssue.toString()).isEqualTo(otherSafetySourceIssue.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withAllFieldsEqual_areEqual() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).setSubtitle("Issue subtitle")
- .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
- .addAction(
- Action.Builder("action_id", "Action label 1", pendingIntent1)
- .setResolving(false)
- .build()
- )
- .setOnDismissPendingIntent(pendingIntent1)
- .build()
- val otherSafetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).setSubtitle("Issue subtitle")
- .setIssueCategory(ISSUE_CATEGORY_ACCOUNT)
- .addAction(
- Action.Builder("action_id", "Action label 1", pendingIntent1)
- .setResolving(false)
- .build()
- )
- .setOnDismissPendingIntent(pendingIntent1)
- .build()
-
- assertThat(safetySourceIssue.hashCode()).isEqualTo(otherSafetySourceIssue.hashCode())
- assertThat(safetySourceIssue).isEqualTo(otherSafetySourceIssue)
- assertThat(safetySourceIssue.toString()).isEqualTo(otherSafetySourceIssue.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentIds_areNotEqual() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .build()
- val otherSafetySourceIssue = SafetySourceIssue.Builder(
- "Other issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.hashCode()).isNotEqualTo(otherSafetySourceIssue.hashCode())
- assertThat(safetySourceIssue).isNotEqualTo(otherSafetySourceIssue)
- assertThat(safetySourceIssue.toString()).isNotEqualTo(otherSafetySourceIssue.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentTitles_areNotEqual() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .build()
- val otherSafetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Other issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.hashCode()).isNotEqualTo(otherSafetySourceIssue.hashCode())
- assertThat(safetySourceIssue).isNotEqualTo(otherSafetySourceIssue)
- assertThat(safetySourceIssue.toString()).isNotEqualTo(otherSafetySourceIssue.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentSubtitles_areNotEqual() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).setSubtitle("Issue subtitle")
- .addAction(action1)
- .build()
- val otherSafetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).setSubtitle("Other issue subtitle")
- .addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.hashCode()).isNotEqualTo(otherSafetySourceIssue.hashCode())
- assertThat(safetySourceIssue).isNotEqualTo(otherSafetySourceIssue)
- assertThat(safetySourceIssue.toString()).isNotEqualTo(otherSafetySourceIssue.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentSummaries_areNotEqual() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .build()
- val otherSafetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Other issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.hashCode()).isNotEqualTo(otherSafetySourceIssue.hashCode())
- assertThat(safetySourceIssue).isNotEqualTo(otherSafetySourceIssue)
- assertThat(safetySourceIssue.toString()).isNotEqualTo(otherSafetySourceIssue.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentSeverityLevels_areNotEqual() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .build()
- val otherSafetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_CRITICAL_WARNING,
- "issue_type_id"
- )
- .addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.hashCode()).isNotEqualTo(otherSafetySourceIssue.hashCode())
- assertThat(safetySourceIssue).isNotEqualTo(otherSafetySourceIssue)
- assertThat(safetySourceIssue.toString()).isNotEqualTo(otherSafetySourceIssue.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentIssueCategories_areNotEqual() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- )
- .addAction(action1)
- .setIssueCategory(ISSUE_CATEGORY_DEVICE)
- .build()
- val otherSafetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- )
- .addAction(action1)
- .setIssueCategory(ISSUE_CATEGORY_GENERAL)
- .build()
-
- assertThat(safetySourceIssue.hashCode()).isNotEqualTo(otherSafetySourceIssue.hashCode())
- assertThat(safetySourceIssue).isNotEqualTo(otherSafetySourceIssue)
- assertThat(safetySourceIssue.toString()).isNotEqualTo(otherSafetySourceIssue.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentActions_areNotEqual() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .addAction(action2)
- .build()
- val otherSafetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action2)
- .addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.hashCode()).isNotEqualTo(otherSafetySourceIssue.hashCode())
- assertThat(safetySourceIssue).isNotEqualTo(otherSafetySourceIssue)
- assertThat(safetySourceIssue.toString()).isNotEqualTo(otherSafetySourceIssue.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentOnDismissPendingIntents_areNotEqual() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .setOnDismissPendingIntent(pendingIntent1)
- .build()
- val otherSafetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .setOnDismissPendingIntent(pendingIntent2)
- .build()
-
- assertThat(safetySourceIssue.hashCode()).isNotEqualTo(otherSafetySourceIssue.hashCode())
- assertThat(safetySourceIssue).isNotEqualTo(otherSafetySourceIssue)
- assertThat(safetySourceIssue.toString()).isNotEqualTo(otherSafetySourceIssue.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentIssueTypeIds_areNotEqual() {
- val safetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "issue_type_id"
- ).addAction(action1)
- .build()
- val otherSafetySourceIssue = SafetySourceIssue.Builder(
- "Issue id",
- "Issue title",
- "Issue summary",
- SEVERITY_LEVEL_INFORMATION,
- "other_issue_type_id"
- ).addAction(action1)
- .build()
-
- assertThat(safetySourceIssue.hashCode()).isNotEqualTo(otherSafetySourceIssue.hashCode())
- assertThat(safetySourceIssue).isNotEqualTo(otherSafetySourceIssue)
- assertThat(safetySourceIssue.toString()).isNotEqualTo(otherSafetySourceIssue.toString())
- }
-}
\ No newline at end of file
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetySourceStatusTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/SafetySourceStatusTest.kt
deleted file mode 100644
index b44f6c5..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/SafetySourceStatusTest.kt
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.app.PendingIntent
-import android.app.PendingIntent.FLAG_IMMUTABLE
-import android.content.Context
-import android.content.Intent
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.os.Parcel
-import android.safetycenter.SafetySourceStatus
-import android.safetycenter.SafetySourceStatus.IconAction
-import android.safetycenter.SafetySourceStatus.IconAction.ICON_TYPE_GEAR
-import android.safetycenter.SafetySourceStatus.IconAction.ICON_TYPE_INFO
-import android.safetycenter.SafetySourceStatus.STATUS_LEVEL_CRITICAL_WARNING
-import android.safetycenter.SafetySourceStatus.STATUS_LEVEL_OK
-import androidx.test.core.app.ApplicationProvider.getApplicationContext
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/** CTS tests for [SafetySourceStatus]. */
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class SafetySourceStatusTest {
- private val context: Context = getApplicationContext()
-
- private val pendingIntent1: PendingIntent = PendingIntent.getActivity(
- context,
- 0 /* requestCode= */, Intent("PendingIntent 1"), FLAG_IMMUTABLE
- )
- private val iconAction1 = IconAction(ICON_TYPE_INFO, pendingIntent1)
- private val pendingIntent2: PendingIntent = PendingIntent.getActivity(
- context,
- 0 /* requestCode= */, Intent("PendingIntent 2"), FLAG_IMMUTABLE
- )
- private val iconAction2 = IconAction(ICON_TYPE_GEAR, pendingIntent2)
-
- @Test
- fun iconAction_getIconType_returnsIconType() {
- val iconAction = IconAction(ICON_TYPE_INFO, pendingIntent1)
-
- assertThat(iconAction.iconType).isEqualTo(ICON_TYPE_INFO)
- }
-
- @Test
- fun iconAction_getPendingIntent_returnsPendingIntent() {
- val iconAction = IconAction(ICON_TYPE_GEAR, pendingIntent1)
-
- assertThat(iconAction.pendingIntent).isEqualTo(pendingIntent1)
- }
-
- @Test
- fun iconAction_describeContents_returns0() {
- val iconAction = IconAction(ICON_TYPE_GEAR, pendingIntent1)
-
- assertThat(iconAction.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun iconAction_createFromParcel_withWriteToParcel_returnsOriginalAction() {
- val iconAction = IconAction(ICON_TYPE_GEAR, pendingIntent1)
-
- val parcel: Parcel = Parcel.obtain()
- iconAction.writeToParcel(parcel, 0 /* flags */)
- parcel.setDataPosition(0)
- val iconActionFromParcel: IconAction = IconAction.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(iconActionFromParcel).isEqualTo(iconAction)
- }
-
- // TODO(b/208473675): Use `EqualsTester` for testing `hashcode` and `equals`.
- @Test
- fun iconAction_hashCode_equals_toString_withEqualByReferenceIconActions_areEqual() {
- val iconAction = IconAction(ICON_TYPE_GEAR, pendingIntent1)
- val otherIconAction = iconAction
-
- assertThat(iconAction.hashCode()).isEqualTo(otherIconAction.hashCode())
- assertThat(iconAction).isEqualTo(otherIconAction)
- assertThat(iconAction.toString()).isEqualTo(otherIconAction.toString())
- }
-
- @Test
- fun iconAction_hashCode_equals_toString_withAllFieldsEqual_areEqual() {
- val iconAction = IconAction(ICON_TYPE_GEAR, pendingIntent1)
- val otherIconAction = IconAction(ICON_TYPE_GEAR, pendingIntent1)
-
- assertThat(iconAction.hashCode()).isEqualTo(otherIconAction.hashCode())
- assertThat(iconAction).isEqualTo(otherIconAction)
- assertThat(iconAction.toString()).isEqualTo(otherIconAction.toString())
- }
-
- @Test
- fun iconAction_hashCode_equals_toString_withDifferentIconTypes_areNotEqual() {
- val iconAction = IconAction(ICON_TYPE_GEAR, pendingIntent1)
- val otherIconAction = IconAction(ICON_TYPE_INFO, pendingIntent1)
-
- assertThat(iconAction.hashCode()).isNotEqualTo(otherIconAction.hashCode())
- assertThat(iconAction).isNotEqualTo(otherIconAction)
- assertThat(iconAction.toString()).isNotEqualTo(otherIconAction.toString())
- }
-
- @Test
- fun iconAction_hashCode_equals_toString_withDifferentPendingIntents_areNotEqual() {
- val iconAction = IconAction(ICON_TYPE_GEAR, pendingIntent1)
- val otherIconAction = IconAction(ICON_TYPE_GEAR, pendingIntent2)
-
- assertThat(iconAction.hashCode()).isNotEqualTo(otherIconAction.hashCode())
- assertThat(iconAction).isNotEqualTo(otherIconAction)
- assertThat(iconAction.toString()).isNotEqualTo(otherIconAction.toString())
- }
-
- @Test
- fun getTitle_returnsTitle() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .build()
-
- assertThat(safetySourceStatus.title).isEqualTo("Status title")
- }
-
- @Test
- fun getSummary_returnsSummary() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .build()
-
- assertThat(safetySourceStatus.summary).isEqualTo("Status summary")
- }
-
- @Test
- fun getStatusLevel_returnsStatusLevel() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .build()
-
- assertThat(safetySourceStatus.statusLevel).isEqualTo(STATUS_LEVEL_OK)
- }
-
- @Test
- fun getPendingIntent_returnsPendingIntent() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .build()
-
- assertThat(safetySourceStatus.pendingIntent).isEqualTo(pendingIntent1)
- }
-
- @Test
- fun getIconAction_withDefaultBuilder_returnsNull() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .build()
-
- assertThat(safetySourceStatus.iconAction).isNull()
- }
-
- @Test
- fun getIconAction_whenSetExplicitly_returnsIconAction() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .setIconAction(iconAction1)
- .build()
-
- assertThat(safetySourceStatus.iconAction).isEqualTo(iconAction1)
- }
-
- @Test
- fun isEnabled_withDefaultBuilder_returnsTrue() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .build()
-
- assertThat(safetySourceStatus.isEnabled).isTrue()
- }
-
- @Test
- fun isEnabled_whenSetExplicitly_returnsEnabled() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .setEnabled(false)
- .build()
-
- assertThat(safetySourceStatus.isEnabled).isFalse()
- }
-
- @Test
- fun describeContents_returns0() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .setIconAction(iconAction1)
- .build()
-
- assertThat(safetySourceStatus.describeContents()).isEqualTo(0)
- }
-
- @Test
- fun createFromParcel_withWriteToParcel_returnsOriginalSafetySourceStatus() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .setIconAction(iconAction1)
- .setEnabled(true)
- .build()
-
- val parcel: Parcel = Parcel.obtain()
- safetySourceStatus.writeToParcel(parcel, 0 /* flags */)
- parcel.setDataPosition(0)
- val safetySourceStatusFromParcel: SafetySourceStatus =
- SafetySourceStatus.CREATOR.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(safetySourceStatusFromParcel).isEqualTo(safetySourceStatus)
- }
-
- // TODO(b/208473675): Use `EqualsTester` for testing `hashcode` and `equals`.
- @Test
- fun hashCode_equals_toString_withEqualByReferenceSafetySourceStatuses_areEqual() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .setIconAction(iconAction1)
- .setEnabled(true)
- .build()
- val otherSafetySourceStatus = safetySourceStatus
-
- assertThat(safetySourceStatus.hashCode()).isEqualTo(otherSafetySourceStatus.hashCode())
- assertThat(safetySourceStatus).isEqualTo(otherSafetySourceStatus)
- assertThat(safetySourceStatus.toString()).isEqualTo(otherSafetySourceStatus.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withAllFieldsEqual_areEqual() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .setIconAction(iconAction1)
- .setEnabled(true)
- .build()
- val otherSafetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .setIconAction(iconAction1)
- .setEnabled(true)
- .build()
-
- assertThat(safetySourceStatus.hashCode()).isEqualTo(otherSafetySourceStatus.hashCode())
- assertThat(safetySourceStatus).isEqualTo(otherSafetySourceStatus)
- assertThat(safetySourceStatus.toString()).isEqualTo(otherSafetySourceStatus.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentTitles_areNotEqual() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .build()
- val otherSafetySourceStatus = SafetySourceStatus.Builder(
- "Other status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .build()
-
- assertThat(safetySourceStatus.hashCode()).isNotEqualTo(otherSafetySourceStatus.hashCode())
- assertThat(safetySourceStatus).isNotEqualTo(otherSafetySourceStatus)
- assertThat(safetySourceStatus.toString()).isNotEqualTo(otherSafetySourceStatus.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentSummaries_areNotEqual() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .build()
- val otherSafetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Other status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .build()
-
- assertThat(safetySourceStatus.hashCode()).isNotEqualTo(otherSafetySourceStatus.hashCode())
- assertThat(safetySourceStatus).isNotEqualTo(otherSafetySourceStatus)
- assertThat(safetySourceStatus.toString()).isNotEqualTo(otherSafetySourceStatus.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentStatusLevels_areNotEqual() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- pendingIntent1
- )
- .build()
- val otherSafetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_CRITICAL_WARNING,
- pendingIntent1
- )
- .build()
-
- assertThat(safetySourceStatus.hashCode()).isNotEqualTo(otherSafetySourceStatus.hashCode())
- assertThat(safetySourceStatus).isNotEqualTo(otherSafetySourceStatus)
- assertThat(safetySourceStatus.toString()).isNotEqualTo(otherSafetySourceStatus.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentPendingIntents_areNotEqual() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_OK,
- PendingIntent.getActivity(
- context, 0 /* requestCode= */,
- Intent("Status PendingIntent"), FLAG_IMMUTABLE
- )
- )
- .build()
- val otherSafetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_CRITICAL_WARNING,
- PendingIntent.getActivity(
- context, 0 /* requestCode= */,
- Intent("Other status PendingIntent"), FLAG_IMMUTABLE
- )
- )
- .build()
-
- assertThat(safetySourceStatus.hashCode()).isNotEqualTo(otherSafetySourceStatus.hashCode())
- assertThat(safetySourceStatus).isNotEqualTo(otherSafetySourceStatus)
- assertThat(safetySourceStatus.toString()).isNotEqualTo(otherSafetySourceStatus.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentIconActions_areNotEqual() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_CRITICAL_WARNING,
- pendingIntent1
- )
- .setIconAction(iconAction1)
- .build()
- val otherSafetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_CRITICAL_WARNING,
- pendingIntent1
- )
- .setIconAction(iconAction2)
- .build()
-
- assertThat(safetySourceStatus.hashCode()).isNotEqualTo(otherSafetySourceStatus.hashCode())
- assertThat(safetySourceStatus).isNotEqualTo(otherSafetySourceStatus)
- assertThat(safetySourceStatus.toString()).isNotEqualTo(otherSafetySourceStatus.toString())
- }
-
- @Test
- fun hashCode_equals_toString_withDifferentEnabled_areNotEqual() {
- val safetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_CRITICAL_WARNING,
- pendingIntent1
- )
- .setEnabled(true)
- .build()
- val otherSafetySourceStatus = SafetySourceStatus.Builder(
- "Status title",
- "Status summary",
- STATUS_LEVEL_CRITICAL_WARNING,
- pendingIntent1
- )
- .setEnabled(false)
- .build()
-
- assertThat(safetySourceStatus.hashCode()).isNotEqualTo(otherSafetySourceStatus.hashCode())
- assertThat(safetySourceStatus).isNotEqualTo(otherSafetySourceStatus)
- assertThat(safetySourceStatus.toString()).isNotEqualTo(otherSafetySourceStatus.toString())
- }
-}
\ No newline at end of file
diff --git a/tests/tests/safetycenter/src/android/safetycenter/cts/XmlConfigTest.kt b/tests/tests/safetycenter/src/android/safetycenter/cts/XmlConfigTest.kt
deleted file mode 100644
index 9b77e99..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/cts/XmlConfigTest.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.cts
-
-import android.os.Build.VERSION_CODES.TIRAMISU
-import android.safetycenter.config.SafetyCenterConfig
-import androidx.test.core.app.ApplicationProvider.getApplicationContext
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.android.safetycenter.resources.SafetyCenterResourcesContext
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
-class XmlConfigTest {
- private val safetyCenterContext = SafetyCenterResourcesContext(getApplicationContext())
-
- @Test
- fun safetyCenterConfigResource_validConfig() {
- // Assert that the parser validates the Safety Center config without throwing any exception
- assertThat(SafetyCenterConfig.fromXml(safetyCenterContext.safetyCenterConfig!!)).isNotNull()
- }
-}
diff --git a/tests/tests/safetycenter/src/android/safetycenter/testers/AnyTester.kt b/tests/tests/safetycenter/src/android/safetycenter/testers/AnyTester.kt
deleted file mode 100644
index f3fbf77..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/testers/AnyTester.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.safetycenter.testers
-
-import com.google.common.truth.Truth.assertThat
-
-/** Collection of functions to test generic objects */
-object AnyTester {
- /**
- * Asserts that two generic objects are equal and that the values returned by the [hashCode] and
- * [toString] methods for the two generic objects are also equal.
- */
- fun assertThatRepresentationsAreEqual(a: Any, b: Any) {
- assertThat(a.hashCode()).isEqualTo(b.hashCode())
- assertThat(a).isEqualTo(b)
- assertThat(a.toString()).isEqualTo(b.toString())
- }
-
- /**
- * Asserts that two generic objects are not equal and that the values returned by the [hashCode]
- * and [toString] methods for the two generic objects are also not equal.
- */
- fun assertThatRepresentationsAreNotEqual(a: Any, b: Any) {
- assertThat(a.hashCode()).isNotEqualTo(b.hashCode())
- assertThat(a).isNotEqualTo(b)
- assertThat(a.toString()).isNotEqualTo(b.toString())
- }
-}
\ No newline at end of file
diff --git a/tests/tests/safetycenter/src/android/safetycenter/testers/ParcelableTester.kt b/tests/tests/safetycenter/src/android/safetycenter/testers/ParcelableTester.kt
deleted file mode 100644
index f2c2482..0000000
--- a/tests/tests/safetycenter/src/android/safetycenter/testers/ParcelableTester.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package android.safetycenter.testers
-
-import android.os.Parcel
-import android.os.Parcelable
-import com.google.common.truth.Truth.assertThat
-
-/** Collection of functions to test [Parcelable] objects */
-object ParcelableTester {
- /**
- * Asserts that writing a [Parcelable] object to a [Parcel] and creating an object from that
- * [Parcel] returns an object that is equal to the original [Parcelable] object.
- */
- fun <T : Parcelable> assertThatRoundTripReturnsOriginal(
- parcelable: T,
- creator: Parcelable.Creator<T>
- ) {
- val parcel: Parcel = Parcel.obtain()
- parcelable.writeToParcel(parcel, 0)
- parcel.setDataPosition(0)
- val parcelableFromParcel: T = creator.createFromParcel(parcel)
- parcel.recycle()
-
- assertThat(parcelableFromParcel).isEqualTo(parcelable)
- }
-}
\ No newline at end of file
diff --git a/tests/tests/secure_element/omapi/apk/signed-CtsOmapiTestCases.apk b/tests/tests/secure_element/omapi/apk/signed-CtsOmapiTestCases.apk
index 53275fd..a53bf88 100644
--- a/tests/tests/secure_element/omapi/apk/signed-CtsOmapiTestCases.apk
+++ b/tests/tests/secure_element/omapi/apk/signed-CtsOmapiTestCases.apk
Binary files differ
diff --git a/tests/tests/security/native/encryption/Android.bp b/tests/tests/security/native/encryption/Android.bp
index 35eff99..d95cc83 100644
--- a/tests/tests/security/native/encryption/Android.bp
+++ b/tests/tests/security/native/encryption/Android.bp
@@ -17,6 +17,7 @@
],
static_libs: [
"libctssecurity_native_test_utils",
+ "libfscrypt",
],
multilib: {
lib32: {
diff --git a/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp b/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp
index b2274de..a8f87229 100644
--- a/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp
+++ b/tests/tests/security/native/encryption/FileBasedEncryptionPolicyTest.cpp
@@ -14,7 +14,12 @@
* limitations under the License.
*/
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
+#include <cutils/properties.h>
#include <fcntl.h>
+#include <fscrypt/fscrypt.h>
+#include <gtest/gtest.h>
#include <linux/fscrypt.h>
#include <setjmp.h>
#include <signal.h>
@@ -22,21 +27,12 @@
#include <sys/ioctl.h>
#include <unistd.h>
-#include <android-base/unique_fd.h>
-#include <cutils/properties.h>
-#include <gtest/gtest.h>
-
#include "utils.h"
// Non-upstream encryption modes that are used on some devices.
#define FSCRYPT_MODE_AES_256_HEH 126
#define FSCRYPT_MODE_PRIVATE 127
-// The relevant Android API levels
-#define Q_API_LEVEL 29
-#define R_API_LEVEL 30
-#define S_API_LEVEL 31
-
#ifdef __arm__
// For ARM32, assemble the 'aese.8' instruction as an .inst, since otherwise
// clang does not accept it. It would be allowed in a separate file compiled
@@ -179,9 +175,10 @@
// likely case where this requirement wouldn't be met is a misconfiguration
// where FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 ("emmc_optimized" in the fstab) is
// used on a non-eMMC based device. CTS can test for that, so we do so below.
-static void validateEncryptionFlags(int flags) {
+static void validateEncryptionFlags(int flags, bool is_adoptable_storage) {
if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) {
EXPECT_TRUE(mightBeUsingEmmcStorage());
+ EXPECT_FALSE(is_adoptable_storage);
}
}
@@ -192,14 +189,53 @@
// way to configure different directories to use different algorithms...
#define DIR_TO_CHECK "/data/local/tmp/"
-// Test that the device is using appropriate encryption algorithms for
-// file-based encryption. If this test fails, you should ensure the device's
-// fstab has the correct fileencryption= option for the userdata partition. See
+static std::string loggedGetProperty(const std::string &name, const std::string &default_value) {
+ auto value = android::base::GetProperty(name, "");
+ if (value == "" && default_value != "") {
+ GTEST_LOG_(INFO) << name << "=\"\" [defaults to \"" << default_value << "\"]";
+ return default_value;
+ }
+ GTEST_LOG_(INFO) << name << "=\"" << value << "\"";
+ return value;
+}
+
+static void validateAdoptableStorageSettings(int first_api_level) {
+ GTEST_LOG_(INFO) << "Validating FBE settings for adoptable storage";
+
+ // Determine the options string being used. This matches the logic in vold.
+ auto contents_mode = loggedGetProperty("ro.crypto.volume.contents_mode", "");
+ auto filenames_mode =
+ loggedGetProperty("ro.crypto.volume.filenames_mode",
+ first_api_level > __ANDROID_API_Q__ ? "" : "aes-256-heh");
+ auto options_string =
+ loggedGetProperty("ro.crypto.volume.options", contents_mode + ":" + filenames_mode);
+
+ // Parse the options string.
+ android::fscrypt::EncryptionOptions options;
+ ASSERT_TRUE(android::fscrypt::ParseOptions(options_string, &options));
+
+ // Log the full options for debugging purposes.
+ std::string options_string_full;
+ ASSERT_TRUE(android::fscrypt::OptionsToString(options, &options_string_full));
+ GTEST_LOG_(INFO) << "options_string_full=\"" << options_string_full << "\"";
+
+ // Validate the encryption options.
+ if (first_api_level > __ANDROID_API_Q__) {
+ // CDD 9.9.3/C-1-13 and 9.9.3/C-1-14, same as internal storage.
+ EXPECT_EQ(2, options.version);
+ }
+ validateEncryptionModes(options.contents_mode, options.filenames_mode, options.version == 1);
+ validateEncryptionFlags(options.flags, true);
+}
+
+// Test that the device is using appropriate settings for file-based encryption.
+// If this test fails, you should ensure that the device's fstab has the correct
+// fileencryption= option for the userdata partition and that the ro.crypto
+// system properties have been set to the correct values. See
// https://source.android.com/security/encryption/file-based.html
TEST(FileBasedEncryptionPolicyTest, allowedPolicy) {
int first_api_level = getFirstApiLevel();
int vendor_api_level = getVendorApiLevel();
- char crypto_type[PROPERTY_VALUE_MAX];
struct fscrypt_get_policy_ex_arg arg;
int res;
int contents_mode;
@@ -207,13 +243,7 @@
int flags;
bool allow_legacy_modes = false;
- android::base::unique_fd fd(open(DIR_TO_CHECK, O_RDONLY | O_CLOEXEC));
- if (fd < 0) {
- FAIL() << "Failed to open " DIR_TO_CHECK ": " << strerror(errno);
- }
-
- property_get("ro.crypto.type", crypto_type, "");
- GTEST_LOG_(INFO) << "ro.crypto.type is '" << crypto_type << "'";
+ std::string crypto_type = loggedGetProperty("ro.crypto.type", "");
GTEST_LOG_(INFO) << "First API level is " << first_api_level;
GTEST_LOG_(INFO) << "Vendor API level is " << vendor_api_level;
@@ -221,13 +251,20 @@
// SC or later.
int min_api_level = (first_api_level < vendor_api_level) ? first_api_level
: vendor_api_level;
- if (min_api_level >= S_API_LEVEL &&
- !deviceSupportsFeature("android.hardware.security.model.compatible")) {
+ if (min_api_level >= __ANDROID_API_S__ &&
+ !deviceSupportsFeature("android.hardware.security.model.compatible")) {
GTEST_SKIP()
<< "Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.";
return;
}
+ GTEST_LOG_(INFO) << "Validating FBE settings for internal storage";
+
+ android::base::unique_fd fd(open(DIR_TO_CHECK, O_RDONLY | O_CLOEXEC));
+ if (fd < 0) {
+ FAIL() << "Failed to open " DIR_TO_CHECK ": " << strerror(errno);
+ }
+
// Note: SELinux policy allows the shell domain to use these ioctls, but not
// apps. Therefore this test needs to be a real native test that's run
// through the shell, not a JNI test run through an installed APK.
@@ -246,12 +283,12 @@
// Starting with Android 10, file-based encryption is required on
// new devices [CDD 9.9.2/C-0-3].
- if (first_api_level < Q_API_LEVEL) {
+ if (first_api_level < __ANDROID_API_Q__) {
GTEST_LOG_(INFO)
<< "Exempt from file-based encryption due to old starting API level";
return;
}
- if (strcmp(crypto_type, "managed") == 0) {
+ if (crypto_type == "managed") {
// Android is running in a virtualized environment and the file system is encrypted
// by the host system.
GTEST_LOG_(INFO) << "Exempt from file-based encryption because the file system is "
@@ -278,9 +315,9 @@
// never be never reused for different cryptographic purposes
// [CDD 9.9.3/C-1-14]. Effectively, these requirements mean that
// the fscrypt policy version must not be v1. If this part of the
- // test fails, make sure the device's fstab has something like
- // "fileencryption=aes-256-xts:aes-256-cts:v2".
- if (first_api_level < R_API_LEVEL) {
+ // test fails, make sure the device's fstab doesn't contain the "v1"
+ // flag in the argument to the fileencryption option.
+ if (first_api_level < __ANDROID_API_R__) {
GTEST_LOG_(INFO) << "Exempt from non-reversible FBE key derivation due to old "
"starting API level";
// On these old devices we also allow the use of some custom
@@ -305,6 +342,7 @@
GTEST_LOG_(INFO) << "Filenames encryption mode: " << filenames_mode;
validateEncryptionModes(contents_mode, filenames_mode, allow_legacy_modes);
+ validateEncryptionFlags(flags, false);
- validateEncryptionFlags(flags);
+ validateAdoptableStorageSettings(first_api_level);
}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0341.java b/tests/tests/security/src/android/security/cts/CVE_2021_0341.java
new file mode 100644
index 0000000..130dce5
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0341.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeNotNull;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateFactory;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionBindingEvent;
+import javax.net.ssl.SSLSessionBindingListener;
+import javax.net.ssl.SSLSessionContext;
+import javax.security.cert.CertificateException;
+
+// Taken reference from
+// libcore/support/src/test/java/org/apache/harmony/xnet/tests/support/mySSLSession.java
+class CVE_2021_0341_SSLSession implements SSLSession {
+
+ private byte[] idData;
+ private String nameHost = null;
+ private int namePort = -1;
+ private Hashtable table;
+ private boolean invalidateDone = false;
+ private Certificate[] certs = null;
+ private javax.security.cert.X509Certificate[] xCerts = null;
+
+ public CVE_2021_0341_SSLSession(Certificate[] xc)
+ throws CertificateEncodingException, CertificateException {
+ certs = xc;
+ xCerts = new javax.security.cert.X509Certificate[xc.length];
+ int i = 0;
+ for (Certificate cert : xc) {
+ xCerts[i++] = javax.security.cert.X509Certificate.getInstance(cert.getEncoded());
+ }
+ }
+
+ public int getApplicationBufferSize() {
+ return 1234567;
+ }
+
+ public String getCipherSuite() {
+ return "SuiteName";
+ }
+
+ public long getCreationTime() {
+ return 1000L;
+ }
+
+ public byte[] getId() {
+ return idData;
+ }
+
+ public long getLastAccessedTime() {
+ return 2000L;
+ }
+
+ public Certificate[] getLocalCertificates() {
+ return null;
+ }
+
+ public Principal getLocalPrincipal() {
+ return null;
+ }
+
+ public int getPacketBufferSize() {
+ return 12345;
+ }
+
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ assumeFalse("peer not authenticated", (certs == null));
+ return certs;
+ }
+
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ assumeFalse("peer not authenticated", (xCerts == null));
+ return xCerts;
+ }
+
+ public String getPeerHost() {
+ return nameHost;
+ }
+
+ public int getPeerPort() {
+ return namePort;
+ }
+
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ return null;
+ }
+
+ public String getProtocol() {
+ return "ProtocolName";
+ }
+
+ public SSLSessionContext getSessionContext() {
+ return null;
+ }
+
+ public void putValue(String s, Object obj) {
+ assumeFalse("arguments can not be null", (s == null || obj == null));
+ Object obj1 = table.put(s, obj);
+ if (obj1 instanceof SSLSessionBindingListener) {
+ SSLSessionBindingEvent sslsessionbindingevent = new SSLSessionBindingEvent(this, s);
+ ((SSLSessionBindingListener) obj1).valueUnbound(sslsessionbindingevent);
+ }
+ if (obj instanceof SSLSessionBindingListener) {
+ SSLSessionBindingEvent sslsessionbindingevent1 = new SSLSessionBindingEvent(this, s);
+ ((SSLSessionBindingListener) obj).valueBound(sslsessionbindingevent1);
+ }
+ }
+
+ public void removeValue(String s) {
+ assumeFalse("argument can not be null", (s == null));
+ Object obj = table.remove(s);
+ if (obj instanceof SSLSessionBindingListener) {
+ SSLSessionBindingEvent sslsessionbindingevent = new SSLSessionBindingEvent(this, s);
+ ((SSLSessionBindingListener) obj).valueUnbound(sslsessionbindingevent);
+ }
+ }
+
+ public Object getValue(String s) {
+ assumeFalse("argument can not be null", (s == null));
+ return table.get(s);
+ }
+
+ public String[] getValueNames() {
+ Vector vector = new Vector();
+ Enumeration enumeration = table.keys();
+ while (enumeration.hasMoreElements()) {
+ vector.addElement(enumeration.nextElement());
+ }
+ String as[] = new String[vector.size()];
+ vector.copyInto(as);
+ return as;
+ }
+
+ public void invalidate() {
+ invalidateDone = true;
+ }
+
+ public boolean isValid() {
+ return invalidateDone;
+ }
+}
+
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2021_0341 {
+
+ public final static byte[] X509_TEST_CERTIFICATE = ("-----BEGIN CERTIFICATE-----\n"
+ + "MIIC3DCCAcSgAwIBAgIURJspNgSx6GVbOLijqravWoGlm+0wDQYJKoZIhvcNAQEL\n"
+ + "BQAwETEPMA0GA1UECgwGZ29vZ2xlMB4XDTIyMDIxNzExNTE1NFoXDTMxMTExNzEx\n"
+ + "NTE1NFowETEPMA0GA1UECgwGZ29vZ2xlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n"
+ + "MIIBCgKCAQEA2PxVfeoY/uA66aVRXpuZXodTBFBGowTt/lAJxR8fVjDwRTOrRTrr\n"
+ + "2qdLPPK40lFQOSfHw/g6+9WjNjjSDBP+U2Agrvo8cU5R1DwJWyK2wcHOtBcL2bsj\n"
+ + "kRx18CZtZUu51a8KEhMCaIoHgGzwGMZkJnfmfO9ABbMfFsyn6KxFf0MXG3bRcQU7\n"
+ + "LyCXyQbo2Lal68QiTMXZs9rXN/a8ex+RmP9PKaXIEsIOeDrtLhzcWyNjrtTuDRoR\n"
+ + "K49xHOpz4EmqHLDzIKuhqyyo9tLR+okK0BRJoNxmfvRTbxNbjzpTTFgyB4KrKBCO\n"
+ + "VQXJROlBf7594xlCMn0QSwElVT4bMaMw/QIDAQABoywwKjAoBgNVHREEITAfggkq\n"
+ + "LmJhci5jb22CEiou44Kw44O844Kw44OrLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEA\n"
+ + "piIwY84InjX4BUmAmM+D9CHD/9euucGxgdXqL6kKG1HRL6lHfwZAIxhlbn3jWFEx\n"
+ + "k5DTkaL039FGLvYzMI0McwTIuHY/7JwCbZUJ3pVl0waW4sab+2LScnpe9c422Tqb\n"
+ + "hECEhc71E/kRlG9FjQN3wjEj3RcnWZAWCqAnJN/dcd/1tBD88tzHVckDC9mSvxzP\n"
+ + "hkmIRRifIDxcrmx7PkpJ6dAfiw9e1Pl5THdsPTDtiGJ4hjlsAi8ury3rrx31lsyo\n"
+ + "kAwQy23Q7Rcbr2z8bijDuSWWWc9RRsz+O/ePy35NJci/RUwVFTpvOFtahC30Jdv3\n"
+ + "vpmqxLqEF7Z9I1yb3Q6YUg==\n" + "-----END CERTIFICATE-----\n").getBytes();
+
+ /**
+ * b/171980069
+ */
+ @AsbSecurityTest(cveBugId = 171980069)
+ @Test
+ public void testPocCVE_2021_0341() throws Exception {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ assumeNotNull(cf);
+ HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
+ assumeNotNull(verifier);
+ InputStream in = new ByteArrayInputStream(X509_TEST_CERTIFICATE);
+ java.security.cert.X509Certificate x509 =
+ (java.security.cert.X509Certificate) cf.generateCertificate(in);
+ assumeNotNull(x509);
+ CVE_2021_0341_SSLSession session =
+ new CVE_2021_0341_SSLSession(new java.security.cert.X509Certificate[] {x509});
+ assertFalse(verifier.verify("\u82b1\u5b50.bar.com", session));
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java b/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java
index b43f489..91e39e8 100644
--- a/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java
+++ b/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java
@@ -15,6 +15,7 @@
*/
package android.security.cts;
+import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -25,8 +26,8 @@
import android.platform.test.annotations.AsbSecurityTest;
import android.security.cts.IIsolatedService;
import android.security.cts.IsolatedService;
-import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
import com.android.internal.util.ArrayUtils;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -39,7 +40,7 @@
import org.junit.Test;
@RunWith(AndroidJUnit4.class)
-public class IsolatedProcessTest extends StsExtraBusinessLogicTestCase {
+public class IsolatedProcessTest {
static final String TAG = IsolatedProcessTest.class.getSimpleName();
private static final long BIND_SERVICE_TIMEOUT = 5000;
@@ -72,6 +73,10 @@
}
};
+ private static Instrumentation getInstrumentation() {
+ return InstrumentationRegistry.getInstrumentation();
+ }
+
@Before
public void setUp() throws InterruptedException {
mLatch = new CountDownLatch(1);
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerCtsTestsBase.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerCtsTestsBase.java
index 4271f74..5ec9a90 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerCtsTestsBase.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerCtsTestsBase.java
@@ -18,6 +18,7 @@
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.*;
import android.app.Activity;
+import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
@@ -648,6 +649,7 @@
protected boolean isAppSearchEnabled() {
return SystemUtil.runWithShellPermissionIdentity(() ->
DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
- "shortcut_appsearch_integration", true));
+ "shortcut_appsearch_integration", true))
+ && !getTestContext().getSystemService(ActivityManager.class).isLowRamDevice();
}
}
diff --git a/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_ContentNotificationsTest.java b/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_ContentNotificationsTest.java
index 1bbf1dd..e9162ff 100644
--- a/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_ContentNotificationsTest.java
+++ b/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_ContentNotificationsTest.java
@@ -20,18 +20,13 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.hamcrest.Matchers.oneOf;
import static org.junit.Assume.assumeThat;
-import static org.junit.Assume.assumeTrue;
-
-import static java.util.concurrent.TimeUnit.SECONDS;
import android.Manifest;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
@@ -40,7 +35,6 @@
import android.provider.SimPhonebookContract.ElementaryFiles;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider;
@@ -50,9 +44,6 @@
import com.android.compatibility.common.util.RequiredFeatureRule;
import com.android.compatibility.common.util.SystemUtil;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.google.common.util.concurrent.SettableFuture;
-
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Before;
@@ -155,60 +146,6 @@
DEFAULT_TIMEOUT, () -> mObserver.observed.size() > 1);
}
- @Test
- public void subscriptionsChange_notifiesObserver() throws Exception {
- Resources resources = ApplicationProvider.getApplicationContext().getResources();
- int id = resources.getIdentifier("config_hotswapCapable", "bool", "android");
- boolean hotswapCapable = resources.getBoolean(id);
- assumeTrue("Device does not support SIM hot swap", hotswapCapable);
- assumeThat(mSubscriptionInfo, Matchers.notNullValue());
- try {
- setSimPower(0);
-
- PollingCheck.check(
- "No content notifications observed for SIM removal",
- DEFAULT_TIMEOUT, () -> mObserver.observed.size() >= 1);
- // It takes some time the SIM state transitions to finish so we sleep a bit to attempt
- // to allow the notifications they trigger to stop so that the notifications we observe
- // for the power on aren't polluted by the power off.
- Thread.sleep(DEFAULT_TIMEOUT);
- mObserver.observed.clear();
- } finally {
- setSimPower(1);
- }
- PollingCheck.check(
- "No content notifications observed for SIM insertion",
- DEFAULT_TIMEOUT, () -> mObserver.observed.size() >= 1);
- }
-
- private void setSimPower(int powerState) throws Exception {
- TelephonyManager telephonyManager = ApplicationProvider.getApplicationContext()
- .getSystemService(TelephonyManager.class);
- int slotIndex = mSubscriptionInfo.getSimSlotIndex();
- SettableFuture<Integer> resultFuture = SettableFuture.create();
- SystemUtil.runWithShellPermissionIdentity(() -> telephonyManager.setSimPowerStateForSlot(
- mSubscriptionInfo.getSimSlotIndex(), powerState,
- MoreExecutors.directExecutor(), resultFuture::set),
- Manifest.permission.MODIFY_PHONE_STATE, Manifest.permission.READ_PHONE_STATE);
-
- int result = resultFuture.get(30, SECONDS);
- assumeThat("setSimPowerStateForSlot failed for slot=" + slotIndex,
- result, oneOf(
- TelephonyManager.SET_SIM_POWER_STATE_ALREADY_IN_STATE,
- TelephonyManager.SET_SIM_POWER_STATE_SUCCESS));
- Thread.sleep(DEFAULT_TIMEOUT);
- int simState = SystemUtil.runWithShellPermissionIdentity(() ->
- telephonyManager.getSimState(slotIndex),
- Manifest.permission.READ_PHONE_STATE);
- // This doesn't work on Cuttlefish so confirm the SIM was actually powered off.
- if(powerState == 1) {
- assumeThat(simState, Matchers.is(TelephonyManager.SIM_STATE_READY));
- } else {
- assumeThat(simState, Matchers.is(oneOf(TelephonyManager.SIM_STATE_ABSENT,
- TelephonyManager.SIM_STATE_NOT_READY)));
- }
- }
-
private static class RecordingContentObserver extends ContentObserver {
List<Uri> observed = new CopyOnWriteArrayList<>();
diff --git a/tests/tests/telecom/AndroidManifest.xml b/tests/tests/telecom/AndroidManifest.xml
index 96a07b3..1b1d48e 100644
--- a/tests/tests/telecom/AndroidManifest.xml
+++ b/tests/tests/telecom/AndroidManifest.xml
@@ -79,6 +79,14 @@
</intent-filter>
</service>
+ <service android:name="android.telecom.cts.NullBindingConnectionService"
+ android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.telecom.ConnectionService"/>
+ </intent-filter>
+ </service>
+
<service android:name="android.telecom.cts.MockInCallService"
android:permission="android.permission.BIND_INCALL_SERVICE"
android:exported="true">
diff --git a/tests/tests/telecom/src/android/telecom/cts/NullBindingConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/NullBindingConnectionService.java
new file mode 100644
index 0000000..161d3ef
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/NullBindingConnectionService.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom.cts;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * A minimal {@link Service} implementation intended to test cases where a {@link ConnectionService}
+ * tries to return a null binding.
+ */
+public class NullBindingConnectionService extends Service {
+ public static CountDownLatch sBindLatch = new CountDownLatch(1);
+ public static CountDownLatch sUnbindLatch = new CountDownLatch(1);
+
+ public NullBindingConnectionService() {
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ CountDownLatch latch = sBindLatch;
+ sUnbindLatch = new CountDownLatch(1);
+ latch.countDown();
+ return null;
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ CountDownLatch latch = sUnbindLatch;
+ sBindLatch = new CountDownLatch(1);
+ latch.countDown();
+ return false;
+ }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/NullBindingTest.java b/tests/tests/telecom/src/android/telecom/cts/NullBindingTest.java
new file mode 100644
index 0000000..611eeab
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/NullBindingTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom.cts;
+
+import android.content.ComponentName;
+import android.net.Uri;
+import android.os.Bundle;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+
+/**
+ * CTS tests to ensure that a ConnectionService which returns a null binding will be automatically
+ * unbound.
+ */
+
+public class NullBindingTest extends BaseTelecomTestWithMockServices {
+ private static final PhoneAccountHandle TEST_NULL_BINDING_HANDLE =
+ new PhoneAccountHandle(new ComponentName("android.telecom.cts",
+ "android.telecom.cts.NullBindingConnectionService"),
+ "1");
+
+ public static final PhoneAccount TEST_NULL_BINDING_ACCOUNT = PhoneAccount.builder(
+ TEST_NULL_BINDING_HANDLE, "Null")
+ .setAddress(Uri.parse("sip:test@test.com"))
+ .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
+ .addSupportedUriScheme(PhoneAccount.SCHEME_SIP)
+ .build();
+
+ private static final Uri TEST_ADDRESS_1 = Uri.fromParts("sip", "call1@test.com", null);
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mContext = getInstrumentation().getContext();
+ if (mShouldTestTelecom) {
+ mTelecomManager.registerPhoneAccount(TEST_NULL_BINDING_ACCOUNT);
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ if (mShouldTestTelecom) {
+ mTelecomManager.unregisterPhoneAccount(TEST_NULL_BINDING_HANDLE);
+ }
+ }
+
+ /**
+ * Ensures that when we bind to a ConnectionService which returns a null binding that the
+ * ConnectionService is unbound automatically.
+ */
+ public void testNullBinding() {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+
+ // Place a call using the null binding connection service.
+ Bundle extras = new Bundle();
+ extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, TEST_NULL_BINDING_HANDLE);
+ mTelecomManager.placeCall(TEST_ADDRESS_1, extras);
+
+ // Ensure it bound and then unbound.
+ assertTrue(TestUtils.waitForLatchCountDown(NullBindingConnectionService.sBindLatch));
+ assertTrue(TestUtils.waitForLatchCountDown(NullBindingConnectionService.sUnbindLatch));
+
+ // Ensure there is no call present in Telecom
+ assertFalse(mTelecomManager.isInCall());
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/DataServiceCallbackTest.java b/tests/tests/telephony/current/src/android/telephony/cts/DataServiceCallbackTest.java
new file mode 100644
index 0000000..1142fef
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/DataServiceCallbackTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.net.InetAddresses;
+import android.net.LinkAddress;
+import android.os.IBinder;
+import android.telephony.data.ApnSetting;
+import android.telephony.data.DataCallResponse;
+import android.telephony.data.DataProfile;
+import android.telephony.data.DataServiceCallback;
+import android.telephony.data.IDataServiceCallback;
+import android.telephony.data.NetworkSliceInfo;
+import android.telephony.data.TrafficDescriptor;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class DataServiceCallbackTest {
+ private static final int RESULT = DataServiceCallback.RESULT_SUCCESS;
+ private static final int ID = 1;
+ private static final int PROTOCOL_TYPE = ApnSetting.PROTOCOL_IP;
+ private static final int MTU_V4 = 1440;
+ private static final int MTU_V6 = 1400;
+ private static final TrafficDescriptor TRAFFIC_DESCRIPTOR = new TrafficDescriptor(
+ "DNN", new byte[]{-105, -92, -104, -29, -4, -110, 92, -108, -119, -122, 3, 51, -48, 110,
+ 78, 71, 10, 69, 78, 84, 69, 82, 80, 82, 73, 83, 69});
+ private static final DataCallResponse DATA_CALL_RESPONSE = new DataCallResponse.Builder()
+ .setCause(0)
+ .setRetryDurationMillis(-1L)
+ .setId(ID)
+ .setLinkStatus(2)
+ .setProtocolType(PROTOCOL_TYPE)
+ .setInterfaceName("IF_NAME")
+ .setAddresses(Arrays.asList(
+ new LinkAddress(InetAddresses.parseNumericAddress("99.88.77.66"), 0)))
+ .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("55.66.77.88")))
+ .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress("11.22.33.44")))
+ .setPcscfAddresses(Arrays.asList(InetAddresses.parseNumericAddress("22.33.44.55")))
+ .setMtuV4(MTU_V4)
+ .setMtuV6(MTU_V6)
+ .setHandoverFailureMode(DataCallResponse.HANDOVER_FAILURE_MODE_DO_FALLBACK)
+ .setPduSessionId(5)
+ .setSliceInfo(new NetworkSliceInfo.Builder()
+ .setSliceServiceType(NetworkSliceInfo.SLICE_SERVICE_TYPE_EMBB)
+ .setSliceDifferentiator(1)
+ .setMappedHplmnSliceDifferentiator(10)
+ .setMappedHplmnSliceServiceType(NetworkSliceInfo.SLICE_SERVICE_TYPE_MIOT)
+ .build())
+ .setTrafficDescriptors(Arrays.asList(TRAFFIC_DESCRIPTOR))
+ .build();
+ private static final List<DataCallResponse> DATA_CALL_LIST = Arrays.asList(DATA_CALL_RESPONSE);
+ private static final String APN = "FAKE_APN";
+ private static final DataProfile DATA_PROFILE = new DataProfile.Builder()
+ .setApnSetting(new ApnSetting.Builder()
+ .setEntryName(APN)
+ .setApnName(APN)
+ .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT)
+ .setAuthType(ApnSetting.AUTH_TYPE_NONE)
+ .setCarrierEnabled(true)
+ .setModemCognitive(true)
+ .setMtuV4(MTU_V4)
+ .setMtuV6(MTU_V6)
+ .setNetworkTypeBitmask(ApnSetting.TYPE_DEFAULT)
+ .setProfileId(ID)
+ .setPassword("PASSWORD")
+ .setProtocol(PROTOCOL_TYPE)
+ .setRoamingProtocol(PROTOCOL_TYPE)
+ .setUser("USER_NAME")
+ .build())
+ .setPreferred(true)
+ .setType(DataProfile.TYPE_COMMON)
+ .setTrafficDescriptor(TRAFFIC_DESCRIPTOR)
+ .build();
+
+ DataServiceCallback mDataServiceCallback;
+ int mResult;
+ DataCallResponse mResponse;
+ List<DataCallResponse> mDataCallList;
+ String mApn;
+ DataProfile mDataProfile;
+
+ private class TestDataServiceCallback implements IDataServiceCallback {
+ public void onSetupDataCallComplete(int result, DataCallResponse response) {
+ mResult = result;
+ mResponse = response;
+ }
+
+ public void onDeactivateDataCallComplete(int result) {
+ mResult = result;
+ }
+
+ public void onSetInitialAttachApnComplete(int result) {
+ mResult = result;
+ }
+
+ public void onSetDataProfileComplete(int result) {
+ mResult = result;
+ }
+
+ public void onRequestDataCallListComplete(int result, List<DataCallResponse> dataCallList) {
+ mResult = result;
+ mDataCallList = dataCallList;
+ }
+
+ public void onDataCallListChanged(List<DataCallResponse> dataCallList) {
+ mDataCallList = dataCallList;
+ }
+
+ public void onHandoverStarted(int result) {
+ mResult = result;
+ }
+
+ public void onHandoverCancelled(int result) {
+ mResult = result;
+ }
+
+ public void onApnUnthrottled(String apn) {
+ mApn = apn;
+ }
+
+ public void onDataProfileUnthrottled(DataProfile dataProfile) {
+ mDataProfile = dataProfile;
+ }
+
+ public IBinder asBinder() {
+ return null;
+ }
+ }
+
+ @Before
+ public void setUp() {
+ mDataServiceCallback = new DataServiceCallback(new TestDataServiceCallback());
+ }
+
+ @Test
+ public void testOnSetupDataCallComplete() {
+ mDataServiceCallback.onSetupDataCallComplete(RESULT, DATA_CALL_RESPONSE);
+ assertThat(RESULT).isEqualTo(mResult);
+ assertThat(DATA_CALL_RESPONSE).isEqualTo(mResponse);
+ }
+
+ @Test
+ public void testOnDeactivateDataCallComplete() {
+ mDataServiceCallback.onDeactivateDataCallComplete(RESULT);
+ assertThat(RESULT).isEqualTo(mResult);
+ }
+
+ @Test
+ public void testOnSetInitialAttachApnComplete() {
+ mDataServiceCallback.onSetInitialAttachApnComplete(RESULT);
+ assertThat(RESULT).isEqualTo(mResult);
+ }
+
+ @Test
+ public void testOnSetDataProfileComplete() {
+ mDataServiceCallback.onSetDataProfileComplete(RESULT);
+ assertThat(RESULT).isEqualTo(mResult);
+ }
+
+ @Test
+ public void testOnRequestDataCallListComplete() {
+ mDataServiceCallback.onRequestDataCallListComplete(RESULT, DATA_CALL_LIST);
+ assertThat(RESULT).isEqualTo(mResult);
+ assertThat(DATA_CALL_LIST).isEqualTo(mDataCallList);
+ }
+
+ @Test
+ public void testOnDataCallListChanged() {
+ mDataServiceCallback.onDataCallListChanged(DATA_CALL_LIST);
+ assertThat(DATA_CALL_LIST).isEqualTo(mDataCallList);
+ }
+ @Test
+ public void testOnHandoverStarted() {
+ mDataServiceCallback.onHandoverStarted(RESULT);
+ assertThat(RESULT).isEqualTo(mResult);
+ }
+
+ @Test
+ public void testOnHandoverCancelled() {
+ mDataServiceCallback.onHandoverCancelled(RESULT);
+ assertThat(RESULT).isEqualTo(mResult);
+ }
+
+ @Test
+ public void testOnApnUnthrottled() {
+ mDataServiceCallback.onApnUnthrottled(APN);
+ assertThat(RESULT).isEqualTo(mResult);
+ assertThat(APN).isEqualTo(mApn);
+ }
+
+ @Test
+ public void testOnDataProfileUnthrottled() {
+ mDataServiceCallback.onDataProfileUnthrottled(DATA_PROFILE);
+ assertThat(RESULT).isEqualTo(mResult);
+ assertThat(DATA_PROFILE).isEqualTo(mDataProfile);
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SipManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SipManagerTest.java
deleted file mode 100644
index 9cd1ff3..0000000
--- a/tests/tests/telephony/current/src/android/telephony/cts/SipManagerTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.cts;
-
-import static androidx.test.InstrumentationRegistry.getContext;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.net.sip.SipException;
-import android.net.sip.SipManager;
-import android.net.sip.SipProfile;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.text.ParseException;
-import java.util.List;
-
-public class SipManagerTest {
- private Context mContext;
- private SipManager mSipManager;
- private static final String SIP_URI1 = "test1";
- private static final String SIP_URI2 = "test2";
-
- @Before
- public void setUp() {
- mContext = getContext();
- mSipManager = SipManager.newInstance(mContext);
- }
-
- @After
- public void tearDown() throws SipException {
- if (mSipManager != null) {
- for (SipProfile profile : mSipManager.getProfiles()) {
- mSipManager.close(profile.getUriString());
- }
- }
- }
-
- @Test
- public void testGetProfiles() throws SipException, ParseException {
- if (!SipManager.isApiSupported(mContext)) {
- return;
- }
- SipProfile sipProfile1 = new SipProfile.Builder(SIP_URI1).build();
- SipProfile sipProfile2 = new SipProfile.Builder(SIP_URI2).build();
- mSipManager.open(sipProfile1);
- mSipManager.open(sipProfile2);
- List<SipProfile> profiles = mSipManager.getProfiles();
- assertEquals(2, profiles.size());
- assertTrue(profiles.get(0).getUriString().contains(SIP_URI2));
- assertTrue(profiles.get(1).getUriString().contains(SIP_URI1));
- }
-}
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 aa02b4e..cb80083 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -3581,6 +3581,7 @@
(tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_THERMAL,
false));
+ waitForMs(500);
boolean isDataEnabledForReason = ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, (tm) -> tm.isDataEnabledForReason(
TelephonyManager.DATA_ENABLED_REASON_THERMAL));
@@ -3595,6 +3596,7 @@
(tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_THERMAL,
true));
+ waitForMs(500);
isDataEnabledForReason = ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, (tm) -> tm.isDataEnabledForReason(
TelephonyManager.DATA_ENABLED_REASON_THERMAL));
@@ -3617,6 +3619,7 @@
(tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_POLICY,
false));
+ waitForMs(500);
boolean isDataEnabledForReason = ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, (tm) -> tm.isDataEnabledForReason(
TelephonyManager.DATA_ENABLED_REASON_POLICY));
@@ -3631,6 +3634,7 @@
(tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_POLICY,
true));
+ waitForMs(500);
isDataEnabledForReason = ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, (tm) -> tm.isDataEnabledForReason(
TelephonyManager.DATA_ENABLED_REASON_POLICY));
@@ -3728,6 +3732,7 @@
TelephonyManager.MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL,
!allowDataDuringVoiceCall));
+ waitForMs(500);
assertNotEquals(allowDataDuringVoiceCall,
ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, getPolicyHelper));
@@ -3737,6 +3742,7 @@
TelephonyManager.MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL,
allowDataDuringVoiceCall));
+ waitForMs(500);
assertEquals(allowDataDuringVoiceCall,
ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, getPolicyHelper));
@@ -3758,6 +3764,7 @@
TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED,
!mmsAlwaysAllowed));
+ waitForMs(500);
assertNotEquals(mmsAlwaysAllowed,
ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, getPolicyHelper));
@@ -3767,6 +3774,7 @@
TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED,
mmsAlwaysAllowed));
+ waitForMs(500);
assertEquals(mmsAlwaysAllowed,
ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, getPolicyHelper));
@@ -4821,9 +4829,22 @@
try {
mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(mSelfPackageName);
+ fail("TelephonyManager#checkCarrierPrivilegesForPackageAnyPhone must be protected "
+ + "with READ_PRIVILEGED_PHONE_STATE");
+ } catch (SecurityException expected) {
+ }
+
+ try {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity(
+ "android.permission.READ_PRIVILEGED_PHONE_STATE");
+ mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(mSelfPackageName);
} catch (SecurityException e) {
- fail("TelephonyManager#checkCarrierPrivilegesForPackageAnyPhone shouldn't require "
- + "READ_PRIVILEGED_PHONE_STATE");
+ fail("TelephonyManager#checkCarrierPrivilegesForPackageAnyPhone should not throw "
+ + "SecurityException with READ_PRIVILEGED_PHONE_STATE permission");
+ } finally {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
}
}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyRegistryManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyRegistryManagerTest.java
index e49fff9..367643c 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyRegistryManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyRegistryManagerTest.java
@@ -14,11 +14,13 @@
import android.telephony.SignalStrength;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-import android.telephony.TelephonyManager.CarrierPrivilegesListener;
+import android.telephony.TelephonyManager.CarrierPrivilegesCallback;
import android.telephony.TelephonyRegistryManager;
import android.text.TextUtils;
import android.util.Pair;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
import com.android.compatibility.common.util.ShellIdentityUtils;
@@ -26,8 +28,7 @@
import org.junit.Before;
import org.junit.Test;
-import java.util.Arrays;
-import java.util.List;
+import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -271,73 +272,143 @@
}
@Test
- public void testNotifyCarrierPrivilegesChanged() throws Exception {
+ public void testCarrierPrivilegesCallback() throws Exception {
Context context = InstrumentationRegistry.getContext();
- LinkedBlockingQueue<Pair<List<String>, int[]>> queue = new LinkedBlockingQueue(2);
- CarrierPrivilegesListener cpl =
- new CarrierPrivilegesListener() {
- @Override
- public void onCarrierPrivilegesChanged(
- List<String> privilegedPackageNames, int[] privilegedUids) {
- queue.offer(new Pair<>(privilegedPackageNames, privilegedUids));
- }
- };
- CarrierPrivilegesListener cpl2 =
- (packageNames, uids) -> queue.offer(new Pair<>(packageNames, uids));
+ LinkedBlockingQueue<Pair<Set<String>, Set<Integer>>> carrierPrivilegesQueue =
+ new LinkedBlockingQueue(2);
+ LinkedBlockingQueue<Pair<String, Integer>> carrierServiceQueue = new LinkedBlockingQueue(2);
+
+ CarrierPrivilegesCallback cpc = new TestCarrierPrivilegesCallback(carrierPrivilegesQueue,
+ carrierServiceQueue);
+ CarrierPrivilegesCallback cpc2 = new TestCarrierPrivilegesCallback(carrierPrivilegesQueue,
+ carrierServiceQueue);
+
TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
try {
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
telephonyManager,
- tm -> tm.addCarrierPrivilegesListener(0, context.getMainExecutor(), cpl));
- // Clear the initial result from registering the listener. We can't necessarily
- // guarantee this is empty so don't assert on it other than the fact we got _something_.
- // We restore this at the end of the test.
- Pair<List<String>, int[]> initialState =
- queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
- assertNotNull(initialState);
+ tm -> tm.registerCarrierPrivilegesCallback(0, context.getMainExecutor(), cpc));
+ // Clear the initial carrierPrivilegesResult from registering the listener. We can't
+ // necessarily guarantee this is empty so don't assert on it other than the fact we
+ // got _something_. We restore this at the end of the test.
+ Pair<Set<String>, Set<Integer>> initialCarrierPrivilegesState =
+ carrierPrivilegesQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ assertNotNull(initialCarrierPrivilegesState);
+ Pair<String, Integer> initialCarrierServiceState =
+ carrierServiceQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ assertNotNull(initialCarrierServiceState);
// Update state
- List<String> privilegedPackageNames =
- Arrays.asList("com.carrier.package1", "com.carrier.package2");
- int[] privilegedUids = new int[] {12345, 54321};
+ Set<String> privilegedPackageNames =
+ Set.of("com.carrier.package1", "com.carrier.package2");
+ Set<Integer> privilegedUids = Set.of(12345, 54321);
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
mTelephonyRegistryMgr,
- trm ->
- trm.notifyCarrierPrivilegesChanged(
- 0, privilegedPackageNames, privilegedUids));
- Pair<List<String>, int[]> result = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
- assertEquals(privilegedPackageNames, result.first);
- assertTrue(Arrays.equals(privilegedUids, result.second));
+ trm -> {
+ trm.notifyCarrierPrivilegesChanged(
+ 0, privilegedPackageNames, privilegedUids);
+ trm.notifyCarrierServiceChanged(0, "com.carrier.package1", 12345);
+ });
+ Pair<Set<String>, Set<Integer>> carrierPrivilegesResult =
+ carrierPrivilegesQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ assertEquals(privilegedPackageNames, carrierPrivilegesResult.first);
+ assertEquals(privilegedUids, carrierPrivilegesResult.second);
- // Registering cpl2 now immediately gets us the most recent state
+ Pair<String, Integer> carrierServiceResult =
+ carrierServiceQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ assertEquals("com.carrier.package1", carrierServiceResult.first);
+ assertEquals(12345, (long) carrierServiceResult.second);
+
+ // Update the state again, but only notify carrier privileges change this time
+ Set<String> newPrivilegedPackageNames = Set.of("com.carrier.package1",
+ "com.carrier.package3");
+ Set<Integer> newPrivilegedUids = Set.of(12345, 678910);
+
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ mTelephonyRegistryMgr,
+ trm -> {
+ trm.notifyCarrierPrivilegesChanged(
+ 0, newPrivilegedPackageNames, newPrivilegedUids);
+ });
+ // The CarrierPrivileges pkgs and UIDs should be updated
+ carrierPrivilegesResult =
+ carrierPrivilegesQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ assertEquals(newPrivilegedPackageNames, carrierPrivilegesResult.first);
+ assertEquals(newPrivilegedUids, carrierPrivilegesResult.second);
+
+ // And the CarrierService change notification should NOT be triggered
+ assertNull(carrierServiceQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
+
+ // Registering cpc2 now immediately gets us the most recent state
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
telephonyManager,
- tm -> tm.addCarrierPrivilegesListener(0, context.getMainExecutor(), cpl2));
- result = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
- assertEquals(privilegedPackageNames, result.first);
- assertTrue(Arrays.equals(privilegedUids, result.second));
+ tm -> tm.registerCarrierPrivilegesCallback(0, context.getMainExecutor(), cpc2));
+ carrierPrivilegesResult = carrierPrivilegesQueue.poll(TIMEOUT_MILLIS,
+ TimeUnit.MILLISECONDS);
+ assertEquals(newPrivilegedPackageNames, carrierPrivilegesResult.first);
+ assertEquals(newPrivilegedUids, carrierPrivilegesResult.second);
- // Removing cpl means it won't get the final callback when we restore the original state
+ carrierServiceResult = carrierServiceQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ assertEquals("com.carrier.package1", carrierServiceResult.first);
+ assertEquals(12345, (long) carrierServiceResult.second);
+
+ // Removing cpc means it won't get the final callback when we restore the original state
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
- telephonyManager, tm -> tm.removeCarrierPrivilegesListener(cpl));
+ telephonyManager, tm -> tm.unregisterCarrierPrivilegesCallback(cpc));
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
mTelephonyRegistryMgr,
- trm ->
- trm.notifyCarrierPrivilegesChanged(
- 0, initialState.first, initialState.second));
- result = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
- assertEquals(initialState.first, result.first);
- assertTrue(Arrays.equals(initialState.second, result.second));
+ trm -> {
+ trm.notifyCarrierPrivilegesChanged(
+ 0, initialCarrierPrivilegesState.first,
+ initialCarrierPrivilegesState.second);
+ trm.notifyCarrierServiceChanged(0, initialCarrierServiceState.first,
+ initialCarrierServiceState.second);
+ });
+
+ carrierPrivilegesResult = carrierPrivilegesQueue.poll(TIMEOUT_MILLIS,
+ TimeUnit.MILLISECONDS);
+ assertEquals(initialCarrierPrivilegesState.first, carrierPrivilegesResult.first);
+ assertEquals(initialCarrierPrivilegesState.second, carrierPrivilegesResult.second);
+
+ carrierServiceResult = carrierServiceQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ assertEquals(initialCarrierServiceState.first, carrierServiceResult.first);
+ assertEquals(initialCarrierServiceState.second, carrierServiceResult.second);
+
// No further callbacks received
- assertNull(queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
+ assertNull(carrierPrivilegesQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
+ assertNull(carrierServiceQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
} finally {
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
telephonyManager,
tm -> {
- tm.removeCarrierPrivilegesListener(cpl); // redundant, but still allowed
- tm.removeCarrierPrivilegesListener(cpl2);
+ tm.unregisterCarrierPrivilegesCallback(cpc); // redundant, but still allowed
+ tm.unregisterCarrierPrivilegesCallback(cpc2);
});
}
}
+
+ private class TestCarrierPrivilegesCallback implements CarrierPrivilegesCallback {
+ LinkedBlockingQueue<Pair<Set<String>, Set<Integer>>> mCarrierPrivilegesQueue;
+ LinkedBlockingQueue<Pair<String, Integer>> mCarrierServiceQueue;
+
+ TestCarrierPrivilegesCallback(
+ LinkedBlockingQueue<Pair<Set<String>, Set<Integer>>> carrierPrivilegesQueue,
+ LinkedBlockingQueue<Pair<String, Integer>> carrierServiceQueue) {
+ mCarrierPrivilegesQueue = carrierPrivilegesQueue;
+ mCarrierServiceQueue = carrierServiceQueue;
+ }
+
+ @Override
+ public void onCarrierPrivilegesChanged(@NonNull Set<String> privilegedPackageNames,
+ @NonNull Set<Integer> privilegedUids) {
+ mCarrierPrivilegesQueue.offer(new Pair<>(privilegedPackageNames, privilegedUids));
+ }
+
+ @Override
+ public void onCarrierServiceChanged(@Nullable String carrierServicePackageName,
+ int carrierServiceUid) {
+ mCarrierServiceQueue.offer(new Pair<>(carrierServicePackageName, carrierServiceUid));
+ }
+ }
}
diff --git a/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java b/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java
index e604c57..2cb2ecc 100644
--- a/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java
@@ -35,6 +35,7 @@
import android.telephony.euicc.EuiccCardManager;
import android.telephony.euicc.EuiccInfo;
import android.telephony.euicc.EuiccManager;
+import android.text.TextUtils;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -595,21 +596,11 @@
if (cardInfo.isEuicc()) {
for (UiccPortInfo portInfo : portInfoList) {
// Check if port is active and no profile install on it.
- if (portInfo.isActive() && portInfo.getIccId() == null) {
+ if (portInfo.isActive() && TextUtils.isEmpty(portInfo.getIccId())) {
boolean result = mEuiccManager.isSimPortAvailable(portInfo.getPortIndex());
assertTrue(result);
- } else {
- // Port is not available.
- boolean result = mEuiccManager.isSimPortAvailable(portInfo.getPortIndex());
- assertFalse(result);
}
}
- } else {
- for (UiccPortInfo portInfo : portInfoList) {
- // Port is not Euicc.
- boolean result = mEuiccManager.isSimPortAvailable(portInfo.getPortIndex());
- assertFalse(result);
- }
}
}
}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
index 01361ff..3495b66 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
@@ -1472,14 +1472,8 @@
ImsException.class);
// IMS registers
- ArraySet<String> featureTags = new ArraySet<>();
- // Chat Session
- featureTags.add(CHAT_FEATURE_TAG);
- featureTags.add(FILE_TRANSFER_FEATURE_TAG);
- ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder(
- IMS_REGI_TECH_LTE).setFeatureTags(featureTags).build();
- sServiceConnector.getCarrierService().getImsRegistration().onRegistered(attr);
- waitForParam(mQueue, attr);
+ sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
+ IMS_REGI_TECH_LTE);
// Notify framework that the RCS capability status is changed and PRESENCE UCE is enabled.
RcsImsCapabilities capabilities =
@@ -1502,6 +1496,20 @@
assertEquals(RcsUceAdapter.PUBLISH_STATE_OK, waitForIntResult(publishStateQueue));
publishStateQueue.clear();
+ // IMS registers
+ ArraySet<String> featureTags = new ArraySet<>();
+ // Chat Session
+ featureTags.add(CHAT_FEATURE_TAG);
+ featureTags.add(FILE_TRANSFER_FEATURE_TAG);
+ ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder(
+ IMS_REGI_TECH_LTE).setFeatureTags(featureTags).build();
+ sServiceConnector.getCarrierService().getImsRegistration().onRegistered(attr);
+ waitForParam(mQueue, attr);
+
+ assertEquals(RcsUceAdapter.PUBLISH_STATE_PUBLISHING, waitForIntResult(publishStateQueue));
+ assertEquals(RcsUceAdapter.PUBLISH_STATE_OK, waitForIntResult(publishStateQueue));
+ publishStateQueue.clear();
+
// Can not verify the pidf fully, but we can ensure that the service id for the feature is
// contained in the XML. Multible PUBLISH requests may occur based on the state of the stack
// at the time of this call, retry to get correct PIDF up to 5 times.
diff --git a/tests/tests/text/src/android/text/cts/PrecomputedTextTest.java b/tests/tests/text/src/android/text/cts/PrecomputedTextTest.java
index ceafff3..1713ffd 100644
--- a/tests/tests/text/src/android/text/cts/PrecomputedTextTest.java
+++ b/tests/tests/text/src/android/text/cts/PrecomputedTextTest.java
@@ -25,7 +25,6 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -100,20 +99,22 @@
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.setTextDirection(LTR).build());
- LineBreakConfig lineBreakConfig = new LineBreakConfig();
- lineBreakConfig.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT);
+ LineBreakConfig strictNoneConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
assertNotNull(new Params.Builder(PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
- .setLineBreakConfig(lineBreakConfig)
+ .setLineBreakConfig(strictNoneConfig)
.setTextDirection(LTR).build());
- LineBreakConfig lineBreakConfig2 = new LineBreakConfig();
- lineBreakConfig.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
+ LineBreakConfig nonePhraseConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NONE)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE).build();
assertNotNull(new Params.Builder(PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
- .setLineBreakConfig(lineBreakConfig2)
+ .setLineBreakConfig(nonePhraseConfig)
.setTextDirection(LTR).build());
}
@@ -127,9 +128,9 @@
assertEquals(RTL, new Params.Builder(PAINT).setTextDirection(RTL).build()
.getTextDirection());
- LineBreakConfig lineBreakConfig = new LineBreakConfig();
- lineBreakConfig.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT);
- lineBreakConfig.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
+ LineBreakConfig lineBreakConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE).build();
assertTrue(lineBreakConfig.equals(new Params.Builder(PAINT)
.setLineBreakConfig(lineBreakConfig).build().getLineBreakConfig()));
}
@@ -142,16 +143,22 @@
new Params.Builder(PAINT).build().getHyphenationFrequency());
assertEquals(TextDirectionHeuristics.FIRSTSTRONG_LTR,
new Params.Builder(PAINT).build().getTextDirection());
+ }
- // Verify that there is no LineBreakConfig instance by default.
- assertNull(new Params.Builder(PAINT).build().getLineBreakConfig());
+ @Test
+ public void testParams_defaultLineBreakConfig() {
+ // Verify it will return the pre-defined instance with the default value if the
+ // LineBreakConfig has not been set to Params before.
+ LineBreakConfig config = new Params.Builder(PAINT).build().getLineBreakConfig();
+ assertEquals(LineBreakConfig.LINE_BREAK_STYLE_NONE, config.getLineBreakStyle());
+ assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE, config.getLineBreakWordStyle());
}
@Test
public void testParams_equals() {
- LineBreakConfig config = new LineBreakConfig();
- config.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT);
- config.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
+ LineBreakConfig config = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE).build();
final Params base = new Params.Builder(PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY)
diff --git a/tests/tests/text/src/android/text/cts/StaticLayoutLineBreakingVariantsTest.java b/tests/tests/text/src/android/text/cts/StaticLayoutLineBreakingVariantsTest.java
index 35772d4..502a91d 100644
--- a/tests/tests/text/src/android/text/cts/StaticLayoutLineBreakingVariantsTest.java
+++ b/tests/tests/text/src/android/text/cts/StaticLayoutLineBreakingVariantsTest.java
@@ -94,8 +94,9 @@
@Test
public void testBreakVariant_loose() {
- LineBreakConfig config = new LineBreakConfig();
- config.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE);
+ LineBreakConfig config = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
assertLineBreak(SAMPLE_TEXT, "ja-JP", config, 90, SAMPLE_TEXT);
assertLineBreak(SAMPLE_TEXT, "ja-JP", config, 80,
"\u30D0\u30C3\u30C6\u30EA\u30FC\u30BB\u30FC\u30D0",
@@ -137,8 +138,9 @@
@Test
public void testBreakVariant_loose_text2() {
- LineBreakConfig config = new LineBreakConfig();
- config.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE);
+ LineBreakConfig config = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
assertLineBreak(SAMPLE_TEXT2, "ja-JP", config, 120, SAMPLE_TEXT2);
assertLineBreak(SAMPLE_TEXT2, "ja-JP", config, 110,
"\u65B0\u3057\u3044\u6A5F\u7A2E\u3082\u6C17\u306B\u306A\u308B",
@@ -195,8 +197,9 @@
@Test
public void testBreakVariant_strict() {
- LineBreakConfig config = new LineBreakConfig();
- config.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT);
+ LineBreakConfig config = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
assertLineBreak(SAMPLE_TEXT, "ja-JP", config, 90, SAMPLE_TEXT);
assertLineBreak(SAMPLE_TEXT, "ja-JP", config, 80,
"\u30D0\u30C3\u30C6\u30EA\u30FC\u30BB\u30FC",
@@ -239,8 +242,9 @@
@Test
public void testBreakVariant_strict_text2() {
- LineBreakConfig config = new LineBreakConfig();
- config.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT);
+ LineBreakConfig config = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
assertLineBreak(SAMPLE_TEXT2, "ja-JP", config, 120, SAMPLE_TEXT2);
assertLineBreak(SAMPLE_TEXT2, "ja-JP", config, 110,
"\u65B0\u3057\u3044\u6A5F\u7A2E\u3082\u6C17\u306B\u306A\u308B",
@@ -298,8 +302,9 @@
@Test
public void testBreakVariant_phrase() {
- LineBreakConfig config = new LineBreakConfig();
- config.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
+ LineBreakConfig config = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NONE)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE).build();
assertLineBreak(SAMPLE_TEXT, "ja-JP", config, 90, SAMPLE_TEXT);
assertLineBreak(SAMPLE_TEXT, "ja-JP", config, 80,
"\u30D0\u30C3\u30C6\u30EA\u30FC\u30BB\u30FC\u30D0",
@@ -341,8 +346,9 @@
@Test
public void testBreakVariant_phrase_text2() {
- LineBreakConfig config = new LineBreakConfig();
- config.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
+ LineBreakConfig config = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE).build();
assertLineBreak(SAMPLE_TEXT2, "ja-JP", config, 120, SAMPLE_TEXT2);
assertLineBreak(SAMPLE_TEXT2, "ja-JP", config, 110,
"\u65B0\u3057\u3044\u6A5F\u7A2E\u3082\u6C17\u306B",
diff --git a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
index 5322a3d..3ce16a6 100644
--- a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
@@ -241,8 +241,9 @@
}
{
// setLineBreakConfig
- LineBreakConfig lineBreakConfig = new LineBreakConfig();
- lineBreakConfig.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT);
+ LineBreakConfig lineBreakConfig = new LineBreakConfig.Builder()
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
@@ -256,8 +257,9 @@
}
{
// setLineBreakConfig with word style(lw=phrase)
- LineBreakConfig lineBreakConfig = new LineBreakConfig();
- lineBreakConfig.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
+ LineBreakConfig lineBreakConfig = new LineBreakConfig.Builder()
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_STYLE_NONE)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE).build();
StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
diff --git a/tests/tests/textclassifier/src/android/view/textclassifier/cts/SelectionEventTest.java b/tests/tests/textclassifier/src/android/view/textclassifier/cts/SelectionEventTest.java
index 72550c4..d86ffb1 100644
--- a/tests/tests/textclassifier/src/android/view/textclassifier/cts/SelectionEventTest.java
+++ b/tests/tests/textclassifier/src/android/view/textclassifier/cts/SelectionEventTest.java
@@ -16,6 +16,11 @@
package android.view.textclassifier.cts;
+import static com.google.common.truth.Truth.assertThat;
+
+import android.view.textclassifier.SelectionEvent;
+import android.view.textclassifier.TextClassifier;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -27,7 +32,23 @@
public class SelectionEventTest {
@Test
- public void testSelectionEvent_placeholder() {
- // TODO: add tests for SelectionEvent
+ public void testSelectionEvent() {
+ SelectionEvent event = SelectionEvent.createSelectionActionEvent(0, 1,
+ SelectionEvent.ACTION_COPY);
+ assertThat(event.getEventType()).isEqualTo(SelectionEvent.ACTION_COPY);
+ assertThat(event.getStart()).isEqualTo(0);
+ assertThat(event.getEnd()).isEqualTo(0);
+ assertThat(event.getInvocationMethod()).isEqualTo(SelectionEvent.INVOCATION_UNKNOWN);
+ assertThat(event.getEntityType()).isEqualTo(TextClassifier.TYPE_UNKNOWN);
+ assertThat(event.getEventIndex()).isEqualTo(0);
+ assertThat(event.getPackageName()).isEqualTo("");
+ assertThat(event.getSmartStart()).isEqualTo(0);
+ assertThat(event.getSmartEnd()).isEqualTo(0);
+ assertThat(event.getWidgetType()).isEqualTo(TextClassifier.WIDGET_TYPE_UNKNOWN);
+ assertThat(event.getWidgetVersion()).isNull();
+ assertThat(event.getResultId()).isEqualTo("");
+ assertThat(event.getEventTime()).isEqualTo(0);
+ assertThat(event.getDurationSinceSessionStart()).isEqualTo(0);
+ assertThat(event.getDurationSincePreviousEvent()).isEqualTo(0);
}
}
diff --git a/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextLinksTest.java b/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextLinksTest.java
index 1414ed7..3592c96 100644
--- a/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextLinksTest.java
+++ b/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextLinksTest.java
@@ -231,6 +231,7 @@
assertNull(request.getDefaultLocales());
assertTrue(request.getExtras().isEmpty());
assertNull(request.getEntityConfig());
+ assertNull(request.getCallingPackageName());
}
@Test
@@ -253,6 +254,7 @@
TextClassifier.HINT_TEXT_IS_EDITABLE,
request.getEntityConfig().getHints().iterator().next());
assertEquals(referenceTime, request.getReferenceTime());
+ assertNull(request.getCallingPackageName());
}
}
diff --git a/tests/tests/tv/src/android/media/tv/interactive/cts/TvInteractiveAppManagerTest.java b/tests/tests/tv/src/android/media/tv/interactive/cts/TvInteractiveAppManagerTest.java
index f108fd0..9162020 100644
--- a/tests/tests/tv/src/android/media/tv/interactive/cts/TvInteractiveAppManagerTest.java
+++ b/tests/tests/tv/src/android/media/tv/interactive/cts/TvInteractiveAppManagerTest.java
@@ -158,7 +158,7 @@
runTestOnUiThread(new Runnable() {
@Override
public void run() {
- mManager.registerCallback(mCallback, getExecutor());
+ mManager.registerCallback(getExecutor(), mCallback);
}
});
}
@@ -264,8 +264,7 @@
PollingCheck.waitFor(
TIME_OUT_MS, () -> StubTvInteractiveAppService.sAppLinkInfo == null);
- info = new AppLinkInfo.Builder("pkg1", "class1").setPackageName("pkg2")
- .setClassName("class2").setUriScheme("url1").setUriHost("host2")
+ info = new AppLinkInfo.Builder("pkg1", "class1").setUriScheme("url1").setUriHost("host2")
.setUriPrefix("prefix").build();
mManager.registerAppLinkInfo(stubInfo.getId(), info);
diff --git a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java
index 626f08d..8e39664 100644
--- a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java
+++ b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java
@@ -649,7 +649,7 @@
TunerTestLnbCallback lnbCB2 = new TunerTestLnbCallback();
// add it as sharee
- lnb.addCallback(lnbCB2, getExecutor());
+ lnb.addCallback(getExecutor(), lnbCB2);
// check callback
lnb.sendDiseqcMessage(new byte[] {1, 2});
@@ -1565,7 +1565,7 @@
// add sharee and check the callback
TunerTestLnbCallback lnbCB2 = new TunerTestLnbCallback();
- lnbA.addCallback(lnbCB2, getExecutor());
+ lnbA.addCallback(getExecutor(), lnbCB2);
lnbA.sendDiseqcMessage(new byte[] {1, 2});
assertTrue(lnbCB1.getOnDiseqcMessageCalled());
lnbCB1.resetOnDiseqcMessageCalled();
diff --git a/tests/tests/uidmigration/Android.bp b/tests/tests/uidmigration/Android.bp
index 92db2e1..4f98ae6 100644
--- a/tests/tests/uidmigration/Android.bp
+++ b/tests/tests/uidmigration/Android.bp
@@ -24,6 +24,7 @@
"androidx.test.rules",
"ctstestrunner-axt",
"permission-test-util-lib",
+ "services.core",
"CtsSharedUserMigrationTestLibs",
],
libs: [
@@ -36,5 +37,5 @@
"cts",
"general-tests",
],
- sdk_version: "test_current",
+ platform_apis: true,
}
diff --git a/tests/tests/uidmigration/DataTestApp/AndroidManifest2.xml b/tests/tests/uidmigration/DataTestApp/AndroidManifest2.xml
index 17fb471..996cc80 100644
--- a/tests/tests/uidmigration/DataTestApp/AndroidManifest2.xml
+++ b/tests/tests/uidmigration/DataTestApp/AndroidManifest2.xml
@@ -17,8 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.uidmigration.cts.DataTestApp"
android:sharedUserId="android.uidmigration.cts"
- android:sharedUserMaxSdkVersion="32"
- android:inheritKeyStoreKeys="true" >
+ android:sharedUserMaxSdkVersion="32" >
<queries>
<package android:name="android.uidmigration.cts" />
diff --git a/tests/tests/uidmigration/DataTestApp/src/android/uidmigration/cts/DataProvider.kt b/tests/tests/uidmigration/DataTestApp/src/android/uidmigration/cts/DataProvider.kt
index 10e2fbc..ef77854 100644
--- a/tests/tests/uidmigration/DataTestApp/src/android/uidmigration/cts/DataProvider.kt
+++ b/tests/tests/uidmigration/DataTestApp/src/android/uidmigration/cts/DataProvider.kt
@@ -18,24 +18,11 @@
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
-import android.security.keystore.KeyGenParameterSpec
-import android.security.keystore.KeyProperties
-import android.util.Log
-import java.nio.charset.StandardCharsets.UTF_8
-import java.security.GeneralSecurityException
-import java.security.KeyPairGenerator
-import java.security.KeyStore
-import java.security.MessageDigest
-import java.security.Signature
import java.util.UUID
-import javax.crypto.Cipher
-import javax.crypto.KeyGenerator
-import javax.crypto.spec.IvParameterSpec
class DataProvider : BaseProvider() {
companion object {
- private const val ANDROID_KEYSTORE = "AndroidKeyStore"
private const val RESULT_KEY = "result"
}
@@ -59,126 +46,9 @@
return data
}
- // Generate new AES secret key and encrypt arg.
- private fun encryptAES(arg: String): Bundle {
- val keyAlias = "aes"
- val result = Bundle()
- try {
- val keyGen = KeyGenerator.getInstance(
- KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEYSTORE
- )
- val spec = KeyGenParameterSpec.Builder(
- keyAlias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
- )
- .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
- .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
- .setKeySize(256)
- .build()
- keyGen.init(spec)
- val key = keyGen.generateKey()
- val cipher = Cipher.getInstance("AES/CBC/PKCS7Padding")
- cipher.init(Cipher.ENCRYPT_MODE, key)
- val enc = cipher.doFinal(arg.toByteArray(UTF_8))
- val iv = cipher.iv
- result.putByteArray(RESULT_KEY, enc)
- result.putByteArray("iv", iv)
- } catch (e: Exception) {
- Log.e("DataTestApp", "Crypto error", e)
- }
- return result
- }
-
- // Decrypt provided data with iv + key in keystore.
- private fun decryptAES(extra: Bundle): Bundle {
- val keyAlias = "aes"
- val result = Bundle()
- val enc = extra.getByteArray(RESULT_KEY)
- val iv = extra.getByteArray("iv")
- if (enc == null || iv == null) return result
- try {
- val ks = KeyStore.getInstance(ANDROID_KEYSTORE)
- ks.load(null)
-
- // Fetch the existing key in keystore.
- val entry = ks.getEntry(keyAlias, null) as KeyStore.SecretKeyEntry
- val key = entry.secretKey
- val cipher = Cipher.getInstance("AES/CBC/PKCS7Padding")
- val ivSpec = IvParameterSpec(iv)
- cipher.init(Cipher.DECRYPT_MODE, key, ivSpec)
- val dec = cipher.doFinal(enc)
- result.putString(RESULT_KEY, String(dec, UTF_8))
- } catch (e: Exception) {
- Log.e("DataTestApp", "Crypto error", e)
- }
- return result
- }
-
- @Throws(GeneralSecurityException::class)
- private fun ecCertChainDigest(ks: KeyStore): ByteArray? {
- val keyAlias = "ec"
- val certs = ks.getCertificateChain(keyAlias) ?: return null
- val digest = MessageDigest.getInstance("SHA256")
- for (cert in certs) {
- digest.update(cert.encoded)
- }
- return digest.digest()
- }
-
- // Generates a new EC keypair in keystore, and return the signed signature data.
- private fun signEC(args: String): Bundle {
- val keyAlias = "ec"
- val result = Bundle()
- val data = args.toByteArray(UTF_8)
- try {
- val kpg = KeyPairGenerator.getInstance(
- KeyProperties.KEY_ALGORITHM_EC, ANDROID_KEYSTORE
- )
- val spec = KeyGenParameterSpec.Builder(
- keyAlias, KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
- )
- .setDigests(KeyProperties.DIGEST_SHA256)
- .setAttestationChallenge(UUID.randomUUID().toString().toByteArray(UTF_8))
- .build()
- kpg.initialize(spec)
- val kp = kpg.generateKeyPair()
- val s = Signature.getInstance("SHA256withECDSA")
- s.initSign(kp.private)
- s.update(data)
- result.putByteArray(RESULT_KEY, s.sign())
- val ks = KeyStore.getInstance(ANDROID_KEYSTORE)
- ks.load(null)
- result.putByteArray("certChain", ecCertChainDigest(ks))
- } catch (e: Exception) {
- Log.e("DataTestApp", "Crypto error", e)
- }
- return result
- }
-
- // Fetch the previously generated EC keypair and returns the certificate.
- private fun getEcCert(): Bundle {
- val keyAlias = "ec"
- val result = Bundle()
- try {
- val ks = KeyStore.getInstance(ANDROID_KEYSTORE)
- ks.load(null)
-
- // Fetch the existing key in keystore.
- val entry = ks.getEntry(keyAlias, null) as KeyStore.PrivateKeyEntry
- result.putByteArray(RESULT_KEY, entry.certificate.encoded)
- result.putByteArray("certChain", ecCertChainDigest(ks))
- } catch (e: Exception) {
- Log.e("DataTestApp", "Crypto error", e)
- }
- return result
- }
-
override fun call(method: String, arg: String?, extras: Bundle?): Bundle {
return when (method) {
"data" -> checkData()
- "encryptAES" -> encryptAES(arg!!)
- "decryptAES" -> decryptAES(extras!!)
- "signEC" -> signEC(arg!!)
- "getECCert" -> getEcCert()
else -> Bundle()
}
}
diff --git a/tests/tests/uidmigration/src/android/uidmigration/cts/AppIdMigrationTest.kt b/tests/tests/uidmigration/src/android/uidmigration/cts/AppIdMigrationTest.kt
new file mode 100644
index 0000000..cb84f3f
--- /dev/null
+++ b/tests/tests/uidmigration/src/android/uidmigration/cts/AppIdMigrationTest.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.uidmigration.cts
+
+import android.Manifest.permission.INTERNET
+import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
+import android.content.Context
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.PackageInfoFlags
+import android.permission.cts.PermissionUtils
+import android.permission.cts.PermissionUtils.isPermissionGranted
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.server.pm.SharedUidMigration.LIVE_TRANSITION
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotEquals
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+
+// All tests ignored: appId migration is disabled (http://b/220015249)
+@RunWith(AndroidJUnit4::class)
+class AppIdMigrationTest {
+
+ companion object {
+ private const val RESULT_KEY = "result"
+ }
+
+ private lateinit var mContext: Context
+ private lateinit var mPm: PackageManager
+
+ @Before
+ fun setup() {
+ mContext = ApplicationProvider.getApplicationContext<Context>()
+ mPm = mContext.packageManager
+ }
+
+ @After
+ fun tearDown() {
+ uninstallPackage(Const.INSTALL_TEST_PKG)
+ uninstallPackage(Const.INSTALL_TEST_PKG + "2")
+ uninstallPackage(Const.PERM_TEST_PKG)
+ uninstallPackage(Const.PERM_TEST_PKG + ".secondary")
+ uninstallPackage(Const.DATA_TEST_PKG)
+ }
+
+ @Ignore
+ @Test
+ fun testAppInstall() = withStrategy(LIVE_TRANSITION) {
+ assertTrue(installPackage(InstallTest.APK))
+ assertTrue(installPackage(InstallTest.APK2))
+
+ // Both app should share the same UID.
+ val uid = mPm.getPackageUid(Const.INSTALL_TEST_PKG, PackageInfoFlags.of(0))
+ var pkgs = mPm.getPackagesForUid(uid).assertNotNull()
+ assertEquals(2, pkgs.size)
+
+ // Should not allow upgrading to an APK that directly removes sharedUserId.
+ assertFalse(installPackage(InstallTest.APK3))
+
+ // Leave shared UID.
+ assertTrue(installPackage(InstallTest.APK4))
+ pkgs = mPm.getPackagesForUid(uid).assertNotNull()
+ assertEquals(1, pkgs.size)
+
+ uninstallPackage(Const.INSTALL_TEST_PKG)
+ uninstallPackage(Const.INSTALL_TEST_PKG + "2")
+ }
+
+ @Ignore
+ @Test
+ fun testPermissionMigration() = withStrategy(LIVE_TRANSITION) {
+ val apk = "$TMP_APK_PATH/PermissionTestApp"
+ assertTrue(installPackage(apk + "1.apk"))
+ assertTrue(installPackage(apk + "2.apk"))
+ val secondaryPkg = Const.PERM_TEST_PKG + ".secondary"
+
+ // Runtime permissions are not granted by default.
+ assertFalse(isPermissionGranted(secondaryPkg, WRITE_EXTERNAL_STORAGE))
+
+ // Grant a runtime permission.
+ PermissionUtils.grantPermission(secondaryPkg, WRITE_EXTERNAL_STORAGE)
+
+ // All apps in the UID group should have the same permissions.
+ assertTrue(isPermissionGranted(Const.PERM_TEST_PKG, INTERNET))
+ assertTrue(isPermissionGranted(Const.PERM_TEST_PKG, WRITE_EXTERNAL_STORAGE))
+ assertTrue(isPermissionGranted(secondaryPkg, INTERNET))
+ assertTrue(isPermissionGranted(secondaryPkg, WRITE_EXTERNAL_STORAGE))
+
+ // Upgrade and leave shared UID.
+ assertTrue(installPackage(apk + "3.apk"))
+
+ // The app in the original UID group should no longer have the permissions.
+ assertFalse(isPermissionGranted(Const.PERM_TEST_PKG, INTERNET))
+ assertFalse(isPermissionGranted(Const.PERM_TEST_PKG, WRITE_EXTERNAL_STORAGE))
+
+ // The upgraded app should still have the permissions.
+ assertTrue(isPermissionGranted(secondaryPkg, INTERNET))
+ assertTrue(isPermissionGranted(secondaryPkg, WRITE_EXTERNAL_STORAGE))
+ uninstallPackage(Const.PERM_TEST_PKG)
+ uninstallPackage(secondaryPkg)
+ }
+
+ @Ignore
+ @Test
+ fun testDataMigration() = withStrategy(LIVE_TRANSITION) {
+ val apk = "$TMP_APK_PATH/DataTestApp"
+ assertTrue(installPackage(apk + "1.apk"))
+ val oldUid = mPm.getPackageUid(Const.DATA_TEST_PKG, PackageInfoFlags.of(0))
+ val authority = Const.DATA_TEST_PKG + ".provider"
+ val resolver = mContext.contentResolver
+
+ // Ask the app to generate a new random UUID and persist in data.
+ var result = resolver.call(authority, "data", null, null).assertNotNull()
+ val oldUUID = result.getString(RESULT_KEY).assertNotNull()
+
+ // Update the data test APK and make sure UID changed.
+ assertTrue(installPackage(apk + "2.apk"))
+ val newUid = mPm.getPackageUid(Const.DATA_TEST_PKG, PackageInfoFlags.of(0))
+ assertNotEquals(oldUid, newUid)
+
+ // Ask the app again for a UUID. If data migration is working, it shall be the same.
+ result = resolver.call(authority, "data", null, null).assertNotNull()
+ val newUUID = result.getString(RESULT_KEY)
+ assertEquals(oldUUID, newUUID)
+ uninstallPackage(Const.DATA_TEST_PKG)
+ }
+}
diff --git a/tests/tests/uidmigration/src/android/uidmigration/cts/Common.kt b/tests/tests/uidmigration/src/android/uidmigration/cts/Common.kt
new file mode 100644
index 0000000..a525ff8
--- /dev/null
+++ b/tests/tests/uidmigration/src/android/uidmigration/cts/Common.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.uidmigration.cts
+
+import android.content.pm.PackageManager
+import com.android.compatibility.common.util.SystemUtil.runShellCommand
+import com.android.server.pm.SharedUidMigration
+import com.android.server.pm.SharedUidMigration.PROPERTY_KEY
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+
+const val TMP_APK_PATH = "/data/local/tmp/cts/uidmigration"
+
+val FLAG_ZERO = PackageManager.PackageInfoFlags.of(0)
+
+// What each APK meant
+// APK : pkg , with sharedUserId
+// APK2: pkg2, with sharedUserId
+// APK3: pkg , with sharedUserId removed
+// APK4: pkg , with sharedUserMaxSdkVersion="32"
+
+object InstallTest {
+ const val APK = "$TMP_APK_PATH/InstallTestApp.apk"
+ const val APK2 = "$TMP_APK_PATH/InstallTestApp2.apk"
+ const val APK3 = "$TMP_APK_PATH/InstallTestApp3.apk"
+ const val APK4 = "$TMP_APK_PATH/InstallTestApp4.apk"
+}
+
+@Suppress("NOTHING_TO_INLINE")
+inline fun <T> T?.assertNotNull(): T {
+ assertNotNull(this)
+ return this!!
+}
+
+@Suppress("NOTHING_TO_INLINE")
+inline fun assertEquals(a: Int, b: Int) = assertEquals(a.toLong(), b.toLong())
+
+fun installPackage(apkPath: String): Boolean {
+ return runShellCommand("pm install --force-queryable -t $apkPath") == "Success\n"
+}
+
+fun uninstallPackage(packageName: String) {
+ runShellCommand("pm uninstall $packageName")
+}
+
+@SharedUidMigration.Strategy
+var migrationStrategy: Int
+ get() = SharedUidMigration.getCurrentStrategy()
+ set(value) { runShellCommand("setprop $PROPERTY_KEY $value") }
+
+inline fun withStrategy(strategy: Int? = null, body: () -> Unit) {
+ if (SharedUidMigration.isDisabled()) {
+ // Nothing to test if shared UID migration is disabled
+ return
+ }
+
+ val backup = migrationStrategy
+ strategy?.let { migrationStrategy = it }
+ try {
+ body.invoke()
+ } finally {
+ // Always restore the device state no matter what happened
+ migrationStrategy = backup
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/uidmigration/src/android/uidmigration/cts/SharedUserMigrationTest.kt b/tests/tests/uidmigration/src/android/uidmigration/cts/SharedUserMigrationTest.kt
index 9c71b7c..3958a12 100644
--- a/tests/tests/uidmigration/src/android/uidmigration/cts/SharedUserMigrationTest.kt
+++ b/tests/tests/uidmigration/src/android/uidmigration/cts/SharedUserMigrationTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,63 +13,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.uidmigration.cts
-import android.Manifest.permission.INTERNET
-import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
-import android.content.BroadcastReceiver
import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
import android.content.pm.PackageManager
-import android.content.pm.PackageManager.PackageInfoFlags
-import android.permission.cts.PermissionUtils
-import android.permission.cts.PermissionUtils.isPermissionGranted
+import android.os.Build
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.compatibility.common.util.SystemUtil.runShellCommand
+import com.android.server.pm.SharedUidMigration.BEST_EFFORT
+import com.android.server.pm.SharedUidMigration.NEW_INSTALL_ONLY
import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import java.io.ByteArrayInputStream
-import java.nio.charset.StandardCharsets.UTF_8
-import java.security.Signature
-import java.security.cert.CertificateFactory
-import java.security.cert.X509Certificate
-import java.util.UUID
-import java.util.concurrent.ArrayBlockingQueue
-import java.util.concurrent.BlockingQueue
-import java.util.concurrent.TimeUnit
-import org.junit.Assert.assertArrayEquals
-import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
-import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class SharedUserMigrationTest {
- companion object {
- private const val TMP_APK_PATH = "/data/local/tmp/cts/uidmigration"
- private const val RESULT_KEY = "result"
- private val NOT_AN_ERROR = Throwable()
- }
-
private lateinit var mContext: Context
private lateinit var mPm: PackageManager
- @Suppress("NOTHING_TO_INLINE")
- private inline fun <T> T?.assertNotNull(): T {
- assertNotNull(this)
- return this!!
- }
-
- @Suppress("NOTHING_TO_INLINE")
- private inline fun assertEquals(a: Int, b: Int) = assertEquals(a.toLong(), b.toLong())
-
@Before
fun setup() {
mContext = ApplicationProvider.getApplicationContext<Context>()
@@ -80,248 +49,97 @@
fun tearDown() {
uninstallPackage(Const.INSTALL_TEST_PKG)
uninstallPackage(Const.INSTALL_TEST_PKG + "2")
- uninstallPackage(Const.PERM_TEST_PKG)
- uninstallPackage(Const.PERM_TEST_PKG + ".secondary")
- uninstallPackage(Const.DATA_TEST_PKG)
}
- @Test
- fun testAppInstall() {
- val apk = "$TMP_APK_PATH/InstallTestApp"
- assertTrue(installPackage("$apk.apk"))
- assertTrue(installPackage(apk + "2.apk"))
-
- // Both app should share the same UID.
- val uid = mPm.getPackageUid(Const.INSTALL_TEST_PKG, PackageInfoFlags.of(0))
- var pkgs = mPm.getPackagesForUid(uid).assertNotNull()
+ // Restore and ensure both test apps are sharing UID.
+ private fun reset(uid: Int) {
+ uninstallPackage(Const.INSTALL_TEST_PKG)
+ assertTrue(installPackage(InstallTest.APK))
+ val pkgs = mPm.getPackagesForUid(uid).assertNotNull()
assertEquals(2, pkgs.size)
+ }
- // Should not allow directly removing sharedUserId.
- assertFalse(installPackage(apk + "3.apk"))
+ private fun testNewInstallOnly(uid: Int) {
+ migrationStrategy = NEW_INSTALL_ONLY
- // Leave shared UID.
- assertTrue(installPackage(apk + "4.apk"))
+ // Should not allow upgrading to an APK that directly removes sharedUserId.
+ assertFalse(installPackage(InstallTest.APK3))
+
+ // Directly parsing APK4 should return no sharedUserId.
+ var pkgInfo = mPm.getPackageArchiveInfo(InstallTest.APK4, FLAG_ZERO).assertNotNull()
+ assertNull(pkgInfo.sharedUserId)
+
+ assertTrue(installPackage(InstallTest.APK4))
+ var pkgs = mPm.getPackagesForUid(uid).assertNotNull()
+ // With NEW_INSTALL_ONLY, upgrades should not change appId.
+ assertEquals(2, pkgs.size)
+ pkgInfo = mPm.getPackageInfo(Const.INSTALL_TEST_PKG, FLAG_ZERO)
+ assertNotNull(pkgInfo.sharedUserId)
+
+ // Should not allow re-joining sharedUserId.
+ assertFalse(installPackage(InstallTest.APK))
+
+ // Uninstall and install a new pkg leaving shared UID
+ uninstallPackage(Const.INSTALL_TEST_PKG)
+ assertTrue(installPackage(InstallTest.APK4))
+ pkgs = mPm.getPackagesForUid(uid).assertNotNull()
+ // Newly installed apps with sharedUserMaxSdkVersion set should not join shared UID.
+ assertEquals(1, pkgs.size)
+ pkgInfo = mPm.getPackageInfo(Const.INSTALL_TEST_PKG, FLAG_ZERO)
+ assertNull(pkgInfo.sharedUserId)
+ }
+
+ private fun testBestEffort(uid: Int) {
+ migrationStrategy = BEST_EFFORT
+
+ assertTrue(installPackage(InstallTest.APK4))
+ var pkgs = mPm.getPackagesForUid(uid).assertNotNull()
+ // With BEST_EFFORT, upgrades should also not change appId.
+ assertEquals(2, pkgs.size)
+ var pkgInfo = mPm.getPackageInfo(Const.INSTALL_TEST_PKG, FLAG_ZERO)
+ assertNotNull(pkgInfo.sharedUserId)
+
+ val oldUidName = mPm.getNameForUid(uid)
+ uninstallPackage(Const.INSTALL_TEST_PKG + "2")
+
+ // There should be only 1 package left in the shared UID group.
+ // This should trigger the transparent shared UID migration.
pkgs = mPm.getPackagesForUid(uid).assertNotNull()
assertEquals(1, pkgs.size)
- // Should not allow re-joining sharedUserId.
- assertFalse(installPackage("$apk.apk"))
+ // Confirm that the internal PackageSetting is actually migrated.
+ val newUidName = mPm.getNameForUid(uid)
+ assertNotEquals(oldUidName, newUidName)
+ pkgInfo = mPm.getPackageInfo(Const.INSTALL_TEST_PKG, FLAG_ZERO)
+ assertNull(pkgInfo.sharedUserId)
- uninstallPackage(Const.INSTALL_TEST_PKG)
- uninstallPackage(Const.INSTALL_TEST_PKG + "2")
+ // Even installing another shared UID app, the appId shall not be reused.
+ assertTrue(installPackage(InstallTest.APK2))
+ pkgs = mPm.getPackagesForUid(uid).assertNotNull()
+ assertEquals(1, pkgs.size)
}
@Test
- fun testPermissionMigration() {
- val apk = "$TMP_APK_PATH/PermissionTestApp"
- assertTrue(installPackage(apk + "1.apk"))
- assertTrue(installPackage(apk + "2.apk"))
- val secondaryPkg = Const.PERM_TEST_PKG + ".secondary"
+ fun testAppInstall() = withStrategy {
+ assertTrue(installPackage(InstallTest.APK))
+ assertTrue(installPackage(InstallTest.APK2))
- // Runtime permissions are not granted by default.
- assertFalse(isPermissionGranted(secondaryPkg, WRITE_EXTERNAL_STORAGE))
+ // Both app should share the same UID.
+ val uid = mPm.getPackageUid(Const.INSTALL_TEST_PKG, FLAG_ZERO)
+ val pkgs = mPm.getPackagesForUid(uid).assertNotNull()
+ assertEquals(2, pkgs.size)
- // Grant a runtime permission.
- PermissionUtils.grantPermission(secondaryPkg, WRITE_EXTERNAL_STORAGE)
-
- // All apps in the UID group should have the same permissions.
- assertTrue(isPermissionGranted(Const.PERM_TEST_PKG, INTERNET))
- assertTrue(isPermissionGranted(Const.PERM_TEST_PKG, WRITE_EXTERNAL_STORAGE))
- assertTrue(isPermissionGranted(secondaryPkg, INTERNET))
- assertTrue(isPermissionGranted(secondaryPkg, WRITE_EXTERNAL_STORAGE))
-
- // Upgrade and leave shared UID.
- assertTrue(installPackage(apk + "3.apk"))
-
- // The app in the original UID group should no longer have the permissions.
- assertFalse(isPermissionGranted(Const.PERM_TEST_PKG, INTERNET))
- assertFalse(isPermissionGranted(Const.PERM_TEST_PKG, WRITE_EXTERNAL_STORAGE))
-
- // The upgraded app should still have the permissions.
- assertTrue(isPermissionGranted(secondaryPkg, INTERNET))
- assertTrue(isPermissionGranted(secondaryPkg, WRITE_EXTERNAL_STORAGE))
- uninstallPackage(Const.PERM_TEST_PKG)
- uninstallPackage(secondaryPkg)
- }
-
- @Test
- fun testDataMigration() {
- val apk = "$TMP_APK_PATH/DataTestApp"
- assertTrue(installPackage(apk + "1.apk"))
- val oldUid = mPm.getPackageUid(Const.DATA_TEST_PKG, PackageInfoFlags.of(0))
- val authority = Const.DATA_TEST_PKG + ".provider"
- val resolver = mContext.contentResolver
-
- // Ask the app to generate a new random UUID and persist in data.
- var result = resolver.call(authority, "data", null, null).assertNotNull()
- val oldUUID = result.getString(RESULT_KEY).assertNotNull()
-
- val receiver = PackageBroadcastReceiver(oldUid)
- IntentFilter().apply {
- addAction(Intent.ACTION_PACKAGE_REMOVED)
- addAction(Intent.ACTION_PACKAGE_ADDED)
- addAction(Intent.ACTION_PACKAGE_REPLACED)
- addDataScheme("package")
- mContext.registerReceiver(receiver, this)
- }
- IntentFilter().apply {
- addAction(Intent.ACTION_UID_REMOVED)
- addAction(Const.ACTION_UPDATE_ACK)
- mContext.registerReceiver(receiver, this)
- }
-
- // Update the data test APK and make sure UID changed.
- assertTrue(installPackage(apk + "2.apk"))
- val newUid = mPm.getPackageUid(Const.DATA_TEST_PKG, PackageInfoFlags.of(0))
- assertNotEquals(oldUid, newUid)
-
- // Ensure system broadcasts are delivered properly.
- try {
- val e = receiver.poll(30, TimeUnit.SECONDS)
- if (e !== NOT_AN_ERROR) {
- throw AssertionError(e)
- }
- } catch (e: InterruptedException) {
- fail(e.message)
- }
- assertEquals(newUid, receiver.newUid)
- mContext.unregisterReceiver(receiver)
-
- // Ask the app again for a UUID. If data migration is working, it shall be the same.
- result = resolver.call(authority, "data", null, null).assertNotNull()
- val newUUID = result.getString(RESULT_KEY)
- assertEquals(oldUUID, newUUID)
- uninstallPackage(Const.DATA_TEST_PKG)
- }
-
- @Test
- fun testKeyMigration() {
- val apk = "$TMP_APK_PATH/DataTestApp"
- assertTrue(installPackage(apk + "1.apk"))
- val oldUid = mPm.getPackageUid(Const.DATA_TEST_PKG, PackageInfoFlags.of(0))
- val authority = Const.DATA_TEST_PKG + ".provider"
- val resolver = mContext.contentResolver
- val secret = UUID.randomUUID().toString()
-
- // Ask the app to encrypt secret with AES.
- var result = resolver.call(authority, "encryptAES", secret, null).assertNotNull()
- assertNotNull(result[RESULT_KEY])
- assertNotNull(result["iv"])
- val encResult = result
-
- // Ask the app to generate a new EC keypair and sign our data.
- result = resolver.call(authority, "signEC", secret, null).assertNotNull()
- val signature = result.getByteArray(RESULT_KEY).assertNotNull()
- val oldCertChain = result.getByteArray("certChain").assertNotNull()
-
- // Update the data test APK and make sure UID changed.
- assertTrue(installPackage(apk + "2.apk"))
- val newUid = mPm.getPackageUid(Const.DATA_TEST_PKG, PackageInfoFlags.of(0))
- assertNotEquals(oldUid, newUid)
-
- // Ask the app to decrypt our secret.
- result = resolver.call(authority, "decryptAES", null, encResult).assertNotNull()
- val decSecret = result.getString(RESULT_KEY)
- assertEquals(secret, decSecret)
-
- // Ask the app to return the previously generated EC certificate.
- result = resolver.call(authority, "getECCert", null, null).assertNotNull()
- val rawCert = result.getByteArray(RESULT_KEY).assertNotNull()
- val newCertChain = result.getByteArray("certChain").assertNotNull()
- val cf = CertificateFactory.getInstance("X.509")
- val cert = cf.generateCertificate(ByteArrayInputStream(rawCert)) as X509Certificate
-
- // Verify the signature and cert.
- assertArrayEquals(oldCertChain, newCertChain)
- val s = Signature.getInstance("SHA256withECDSA")
- s.initVerify(cert)
- s.update(secret.toByteArray(UTF_8))
- assertTrue(s.verify(signature))
- uninstallPackage(Const.DATA_TEST_PKG)
- }
-
- private fun installPackage(apkPath: String): Boolean {
- return runShellCommand("pm install --force-queryable -t $apkPath") == "Success\n"
- }
-
- private fun uninstallPackage(packageName: String) {
- runShellCommand("pm uninstall $packageName")
- }
-
- class PackageBroadcastReceiver(
- private val mPreviousUid: Int
- ) : BroadcastReceiver(), BlockingQueue<Throwable?> by ArrayBlockingQueue<Throwable?>(1) {
-
- var newUid = -1
- private set
- private var mCounter = 0
-
- override fun onReceive(context: Context?, intent: Intent) {
- try {
- verifyInternal(intent)
- } catch (e: Throwable) {
- offer(e)
+ if (Build.IS_USERDEBUG) {
+ testNewInstallOnly(uid)
+ reset(uid)
+ testBestEffort(uid)
+ } else {
+ when (migrationStrategy) {
+ NEW_INSTALL_ONLY -> testNewInstallOnly(uid)
+ BEST_EFFORT -> testBestEffort(uid)
}
}
- private fun verifyInternal(intent: Intent) {
- val action = intent.action
- assertNotNull(action)
- if (action == Intent.ACTION_UID_REMOVED) {
- // Not the test package, none of our business.
- if (intent.getIntExtra(Intent.EXTRA_UID, -1) != mPreviousUid) {
- return
- }
- }
- val data = intent.data
- if (data != null) {
- assertEquals("package", data.scheme)
- val pkg = data.schemeSpecificPart
- assertNotNull(pkg)
- // Not the test package, none of our business.
- if (Const.DATA_TEST_PKG != pkg) {
- return
- }
- }
-
- // Broadcasts must come in the following order:
- // ACTION_PACKAGE_REMOVED -> ACTION_UID_REMOVED
- // -> ACTION_PACKAGE_ADDED -> ACTION_UPDATE_ACK
- mCounter++
- when (action) {
- Intent.ACTION_PACKAGE_REMOVED -> {
- assertEquals(1, mCounter)
- assertFalse(intent.hasExtra(Intent.EXTRA_REPLACING))
- assertTrue(intent.getBooleanExtra(Intent.EXTRA_UID_CHANGING, false))
- assertEquals(mPreviousUid, intent.getIntExtra(Intent.EXTRA_UID, -1))
- newUid = intent.getIntExtra(Intent.EXTRA_NEW_UID, -1)
- assertNotEquals(mPreviousUid, newUid)
- }
- Intent.ACTION_UID_REMOVED -> {
- assertEquals(2, mCounter)
- assertFalse(intent.hasExtra(Intent.EXTRA_REPLACING))
- assertTrue(intent.getBooleanExtra(Intent.EXTRA_UID_CHANGING, false))
- assertEquals(
- Const.DATA_TEST_PKG,
- intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME)
- )
- }
- Intent.ACTION_PACKAGE_ADDED -> {
- assertEquals(3, mCounter)
- assertFalse(intent.hasExtra(Intent.EXTRA_REPLACING))
- assertTrue(intent.getBooleanExtra(Intent.EXTRA_UID_CHANGING, false))
- assertEquals(newUid, intent.getIntExtra(Intent.EXTRA_UID, mPreviousUid))
- assertEquals(mPreviousUid, intent.getIntExtra(Intent.EXTRA_PREVIOUS_UID, -1))
- }
- Const.ACTION_UPDATE_ACK -> {
- assertEquals(4, mCounter)
- assertEquals(newUid, intent.getIntExtra(Intent.EXTRA_UID, -2))
- // End of actions
- offer(NOT_AN_ERROR)
- }
- Intent.ACTION_PACKAGE_REPLACED -> fail("PACKAGE_REPLACED should not be called!")
- else -> fail("Unknown action received")
- }
- }
+ tearDown()
}
}
\ No newline at end of file
diff --git a/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java b/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java
index 72b4e97..95ed1db0 100644
--- a/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java
+++ b/tests/tests/view/src/android/view/cts/ASurfaceControlTest.java
@@ -1625,6 +1625,30 @@
}
@Test
+ public void testSurfaceTransaction_scaleToZero() {
+ verifyTest(
+ new BasicSurfaceHolderCallback() {
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ long parentSurfaceControl = createFromWindow(holder.getSurface());
+ long childSurfaceControl = create(parentSurfaceControl);
+
+ setSolidBuffer(parentSurfaceControl,
+ DEFAULT_LAYOUT_WIDTH, DEFAULT_LAYOUT_HEIGHT, PixelColor.YELLOW);
+ setSolidBuffer(childSurfaceControl,
+ DEFAULT_LAYOUT_WIDTH, DEFAULT_LAYOUT_HEIGHT, PixelColor.RED);
+ setScale(childSurfaceControl, 0f, 0f);
+ }
+ },
+ new PixelChecker(PixelColor.YELLOW) {
+ @Override
+ public boolean checkPixels(int matchingPixelCount, int width, int height) {
+ return matchingPixelCount > 9000 & matchingPixelCount < 11000;
+ }
+ });
+ }
+
+ @Test
public void testSurfaceTransaction_setPositionAndScale() {
verifyTest(
new BasicSurfaceHolderCallback() {
diff --git a/tests/tests/view/src/android/view/cts/DisplayRefreshRateCtsActivity.java b/tests/tests/view/src/android/view/cts/DisplayRefreshRateCtsActivity.java
index 957ee10..2fd87ca 100644
--- a/tests/tests/view/src/android/view/cts/DisplayRefreshRateCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/DisplayRefreshRateCtsActivity.java
@@ -18,6 +18,8 @@
import android.opengl.GLSurfaceView;
import android.util.Log;
+import android.view.Window;
+import android.view.WindowManager;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
@@ -141,4 +143,14 @@
public FpsResult getFpsResult() {
return mResult;
}
+
+ public void setModeId(int modeId) {
+ runOnUiThread(() -> {
+ Window w = getWindow();
+ WindowManager.LayoutParams params = w.getAttributes();
+ params.preferredDisplayModeId = modeId;
+ w.setAttributes(params);
+ });
+
+ }
}
diff --git a/tests/tests/view/src/android/view/cts/DisplayRefreshRateTest.java b/tests/tests/view/src/android/view/cts/DisplayRefreshRateTest.java
index 618ca21..c8f16ef 100644
--- a/tests/tests/view/src/android/view/cts/DisplayRefreshRateTest.java
+++ b/tests/tests/view/src/android/view/cts/DisplayRefreshRateTest.java
@@ -18,21 +18,32 @@
import static org.junit.Assert.assertTrue;
+import android.Manifest;
import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.AdoptShellPermissionsRule;
+
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
/**
* Test that the screen refresh rate claimed by
* android.view.Display.getRefreshRate() matches the steady-state framerate
@@ -51,30 +62,112 @@
private static final String TAG = "DisplayRefreshRateTest";
- @Rule
- public ActivityTestRule<DisplayRefreshRateCtsActivity> mActivityRule =
- new ActivityTestRule<>(DisplayRefreshRateCtsActivity.class);
+ private DisplayManager mDisplayManager;
+
+ private Display mDisplay;
+
+ private int mInitialMatchContentFrameRate;
+
+ private final DisplayListener mDisplayListener = new DisplayListener();
private DisplayRefreshRateCtsActivity mActivity;
private DisplayRefreshRateCtsActivity.FpsResult mFpsResult;
+ @Rule
+ public ActivityTestRule<DisplayRefreshRateCtsActivity> mActivityRule =
+ new ActivityTestRule<>(DisplayRefreshRateCtsActivity.class);
+
+ @Rule
+ public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule(
+ InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+ Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS,
+ Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE);
+
+ class DisplayListener implements DisplayManager.DisplayListener {
+ private CountDownLatch mCountDownLatch = new CountDownLatch(1);
+
+ void waitForModeToChange(int modeId) throws InterruptedException {
+ while (modeId != mDisplay.getMode().getModeId()) {
+ mCountDownLatch.await(5, TimeUnit.SECONDS);
+ }
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (displayId != mDisplay.getDisplayId()) {
+ return;
+ }
+
+ mCountDownLatch.countDown();
+ }
+ }
+
+
@Before
- public void setup() {
+ public void setup() throws InterruptedException {
mActivity = mActivityRule.getActivity();
mFpsResult = mActivity.getFpsResult();
+
+ Context context = mActivity.getApplicationContext();
+ mDisplayManager = context.getSystemService(DisplayManager.class);
+
+ mInitialMatchContentFrameRate =
+ toSwitchingType(mDisplayManager.getMatchContentFrameRateUserPreference());
+ mDisplayManager.setRefreshRateSwitchingType(DisplayManager.SWITCHING_TYPE_NONE);
+ mDisplayManager.setShouldAlwaysRespectAppRequestedMode(true);
+
+ // This tests the fps of the default display.
+ // In consideration of multi-display devices we use getApplicationContext()
+ // to get the default display.
+ WindowManager wm = context.getSystemService(WindowManager.class);
+ mDisplay = wm.getDefaultDisplay();
+
+ mDisplayManager.registerDisplayListener(mDisplayListener,
+ new Handler(Looper.getMainLooper()));
+
+ int highestRefreshRateModeId = getHighestRefreshRateModeId();
+ mActivity.setModeId(highestRefreshRateModeId);
+ mDisplayListener.waitForModeToChange(highestRefreshRateModeId);
+ }
+
+ private int getHighestRefreshRateModeId() {
+ int highestRefreshRateModeId = mDisplay.getMode().getModeId();
+ for (Display.Mode mode : mDisplay.getSupportedModes()) {
+ if (mode.getPhysicalHeight() != mDisplay.getMode().getPhysicalHeight()) {
+ continue;
+ }
+
+ if (mode.getPhysicalWidth() != mDisplay.getMode().getPhysicalWidth()) {
+ continue;
+ }
+
+ if (mode.getRefreshRate() > mDisplay.getMode().getRefreshRate()) {
+ highestRefreshRateModeId = mode.getModeId();
+ }
+ }
+ return highestRefreshRateModeId;
+ }
+
+ @After
+ public void tearDown() {
+ mDisplayManager.setRefreshRateSwitchingType(mInitialMatchContentFrameRate);
+ mDisplayManager.setShouldAlwaysRespectAppRequestedMode(false);
}
@Test
public void testRefreshRate() {
boolean fpsOk = false;
- // This tests the fps of the default display.
- // In consideration of multi-display devices we use getApplicationContext()
- // to get the default display.
- Context context = mActivity.getApplicationContext();
- WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-
- Display dpy = wm.getDefaultDisplay();
- float claimedFps = dpy.getRefreshRate();
+ float claimedFps = mDisplay.getRefreshRate();
for (int i = 0; i < 3; i++) {
float achievedFps = mFpsResult.waitResult();
@@ -93,4 +186,17 @@
mActivity.finish();
assertTrue(fpsOk);
}
+
+ private static int toSwitchingType(int matchContentFrameRateUserPreference) {
+ switch (matchContentFrameRateUserPreference) {
+ case DisplayManager.MATCH_CONTENT_FRAMERATE_NEVER:
+ return DisplayManager.SWITCHING_TYPE_NONE;
+ case DisplayManager.MATCH_CONTENT_FRAMERATE_SEAMLESSS_ONLY:
+ return DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS;
+ case DisplayManager.MATCH_CONTENT_FRAMERATE_ALWAYS:
+ return DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS;
+ default:
+ return -1;
+ }
+ }
}
diff --git a/tests/tests/view/src/android/view/cts/SurfaceControlTest.java b/tests/tests/view/src/android/view/cts/SurfaceControlTest.java
index 8595664..ab245d2 100644
--- a/tests/tests/view/src/android/view/cts/SurfaceControlTest.java
+++ b/tests/tests/view/src/android/view/cts/SurfaceControlTest.java
@@ -1224,4 +1224,31 @@
}
});
}
+
+ @Test
+ public void testSurfaceControl_scaleToZero() {
+ verifyTest(
+ new BasicSurfaceHolderCallback() {
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ SurfaceControl parentSurfaceControl = createFromWindow(holder);
+ SurfaceControl childSurfaceControl = create(parentSurfaceControl);
+
+ setSolidBuffer(parentSurfaceControl,
+ DEFAULT_LAYOUT_WIDTH, DEFAULT_LAYOUT_HEIGHT, PixelColor.YELLOW);
+ setSolidBuffer(childSurfaceControl,
+ DEFAULT_LAYOUT_WIDTH, DEFAULT_LAYOUT_HEIGHT, PixelColor.RED);
+ new SurfaceControl.Transaction()
+ .setScale(childSurfaceControl, 0, 0)
+ .apply();
+ }
+ },
+ new PixelChecker(PixelColor.YELLOW) {
+ @Override
+ public boolean checkPixels(int matchingPixelCount, int width, int height) {
+ return matchingPixelCount > 9000 && matchingPixelCount < 11000;
+ }
+ }
+ );
+ }
}
diff --git a/tests/tests/view/src/android/view/cts/input/OWNERS b/tests/tests/view/src/android/view/cts/input/OWNERS
index bbaec4d..c88bfe9 100644
--- a/tests/tests/view/src/android/view/cts/input/OWNERS
+++ b/tests/tests/view/src/android/view/cts/input/OWNERS
@@ -1,4 +1 @@
-# Bug component: 136048
-michaelwr@google.com
-prabirmsp@google.com
-svv@google.com
\ No newline at end of file
+include platform/frameworks/base:/INPUT_OWNERS
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index db505a9..dbf9c5a 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -8551,10 +8551,8 @@
mTextView.setTextMetricsParams(param);
assertTrue(param.equals(mTextView.getTextMetricsParams()));
- LineBreakConfig lbConfig = new LineBreakConfig();
- lbConfig.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT);
- lbConfig.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
- mTextView.setLineBreakConfig(lbConfig);
+ mTextView.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT);
+ mTextView.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
PrecomputedText.Params resultParams = mTextView.getTextMetricsParams();
assertEquals(LineBreakConfig.LINE_BREAK_STYLE_STRICT,
@@ -8607,186 +8605,219 @@
public void testLineBreakConfigDefaultValue() {
final Context context = InstrumentationRegistry.getTargetContext();
final TextView textView = new TextView(context);
- LineBreakConfig lbConfig = textView.getLineBreakConfig();
- assertEquals(LineBreakConfig.LINE_BREAK_STYLE_NONE, lbConfig.getLineBreakStyle());
- assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE, lbConfig.getLineBreakWordStyle());
+ assertEquals(LineBreakConfig.LINE_BREAK_STYLE_NONE, textView.getLineBreakStyle());
+ assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE, textView.getLineBreakWordStyle());
}
@UiThreadTest
@Test
public void testSetGetLineBreakConfig() {
TextView tv = new TextView(mActivity);
- LineBreakConfig lbConfig = new LineBreakConfig();
+ tv.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NONE);
+ assertEquals(LineBreakConfig.LINE_BREAK_STYLE_NONE, tv.getLineBreakStyle());
- lbConfig.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE);
- tv.setLineBreakConfig(lbConfig);
- LineBreakConfig resultLbConfig = tv.getLineBreakConfig();
- assertEquals(LineBreakConfig.LINE_BREAK_STYLE_LOOSE, resultLbConfig.getLineBreakStyle());
+ tv.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE);
+ assertEquals(LineBreakConfig.LINE_BREAK_STYLE_LOOSE, tv.getLineBreakStyle());
- lbConfig.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NORMAL);
- tv.setLineBreakConfig(lbConfig);
- resultLbConfig = tv.getLineBreakConfig();
- assertEquals(LineBreakConfig.LINE_BREAK_STYLE_NORMAL, resultLbConfig.getLineBreakStyle());
+ tv.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NORMAL);
+ assertEquals(LineBreakConfig.LINE_BREAK_STYLE_NORMAL, tv.getLineBreakStyle());
- lbConfig.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT);
- tv.setLineBreakConfig(lbConfig);
- resultLbConfig = tv.getLineBreakConfig();
- assertEquals(LineBreakConfig.LINE_BREAK_STYLE_STRICT, resultLbConfig.getLineBreakStyle());
+ tv.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT);
+ assertEquals(LineBreakConfig.LINE_BREAK_STYLE_STRICT, tv.getLineBreakStyle());
- lbConfig.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE);
- tv.setLineBreakConfig(lbConfig);
- resultLbConfig = tv.getLineBreakConfig();
- assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE,
- resultLbConfig.getLineBreakWordStyle());
+ tv.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE);
+ assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE, tv.getLineBreakWordStyle());
- lbConfig.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
- tv.setLineBreakConfig(lbConfig);
- resultLbConfig = tv.getLineBreakConfig();
+ tv.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
+ assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE, tv.getLineBreakWordStyle());
+ }
+
+ @Test
+ public void testUpdateLineBreakConfigBuilder() {
+ LineBreakConfig.Builder builder = new LineBreakConfig.Builder();
+ builder.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
+ LineBreakConfig resultConfig = builder.build();
+
+ assertEquals(LineBreakConfig.LINE_BREAK_STYLE_STRICT, resultConfig.getLineBreakStyle());
assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE,
- resultLbConfig.getLineBreakWordStyle());
-
- try {
- lbConfig.set(null);
- fail("Should thrown NullPointerException if the line break config is null");
- } catch (NullPointerException e) {
- }
-
- try {
- tv.setLineBreakConfig(null);
- fail("Should thrown NullPointerException if the line break config is null");
- } catch (NullPointerException e) {
- }
+ resultConfig.getLineBreakWordStyle());
}
@Test
public void testLineBreakConfigByStyle() {
TextView defaultTv = findTextView(R.id.textview_line_break_style_default);
- TextView noneTv = findTextView(R.id.textview_line_break_style_none);
- TextView looseTv = findTextView(R.id.textview_line_break_style_loose);
- TextView normalTv = findTextView(R.id.textview_line_break_style_normal);
- TextView strictTv = findTextView(R.id.textview_line_break_style_strict);
+ TextView nonePhraseTv = findTextView(R.id.textview_line_break_style_none);
+ TextView looseNoneTv = findTextView(R.id.textview_line_break_style_loose);
+ TextView normalPhraseTv = findTextView(R.id.textview_line_break_style_normal);
+ TextView strictNoneTv = findTextView(R.id.textview_line_break_style_strict);
+ TextView loosePhraseTv = findTextView(R.id.textview_line_break_with_style);
- assertEquals(LineBreakConfig.LINE_BREAK_STYLE_NONE,
- defaultTv.getLineBreakConfig().getLineBreakStyle());
- assertEquals(LineBreakConfig.LINE_BREAK_STYLE_NONE,
- noneTv.getLineBreakConfig().getLineBreakStyle());
- assertEquals(LineBreakConfig.LINE_BREAK_STYLE_LOOSE,
- looseTv.getLineBreakConfig().getLineBreakStyle());
- assertEquals(LineBreakConfig.LINE_BREAK_STYLE_NORMAL,
- normalTv.getLineBreakConfig().getLineBreakStyle());
- assertEquals(LineBreakConfig.LINE_BREAK_STYLE_STRICT,
- strictTv.getLineBreakConfig().getLineBreakStyle());
+ assertEquals(LineBreakConfig.LINE_BREAK_STYLE_NONE, defaultTv.getLineBreakStyle());
+ assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE, defaultTv.getLineBreakWordStyle());
- assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE,
- defaultTv.getLineBreakConfig().getLineBreakWordStyle());
+ assertEquals(LineBreakConfig.LINE_BREAK_STYLE_NONE, nonePhraseTv.getLineBreakStyle());
assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE,
- noneTv.getLineBreakConfig().getLineBreakWordStyle());
- assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE,
- looseTv.getLineBreakConfig().getLineBreakWordStyle());
- assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE,
- normalTv.getLineBreakConfig().getLineBreakWordStyle());
- assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE,
- strictTv.getLineBreakConfig().getLineBreakWordStyle());
+ nonePhraseTv.getLineBreakWordStyle());
- TextView styleTv = findTextView(R.id.textview_line_break_with_style);
- assertEquals(LineBreakConfig.LINE_BREAK_STYLE_LOOSE,
- styleTv.getLineBreakConfig().getLineBreakStyle());
+ assertEquals(LineBreakConfig.LINE_BREAK_STYLE_LOOSE, looseNoneTv.getLineBreakStyle());
+ assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE,
+ looseNoneTv.getLineBreakWordStyle());
+
+ assertEquals(LineBreakConfig.LINE_BREAK_STYLE_NORMAL, normalPhraseTv.getLineBreakStyle());
assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE,
- styleTv.getLineBreakConfig().getLineBreakWordStyle());
+ normalPhraseTv.getLineBreakWordStyle());
+
+ assertEquals(LineBreakConfig.LINE_BREAK_STYLE_STRICT, strictNoneTv.getLineBreakStyle());
+ assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE,
+ strictNoneTv.getLineBreakWordStyle());
+
+ assertEquals(LineBreakConfig.LINE_BREAK_STYLE_LOOSE, loosePhraseTv.getLineBreakStyle());
+ assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE,
+ loosePhraseTv.getLineBreakWordStyle());
}
@Test
public void testLineBreakConfigWithTextAppearance() {
TextView textView = new TextView(mActivity);
+ textView.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE);
+ textView.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE);
+
+ // Override the line break config via TextAppearance.
textView.setTextAppearance(R.style.LineBreakStyle_strict);
- assertEquals(LineBreakConfig.LINE_BREAK_STYLE_STRICT,
- textView.getLineBreakConfig().getLineBreakStyle());
+ assertEquals(LineBreakConfig.LINE_BREAK_STYLE_STRICT, textView.getLineBreakStyle());
textView.setTextAppearance(R.style.LineBreakWordStyle_phrase);
assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE,
- textView.getLineBreakConfig().getLineBreakWordStyle());
+ textView.getLineBreakWordStyle());
textView.setTextAppearance(R.style.LineBreakConfig_loose_phrase);
- assertEquals(LineBreakConfig.LINE_BREAK_STYLE_LOOSE,
- textView.getLineBreakConfig().getLineBreakStyle());
+ assertEquals(LineBreakConfig.LINE_BREAK_STYLE_LOOSE, textView.getLineBreakStyle());
assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE,
- textView.getLineBreakConfig().getLineBreakWordStyle());
-
- LineBreakConfig lbConfig = new LineBreakConfig();
-
- // Verify only the lineBreakStyle style is set.
- TextView textView2 = new TextView(mActivity);
- // Init the line break config in the TextView.
- lbConfig.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE);
- lbConfig.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
- textView2.setLineBreakConfig(lbConfig);
- // Override the line break style from "loose" to "strict" via the TextAppearance.
- textView2.setTextAppearance(R.style.LineBreakStyle_strict);
- assertEquals(LineBreakConfig.LINE_BREAK_STYLE_STRICT,
- textView2.getLineBreakConfig().getLineBreakStyle());
- assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE,
- textView2.getLineBreakConfig().getLineBreakWordStyle());
-
- // Verify only the lineBreakWordStyle style is set.
- TextView textView3 = new TextView(mActivity);
- // Init the line break config in the TextView.
- lbConfig.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT);
- lbConfig.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE);
- textView3.setLineBreakConfig(lbConfig);
- // Override the line break word style from "none" to "phrase" via the TextAppearance.
- textView3.setTextAppearance(R.style.LineBreakWordStyle_phrase);
- assertEquals(LineBreakConfig.LINE_BREAK_STYLE_STRICT,
- textView3.getLineBreakConfig().getLineBreakStyle());
- assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE,
- textView3.getLineBreakConfig().getLineBreakWordStyle());
+ textView.getLineBreakWordStyle());
}
@Test
- public void testLineBreakConfigEquals() {
- LineBreakConfig config1 = new LineBreakConfig();
- config1.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE);
+ public void testLineBreakStyleEquals_returnsFalseIfStyleIsDifferent() {
+ LineBreakConfig looseNoneConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
- LineBreakConfig config2 = new LineBreakConfig();
- config2.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NORMAL);
+ LineBreakConfig normalNoneConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NORMAL)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
- LineBreakConfig config3 = new LineBreakConfig();
- config3.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT);
+ LineBreakConfig strictNoneConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
- assertFalse(config1.equals(config2));
- assertFalse(config1.equals(config3));
- assertFalse(config2.equals(config3));
- assertFalse(Objects.equals(config1, config2));
- assertFalse(Objects.equals(config1, config3));
- assertFalse(Objects.equals(config2, config3));
+ // Verify the lineBreakConfig instances are not equals.
+ assertFalse(looseNoneConfig.equals(normalNoneConfig));
+ assertFalse(looseNoneConfig.equals(strictNoneConfig));
+ assertFalse(normalNoneConfig.equals(strictNoneConfig));
+ assertFalse(Objects.equals(looseNoneConfig, normalNoneConfig));
+ assertFalse(Objects.equals(looseNoneConfig, strictNoneConfig));
+ assertFalse(Objects.equals(normalNoneConfig, strictNoneConfig));
+ }
- LineBreakConfig config4 = new LineBreakConfig();
- config4.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE);
- assertTrue(config1.equals(config4));
- assertTrue(Objects.equals(config1, config4));
+ @Test
+ public void testLineBreakStyleEquals_returnsTrueIfStyleIsNotDifferent() {
+ LineBreakConfig looseNoneConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
- LineBreakConfig config5 = new LineBreakConfig();
- config5.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE);
+ LineBreakConfig newLooseNoneConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
- LineBreakConfig config6 = new LineBreakConfig();
- config6.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
+ assertTrue(newLooseNoneConfig.equals(looseNoneConfig));
+ assertTrue(Objects.equals(newLooseNoneConfig, looseNoneConfig));
- LineBreakConfig config7 = new LineBreakConfig();
- config7.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE);
- config7.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
+ LineBreakConfig normalNoneConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NORMAL)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
- assertFalse(config5.equals(config6));
- assertFalse(config5.equals(config7));
- assertFalse(config6.equals(config7));
- assertFalse(Objects.equals(config5, config6));
- assertFalse(Objects.equals(config5, config7));
- assertFalse(Objects.equals(config6, config7));
+ LineBreakConfig newNormalNoneConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NORMAL)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
- LineBreakConfig config8 = new LineBreakConfig();
- config8.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE);
- config8.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
+ assertTrue(newNormalNoneConfig.equals(normalNoneConfig));
+ assertTrue(Objects.equals(newNormalNoneConfig, normalNoneConfig));
- assertTrue(config7.equals(config8));
- assertTrue(Objects.equals(config7, config8));
+ LineBreakConfig strictNoneConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
+
+ LineBreakConfig newStringNoneStrictConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
+
+ assertTrue(newStringNoneStrictConfig.equals(strictNoneConfig));
+ assertTrue(Objects.equals(newStringNoneStrictConfig, strictNoneConfig));
+ }
+
+ @Test
+ public void testLineBreakWordStyleEquals_returnsFalseIfWordStyleIsDifferent() {
+ LineBreakConfig nonePhraseConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NONE)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE).build();
+
+ LineBreakConfig noneNoneConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NONE)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE).build();
+
+ // Verify the lineBreakConfig instances are not equals.
+ assertFalse(nonePhraseConfig.equals(noneNoneConfig));
+ assertFalse(Objects.equals(nonePhraseConfig, noneNoneConfig));
+ }
+
+ @Test
+ public void testLineBreakWordStyleEquals_returnsTrueIfWordStyleIsNotDifferent() {
+ LineBreakConfig nonePhraseConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NONE)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE).build();
+
+ LineBreakConfig newNonePhraseConfig = new LineBreakConfig.Builder()
+ .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NONE)
+ .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE).build();
+ assertTrue(nonePhraseConfig.equals(newNonePhraseConfig));
+ assertTrue(Objects.equals(nonePhraseConfig, newNonePhraseConfig));
+ }
+
+ @Test
+ public void testLineBreakConfigEquals_returnFalseIfValueOfConfigIsDifferent() {
+ LineBreakConfig[] lineBreakConfigArray = new LineBreakConfig[8];
+
+ int[] lineBreakStyleArray = {
+ LineBreakConfig.LINE_BREAK_STYLE_NONE,
+ LineBreakConfig.LINE_BREAK_STYLE_LOOSE,
+ LineBreakConfig.LINE_BREAK_STYLE_NORMAL,
+ LineBreakConfig.LINE_BREAK_STYLE_STRICT,
+ };
+
+ int[] lineBreakWordStyleArray = {
+ LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE,
+ LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE,
+ };
+
+ int index = 0;
+ for (int lineBreakStyle : lineBreakStyleArray) {
+ for (int lineBreakWordStyle : lineBreakWordStyleArray) {
+ lineBreakConfigArray[index++] = new LineBreakConfig.Builder()
+ .setLineBreakStyle(lineBreakStyle)
+ .setLineBreakWordStyle(lineBreakWordStyle).build();
+ }
+ }
+
+ // Verify the lineBreakConfig instances are not equal.
+ for (int i = 0; i < lineBreakConfigArray.length - 1; i++) {
+ LineBreakConfig lbConfig = lineBreakConfigArray[i];
+ for (int j = i + 1; j < lineBreakConfigArray.length; j++) {
+ LineBreakConfig comparedLbConfig = lineBreakConfigArray[j];
+ assertFalse(lbConfig.equals(comparedLbConfig));
+ assertFalse(Objects.equals(lbConfig, comparedLbConfig));
+ }
+ }
}
@Test
diff --git a/tests/tests/widget/src/android/widget/cts/ToastTest.java b/tests/tests/widget/src/android/widget/cts/ToastTest.java
index c3a16f3..e21a64c 100644
--- a/tests/tests/widget/src/android/widget/cts/ToastTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToastTest.java
@@ -853,8 +853,12 @@
public void testTextToastNotAllowed_whenInTheBackground_withoutNotificationPermission()
throws Throwable {
assumeFalse("Skipping test: Watch does not support new Toast behavior yet", isWatch());
+
// Make it background
mActivityRule.finishActivity();
+ // may take time for the app process importance to get downgraded from foreground:
+ SystemClock.sleep(TIME_FOR_UI_OPERATION);
+
List<TextToastInfo> toastInfoList = createTextToasts(1, "Text", Toast.LENGTH_SHORT);
mActivityRule.runOnUiThread(
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
index ed2342d..b6fd50a 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
@@ -4700,10 +4700,10 @@
}
/**
- * Verify the invalid and valid usages of {@code WifiManager#getAutojoinGlobal}.
+ * Verify the invalid and valid usages of {@code WifiManager#queryAutojoinGlobal}.
*/
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
- public void testGetAutojoinGlobal() throws Exception {
+ public void testQueryAutojoinGlobal() throws Exception {
if (!WifiFeature.isWifiSupported(getContext())) {
// skip the test if WiFi is not supported
return;
@@ -4721,19 +4721,19 @@
};
// Test invalid inputs trigger IllegalArgumentException
assertThrows("null executor should trigger exception", NullPointerException.class,
- () -> mWifiManager.getAutojoinGlobal(null, listener));
+ () -> mWifiManager.queryAutojoinGlobal(null, listener));
assertThrows("null listener should trigger exception", NullPointerException.class,
- () -> mWifiManager.getAutojoinGlobal(mExecutor, null));
+ () -> mWifiManager.queryAutojoinGlobal(mExecutor, null));
// Test caller with no permission triggers SecurityException.
assertThrows("No permission should trigger SecurityException", SecurityException.class,
- () -> mWifiManager.getAutojoinGlobal(mExecutor, listener));
+ () -> mWifiManager.queryAutojoinGlobal(mExecutor, listener));
// Test get/set autojoin global enabled
ShellIdentityUtils.invokeWithShellPermissions(
() -> mWifiManager.allowAutojoinGlobal(true));
ShellIdentityUtils.invokeWithShellPermissions(
- () -> mWifiManager.getAutojoinGlobal(mExecutor, listener));
+ () -> mWifiManager.queryAutojoinGlobal(mExecutor, listener));
synchronized (mLock) {
mLock.wait(TEST_WAIT_DURATION_MS);
}
@@ -4743,7 +4743,7 @@
ShellIdentityUtils.invokeWithShellPermissions(
() -> mWifiManager.allowAutojoinGlobal(false));
ShellIdentityUtils.invokeWithShellPermissions(
- () -> mWifiManager.getAutojoinGlobal(mExecutor, listener));
+ () -> mWifiManager.queryAutojoinGlobal(mExecutor, listener));
synchronized (mLock) {
mLock.wait(TEST_WAIT_DURATION_MS);
}
@@ -5553,8 +5553,27 @@
}
/**
- * Tests
- * {@link WifiManager#reportCreateInterfaceImpact(int, boolean, Executor, BiConsumer)}.
+ * Verifies that
+ * {@link WifiManager#reportCreateInterfaceImpact(int, boolean, Executor, BiConsumer)} raises
+ * a security exception without permission.
+ */
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ public void testIsItPossibleToCreateInterfaceNotAllowed() throws Exception {
+ if (!WifiFeature.isWifiSupported(getContext())) {
+ // skip the test if WiFi is not supported
+ return;
+ }
+
+ assertThrows(SecurityException.class, () -> mWifiManager.reportCreateInterfaceImpact(
+ WifiManager.WIFI_INTERFACE_TYPE_AP, false, mExecutor,
+ (canBeCreatedLocal, interfacesWhichWillBeDeletedLocal) -> {
+ // should not get here (security exception!)
+ }));
+ }
+
+ /**
+ * Verifies
+ * {@link WifiManager#reportCreateInterfaceImpact(int, boolean, Executor, BiConsumer)} .
*/
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
public void testIsItPossibleToCreateInterface() throws Exception {
@@ -5565,17 +5584,35 @@
AtomicBoolean called = new AtomicBoolean(false);
AtomicBoolean canBeCreated = new AtomicBoolean(false);
- assertThrows(SecurityException.class, () -> mWifiManager.reportCreateInterfaceImpact(
- WifiManager.WIFI_INTERFACE_TYPE_AP, false, mExecutor,
- (canBeCreatedLocal, interfacesWhichWillBeDeleted) -> {
- synchronized (mLock) {
- canBeCreated.set(canBeCreatedLocal);
- called.set(true);
- mLock.notify();
- }
- }));
+ AtomicReference<List<WifiManager.InterfaceCreationImpact>>
+ interfacesWhichWillBeDeleted = new AtomicReference<>(null);
+ ShellIdentityUtils.invokeWithShellPermissions(
+ () -> mWifiManager.reportCreateInterfaceImpact(
+ WifiManager.WIFI_INTERFACE_TYPE_AP, false, mExecutor,
+ (canBeCreatedLocal, interfacesWhichWillBeDeletedLocal) -> {
+ synchronized (mLock) {
+ canBeCreated.set(canBeCreatedLocal);
+ called.set(true);
+ interfacesWhichWillBeDeleted.set(interfacesWhichWillBeDeletedLocal);
+ mLock.notify();
+ }
+ }));
synchronized (mLock) {
mLock.wait(TEST_WAIT_DURATION_MS);
}
+ assertTrue(called.get());
+ if (canBeCreated.get()) {
+ for (WifiManager.InterfaceCreationImpact entry : interfacesWhichWillBeDeleted.get()) {
+ int interfaceType = entry.getInterfaceType();
+ assertTrue(interfaceType == WifiManager.WIFI_INTERFACE_TYPE_STA
+ || interfaceType == WifiManager.WIFI_INTERFACE_TYPE_AP
+ || interfaceType == WifiManager.WIFI_INTERFACE_TYPE_DIRECT
+ || interfaceType == WifiManager.WIFI_INTERFACE_TYPE_AWARE);
+ Set<String> packages = entry.getPackages();
+ for (String p : packages) {
+ assertNotNull(p);
+ }
+ }
+ }
}
}
diff --git a/tests/tests/wifi/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java b/tests/tests/wifi/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java
index ec4e27b..f1780b2 100644
--- a/tests/tests/wifi/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java
@@ -131,6 +131,15 @@
} catch (Exception ignore) {}
}
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+ @Test
+ public void testGetMaxSsidsPerScan() {
+ try {
+ WifiNl80211Manager manager = mContext.getSystemService(WifiNl80211Manager.class);
+ manager.getMaxSsidsPerScan("wlan0");
+ } catch (Exception ignore) { }
+ }
+
@Test
public void testSetOnServiceDeadCallback() {
try {
diff --git a/tests/uwb/src/android/uwb/cts/RangingSessionTest.java b/tests/uwb/src/android/uwb/cts/RangingSessionTest.java
index 19c945a..6fcdc74 100644
--- a/tests/uwb/src/android/uwb/cts/RangingSessionTest.java
+++ b/tests/uwb/src/android/uwb/cts/RangingSessionTest.java
@@ -32,7 +32,7 @@
import android.os.PersistableBundle;
import android.os.RemoteException;
-import android.uwb.IUwbAdapter2;
+import android.uwb.IUwbAdapter;
import android.uwb.RangingReport;
import android.uwb.RangingSession;
import android.uwb.SessionHandle;
@@ -64,7 +64,7 @@
public void testOnRangingOpened_OnOpenSuccessCalled() {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter2 adapter = mock(IUwbAdapter2.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
verifyOpenState(session, false);
@@ -80,7 +80,7 @@
public void testOnRangingOpened_OnServiceDiscoveredConnectedCalled() {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter2 adapter = mock(IUwbAdapter2.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
verifyOpenState(session, false);
@@ -103,7 +103,7 @@
public void testOnRangingOpened_CannotOpenClosedSession() {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter2 adapter = mock(IUwbAdapter2.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
session.onRangingOpened();
@@ -127,7 +127,7 @@
public void testOnRangingClosed_OnClosedCalledWhenSessionNotOpen() {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter2 adapter = mock(IUwbAdapter2.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
verifyOpenState(session, false);
@@ -143,7 +143,7 @@
public void testOnRangingClosed_OnClosedCalled() {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter2 adapter = mock(IUwbAdapter2.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
session.onRangingStarted(PARAMS);
session.onRangingClosed(REASON, PARAMS);
@@ -158,7 +158,7 @@
public void testOnRangingResult_OnReportReceivedCalled() {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter2 adapter = mock(IUwbAdapter2.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
verifyOpenState(session, false);
@@ -174,7 +174,7 @@
public void testStart_CannotStartIfAlreadyStarted() throws RemoteException {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter2 adapter = mock(IUwbAdapter2.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
session.onRangingOpened();
@@ -191,7 +191,7 @@
public void testStop_CannotStopIfAlreadyStopped() throws RemoteException {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter2 adapter = mock(IUwbAdapter2.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
doAnswer(new StopAnswer(session)).when(adapter).stopRanging(any());
@@ -210,7 +210,7 @@
public void testStop_CannotStopIfOpenFailed() throws RemoteException {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter2 adapter = mock(IUwbAdapter2.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
doAnswer(new StopAnswer(session)).when(adapter).stopRanging(any());
@@ -230,7 +230,7 @@
public void testCallbacks_OnlyWhenOpened() throws RemoteException {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter2 adapter = mock(IUwbAdapter2.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
doAnswer(new OpenAnswer(session)).when(adapter).openRanging(
any(), any(), any(), any(), any());
@@ -353,7 +353,7 @@
public void testClose_NoCallbackUntilInvoked() throws RemoteException {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter2 adapter = mock(IUwbAdapter2.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
session.onRangingOpened();
@@ -382,7 +382,7 @@
public void testClose_OnClosedCalled() throws RemoteException {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter2 adapter = mock(IUwbAdapter2.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any());
session.onRangingOpened();
@@ -395,7 +395,7 @@
public void testClose_CannotInteractFurther() throws RemoteException {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter2 adapter = mock(IUwbAdapter2.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any());
session.close();
@@ -410,7 +410,7 @@
public void testOnRangingResult_OnReportReceivedCalledWhenOpen() {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter2 adapter = mock(IUwbAdapter2.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
assertFalse(session.isOpen());
@@ -427,7 +427,7 @@
public void testOnRangingResult_OnReportReceivedNotCalledWhenNotOpen() {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter2 adapter = mock(IUwbAdapter2.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
assertFalse(session.isOpen());
diff --git a/tools/cts-tradefed/OWNERS b/tools/cts-tradefed/OWNERS
index 790c317..d27cf19 100644
--- a/tools/cts-tradefed/OWNERS
+++ b/tools/cts-tradefed/OWNERS
@@ -1,6 +1,5 @@
# Android EngProd Approvers
guangzhu@google.com
-fdeng@google.com
normancheung@google.com
jdesprez@google.com
@@ -15,4 +14,4 @@
per-file cts-on-csi*.xml = ycchen@google.com, hsinyichen@google.com, tyanh@google.com
per-file csi-*.xml = ycchen@google.com, hsinyichen@google.com, tyanh@google.com
per-file cts-on-gsi*.xml = bettyzhou@google.com, ycchen@google.com, hsinyichen@google.com, tyanh@google.com
-
+per-file cts-known-failures.xml = rossyeh@google.com, mariay@google.com, robinjacob@google.com
diff --git a/tools/cts-tradefed/res/config/csi-known-failures.xml b/tools/cts-tradefed/res/config/csi-known-failures.xml
index bbb98b7..86c8fe6 100644
--- a/tools/cts-tradefed/res/config/csi-known-failures.xml
+++ b/tools/cts-tradefed/res/config/csi-known-failures.xml
@@ -32,84 +32,38 @@
<option name="compatibility:exclude-filter" value="CtsStatsdHostTestCases android.cts.statsd.atom.UidAtomTests#testAppCrashOccurred" />
<option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases android.uirendering.cts.testclasses.SurfaceViewTests#testMovingWhiteSurfaceView" />
- <!-- Exclude known failure of CtsMediaTestCases (mostly on some Pixel phones) -->
+ <!-- Exclude known failure of CtsMedia*TestCases (mostly on some Pixel phones) -->
<!-- CSI doesn't seem to include ringtones. -->
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.RingtoneManagerTest" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.RingtoneTest" />
+ <option name="compatibility:exclude-filter" value="CtsMediaAudioTestCases android.media.audio.cts.RingtoneManagerTest" />
+ <option name="compatibility:exclude-filter" value="CtsMediaAudioTestCases android.media.audio.cts.RingtoneTest" />
<!-- Following failures take about 10 min each, so exclude them to reduce test time. -->
<!-- CSI on Goldfish can pass the following tests in StreamingMediaPlayerTest. -->
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.StreamingMediaPlayerTest#testHTTP_H263_AMR_Video2" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.StreamingMediaPlayerTest#testHTTP_H264Base_AAC_Video2" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.StreamingMediaPlayerTest#testHTTP_MPEG4SP_AAC_Video2" />
+ <option name="compatibility:exclude-filter" value="CtsMediaPlayerTestCases android.media.cts.player.StreamingMediaPlayerTest#testHTTP_H263_AMR_Video2" />
+ <option name="compatibility:exclude-filter" value="CtsMediaPlayerTestCases android.media.cts.player.StreamingMediaPlayerTest#testHTTP_H264Base_AAC_Video2" />
+ <option name="compatibility:exclude-filter" value="CtsMediaPlayerTestCases android.media.cts.player.StreamingMediaPlayerTest#testHTTP_MPEG4SP_AAC_Video2" />
<!-- CSI on Cuttlefish and Goldfish can pass the following tests in VideoCodecTest. -->
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoCodecTest#testParallelEncodingAndDecodingAVC" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoCodecTest#testParallelEncodingAndDecodingHEVC" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoCodecTest#testParallelEncodingAndDecodingVP8" />
+ <option name="compatibility:exclude-filter" value="CtsMediaCodecTestCases android.media.codec.cts.VideoCodecTest#testParallelEncodingAndDecoding" />
<!-- Failures will crash the test harness, so exclude it here (even though only failed with VP9 decoder). -->
<!-- CSI on Cuttlefish and Goldfish can pass the following tests in VideoDecoderRotationTest. -->
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderRotationTest" />
+ <option name="compatibility:exclude-filter" value="CtsMediaCodecTestCases android.media.codec.cts.VideoDecoderRotationTest" />
<!-- CSI on Cuttlefish and Goldfish can pass the following tests in VideoDecoderPerfTest. -->
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testAvcOther0Perf0320x0240" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testAvcOther0Perf0720x0480" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testAvcOther0Perf1280x0720" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testAvcOther1Perf0320x0240" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testAvcOther1Perf0720x0480" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testAvcOther1Perf1280x0720" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testAvcOther1Perf1920x1080" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther0Perf0352x0288" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther0Perf0640x0360" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther0Perf0720x0480" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther0Perf1280x0720" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther0Perf1920x1080" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther1Perf0352x0288" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther1Perf0640x0360" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther1Perf0720x0480" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther1Perf1280x0720" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther1Perf1920x1080" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testHevcOther1Perf3840x2160" />
+ <option name="compatibility:exclude-filter" value="CtsMediaDecoderTestCases android.media.decoder.cts.VideoDecoderPerfTest#testPerf" />
<!-- CSI on Cuttlefish and Goldfish can pass the following tests in VideoEncoderTest. -->
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH263SurfMinMin" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfArbitraryH" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfArbitraryW" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfMaxMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfMaxMin" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfMinMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfNearMaxMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfNearMaxMin" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfNearMinMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH265SurfQCIF" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfArbitraryH" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfArbitraryW" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfMaxMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfMinMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfNearMaxMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfNearMaxMin" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfNearMinMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogMpeg4SurfNearMinMin" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8Surf480p" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfArbitraryH" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfArbitraryW" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfMaxMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfMaxMin" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfMinMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfNearMaxMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfNearMaxMin" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfNearMinMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP8SurfQCIF" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9Surf480p" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfArbitraryH" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfArbitraryW" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfMaxMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfMaxMin" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfMinMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfNearMaxMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfNearMaxMin" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfNearMinMax" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogVP9SurfQCIF" />
-
+ <option name="compatibility:exclude-filter" value="CtsMediaEncoderTestCases android.media.encoder.cts.VideoEncoderTest#testSurfMinMin" />
+ <option name="compatibility:exclude-filter" value="CtsMediaEncoderTestCases android.media.encoder.cts.VideoEncoderTest#testSurfArbitraryH" />
+ <option name="compatibility:exclude-filter" value="CtsMediaEncoderTestCases android.media.encoder.cts.VideoEncoderTest#testSurfArbitraryW" />
+ <option name="compatibility:exclude-filter" value="CtsMediaEncoderTestCases android.media.encoder.cts.VideoEncoderTest#testSurfMaxMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaEncoderTestCases android.media.encoder.cts.VideoEncoderTest#testSurfMaxMin" />
+ <option name="compatibility:exclude-filter" value="CtsMediaEncoderTestCases android.media.encoder.cts.VideoEncoderTest#testSurfMinMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaEncoderTestCases android.media.encoder.cts.VideoEncoderTest#testSurfNearMaxMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaEncoderTestCases android.media.encoder.cts.VideoEncoderTest#testSurfNearMaxMin" />
+ <option name="compatibility:exclude-filter" value="CtsMediaEncoderTestCases android.media.encoder.cts.VideoEncoderTest#testSurfNearMinMax" />
+ <option name="compatibility:exclude-filter" value="CtsMediaEncoderTestCases android.media.encoder.cts.VideoEncoderTest#testSurfQCIF" />
+ <option name="compatibility:exclude-filter" value="CtsMediaEncoderTestCases android.media.encoder.cts.VideoEncoderTest#testSurfNearMinMin" />
+ <option name="compatibility:exclude-filter" value="CtsMediaEncoderTestCases android.media.encoder.cts.VideoEncoderTest#testSurf480p" />
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index 72ff5ce..1da1953 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -255,4 +255,7 @@
<option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testSetCameraDisabledLogged" />
<option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedProfileOwnerTest#testSetCameraDisabledLogged" />
+ <!-- b/182630972, b/214019488 -->
+ <option name="compatibility:exclude-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.PinnedStackTests#testEnterPipWithMinimalSize" />
+
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-meerkat.xml b/tools/cts-tradefed/res/config/cts-meerkat.xml
index 6bc6b30..31aed81 100644
--- a/tools/cts-tradefed/res/config/cts-meerkat.xml
+++ b/tools/cts-tradefed/res/config/cts-meerkat.xml
@@ -39,7 +39,7 @@
<!-- System Alert Window (SAW) -->
<option name="compatibility:include-filter" value="CtsSystemIntentTestCases"/>
<option name="compatibility:include-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.HideOverlayWindowsTest"/>
- <option name="compatibility:include-filter" value="CtsMediaTestCases android.media.cts.MediaProjectionTest"/>
+ <option name="compatibility:include-filter" value="CtsMediaMiscTestCases android.media.misc.cts.MediaProjectionTest"/>
<!-- Toasts -->
<option name="compatibility:include-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.ToastWindowTest"/>
diff --git a/tools/cts-tradefed/res/config/cts-on-aosp-exclude.xml b/tools/cts-tradefed/res/config/cts-on-aosp-exclude.xml
index d220e8f..bd4153b 100644
--- a/tools/cts-tradefed/res/config/cts-on-aosp-exclude.xml
+++ b/tools/cts-tradefed/res/config/cts-on-aosp-exclude.xml
@@ -61,10 +61,10 @@
<option name="compatibility:exclude-filter" value="CtsAppTestCases android.app.cts.ActivityKeyboardShortcutsTest#testRequestShowKeyboardShortcuts" />
<!-- b/161837932: Fix MediaPlayerTests that use "too small" resolution -->
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.MediaPlayerTest#testOnSubtitleDataListener" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.MediaPlayerTest#testChangeSubtitleTrack" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.MediaPlayerTest#testDeselectTrackForSubtitleTracks" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.MediaPlayerTest#testGetTrackInfoForVideoWithSubtitleTracks" />
+ <option name="compatibility:exclude-filter" value="CtsMediaPlayerTestCases android.media.player.cts.MediaPlayerTest#testOnSubtitleDataListener" />
+ <option name="compatibility:exclude-filter" value="CtsMediaPlayerTestCases android.media.player.cts.MediaPlayerTest#testChangeSubtitleTrack" />
+ <option name="compatibility:exclude-filter" value="CtsMediaPlayerTestCases android.media.player.cts.MediaPlayerTest#testDeselectTrackForSubtitleTracks" />
+ <option name="compatibility:exclude-filter" value="CtsMediaPlayerTestCases android.media.player.cts.MediaPlayerTest#testGetTrackInfoForVideoWithSubtitleTracks" />
<!-- b/152359655: ResumeOnReboot can't work on GSI -->
<option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.ResumeOnRebootHostTest" />
diff --git a/tools/cts-tradefed/res/config/cts-on-csi-cf.xml b/tools/cts-tradefed/res/config/cts-on-csi-cf.xml
index c810f2d..6d55fe2 100644
--- a/tools/cts-tradefed/res/config/cts-on-csi-cf.xml
+++ b/tools/cts-tradefed/res/config/cts-on-csi-cf.xml
@@ -41,8 +41,16 @@
<option name="compatibility:exclude-filter" value="CtsKeystoreTestCases" />
<option name="compatibility:exclude-filter" value="CtsMediaBitstreamsTestCases" />
<option name="compatibility:exclude-filter" value="CtsMediaStressTestCases" />
- <option name="compatibility:exclude-filter" value="CtsMediaDrmTestCases" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsMediaAudioTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsMediaCodecTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsMediaDecoderTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsMediaDrmFrameworkTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsMediaEncoderTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsMediaExtractorTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsMediaMiscTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsMediaMuxerTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsMediaPlayerTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsMediaRecorderTestCases" />
<option name="compatibility:exclude-filter" value="CtsMediaV2TestCases" />
<option name="compatibility:exclude-filter" value="CtsNativeHardwareTestCases" />
<option name="compatibility:exclude-filter" value="CtsOpenGLTestCases" />
diff --git a/tools/cts-tradefed/res/config/cts-on-csi-no-apks.xml b/tools/cts-tradefed/res/config/cts-on-csi-no-apks.xml
index a99c656..dc93565 100644
--- a/tools/cts-tradefed/res/config/cts-on-csi-no-apks.xml
+++ b/tools/cts-tradefed/res/config/cts-on-csi-no-apks.xml
@@ -159,8 +159,8 @@
<option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testManageStorage" />
<!-- No SystemUI -->
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.AudioPlaybackCaptureTest" />
- <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.MediaProjectionTest" />
+ <option name="compatibility:exclude-filter" value="CtsMediaAudioTestCases android.media.audio.cts.AudioPlaybackCaptureTest" />
+ <option name="compatibility:exclude-filter" value="CtsMediaMiscTestCases android.media.misc.cts.MediaProjectionTest" />
<option name="compatibility:exclude-filter" value="CtsPermission3TestCases android.permission3.cts.PermissionTest22#testCompatRevoked" />
<option name="compatibility:exclude-filter" value="CtsPermission3TestCases android.permission3.cts.PermissionTest23#testGranted" />
<option name="compatibility:exclude-filter" value="CtsPermission3TestCases android.permission3.cts.PermissionTest23#testRevokeAffectsWholeGroup" />
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java
index 673d93c..ced6aaf 100644
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java
@@ -30,13 +30,13 @@
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.testtype.InstrumentationTest;
import com.android.tradefed.util.AaptParser;
+import com.android.tradefed.util.FileUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.io.File;
-import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -69,20 +69,12 @@
fail(String.format("%s does not exists", testcases));
return;
}
- File[] listConfig = testcases.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- if (name.endsWith(".config")) {
- return true;
- }
- return false;
- }
- });
- assertTrue(listConfig.length > 0);
+ Set<File> listConfigs = FileUtil.findFilesObject(testcases, ".*\\.config");
+ assertTrue(listConfigs.size() > 0);
// We check all apk installed by all modules
Map<String, String> packageNames = new HashMap<>();
- for (File config : listConfig) {
+ for (File config : listConfigs) {
IConfiguration c = ConfigurationFactory.getInstance()
.createConfigurationFromArgs(new String[] {config.getAbsolutePath()});
// For each config, we check all the apk it's going to install
@@ -97,15 +89,17 @@
if (prep instanceof FilePusher && ((FilePusher) prep).shouldAppendBitness()) {
for (File f : ((PushFilePreparer) prep).getPushSpecs(null).values()) {
String path = f.getPath();
- if (!new File(testcases, path + "32").exists()
- || !new File(testcases, path + "64").exists()) {
+ File file32 = FileUtil.findFile(config.getParentFile(), path + "32");
+ File file64 = FileUtil.findFile(config.getParentFile(), path + "64");
+ if (file32 == null || file64 == null) {
// TODO: Enforce should abort on failure is True in CTS
if (((FilePusher) prep).shouldAbortOnFailure()) {
fail(
String.format(
- "File %s[32/64] wasn't found in testcases/ while "
- + "it's expected to be pushed as part of "
- + "%s",
+ "File %s[32/64] wasn't found in module "
+ + "dependencies while "
+ + "it's expected to be pushed as part"
+ + " of %s.",
path, config.getName()));
}
}
@@ -113,24 +107,27 @@
} else if (prep instanceof PushFilePreparer) {
for (File f : ((PushFilePreparer) prep).getPushSpecs(null).values()) {
String path = f.getPath();
- if (!new File(testcases, path).exists()) {
+ File toBePushed = FileUtil.findFile(config.getParentFile(), path);
+ if (toBePushed == null) {
// TODO: Enforce should abort on failure is True in CTS
if (((PushFilePreparer) prep).shouldAbortOnFailure()) {
fail(
String.format(
- "File %s wasn't found in testcases/ while it's "
- + "expected to be pushed as part of %s",
+ "File %s wasn't found in module dependencies "
+ + "while it's expected to be pushed "
+ + "as part of %s.",
path, config.getName()));
}
}
}
}
}
-
+
+ // All apks need to be in the config dir or sub-dir
for (File apk : apkNames) {
String apkName = apk.getName();
- File apkFile = new File(testcases, apkName);
- if (!apkFile.exists()) {
+ File apkFile = FileUtil.findFile(config.getParentFile(), apkName);
+ if (apkFile == null || !apkFile.exists()) {
fail(String.format("Module %s is trying to install %s which does not "
+ "exists in testcases/", config.getName(), apkFile));
}
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java
index 0a392fd..7b6e0d1 100644
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java
@@ -40,6 +40,7 @@
import com.android.tradefed.testtype.ITestFilterReceiver;
import com.android.tradefed.testtype.suite.ITestSuite;
import com.android.tradefed.testtype.suite.params.ModuleParameters;
+import com.android.tradefed.util.FileUtil;
import org.junit.Assert;
import org.junit.Test;
@@ -47,7 +48,6 @@
import org.junit.runners.JUnit4;
import java.io.File;
-import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -193,16 +193,8 @@
fail(String.format("%s does not exists", testcases));
return;
}
- File[] listConfig = testcases.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- if (name.endsWith(".config")) {
- return true;
- }
- return false;
- }
- });
- assertTrue(listConfig.length > 0);
+ Set<File> listConfigs = FileUtil.findFilesObject(testcases, ".*\\.config");
+ assertTrue(listConfigs.size() > 0);
// Create a FolderBuildInfo to similate the CompatibilityBuildProvider
FolderBuildInfo stubFolder = new FolderBuildInfo("-1", "-1");
stubFolder.setRootDir(new File(ctsRoot));
@@ -213,7 +205,7 @@
List<String> missingMandatoryParameters = new ArrayList<>();
// We expect to be able to load every single config in testcases/
- for (File config : listConfig) {
+ for (File config : listConfigs) {
IConfiguration c = ConfigurationFactory.getInstance()
.createConfigurationFromArgs(new String[] {config.getAbsolutePath()});
if (c.getDeviceConfig().size() > 2) {
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
index 97ee339..94a65bf 100644
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
@@ -29,18 +29,17 @@
import org.junit.runners.JUnit4;
import java.io.File;
-import java.io.FilenameFilter;
import java.io.IOException;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.util.Set;
+import java.util.stream.Collectors;
/**
* Tests to validate that the build is containing usable test artifact.
@@ -83,23 +82,31 @@
* and embed native libraries.
*/
APK_EXCEPTIONS.add("CtsExtractNativeLibsAppFalse64");
+
+ /**
+ * These apks are prebuilts needed for some tests
+ */
+ APK_EXCEPTIONS.add("CtsApkVerityTestAppPrebuilt");
+ APK_EXCEPTIONS.add("CtsApkVerityTestApp2Prebuilt");
+
+ /**
+ * Data apk used by SimpleperfTestCases
+ */
+ APK_EXCEPTIONS.add("base");
}
private static final Set<String> BINARY_EXCEPTIONS = new HashSet<>();
static {
/**
- * Tests that build for either 32 bit or 64 bit only.
- */
- BINARY_EXCEPTIONS.add("CVE-2017-0684" + "32");
- BINARY_EXCEPTIONS.add("CVE_2019_2135" + "64");
- BINARY_EXCEPTIONS.add("CVE-2020-0037" + "64");
- BINARY_EXCEPTIONS.add("CVE-2020-0038" + "64");
- BINARY_EXCEPTIONS.add("CVE-2020-0039" + "64");
-
- /**
- * This binary is a host side helper, so we do not need to check it.
+ * These binaries are host side helpers, so we do not need to check them.
*/
BINARY_EXCEPTIONS.add("sepolicy-analyze");
+ BINARY_EXCEPTIONS.add("avbtool");
+ BINARY_EXCEPTIONS.add("img2simg");
+ BINARY_EXCEPTIONS.add("lpmake");
+ BINARY_EXCEPTIONS.add("lpunpack");
+ BINARY_EXCEPTIONS.add("sign_virt_apex");
+ BINARY_EXCEPTIONS.add("simg2img");
}
private static final String BINARY_EXCEPTIONS_REGEX [] = {
@@ -126,26 +133,22 @@
* the two abis required and the second one will fail.
*/
@Test
- public void testApksAbis() {
+ public void testApksAbis() throws IOException {
String ctsRoot = System.getProperty("CTS_ROOT");
File testcases = new File(ctsRoot, "/android-cts/testcases/");
if (!testcases.exists()) {
fail(String.format("%s does not exists", testcases));
return;
}
- File[] listApks = testcases.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- for (String apk : APK_EXCEPTIONS) {
- if (name.startsWith(apk)) {
- return false;
+ Set<File> listApks = FileUtil.findFilesObject(testcases, ".*\\.apk");
+ listApks.removeIf(
+ a -> {for (String apk : APK_EXCEPTIONS) {
+ if (a.getName().startsWith(apk)) {
+ return true;
}
}
-
- return name.endsWith(".apk");
- }
- });
- assertTrue(listApks.length > 0);
+ return false;});
+ assertTrue(listApks.size() > 0);
int maxAbi = 0;
Map<String, Integer> apkToAbi = new HashMap<>();
@@ -205,38 +208,37 @@
* If there is only one bitness, then we check that it's the right one.
*/
@Test
- public void testBinariesAbis() {
+ public void testBinariesAbis() throws IOException {
String ctsRoot = System.getProperty("CTS_ROOT");
File testcases = new File(ctsRoot, "/android-cts/testcases/");
if (!testcases.exists()) {
fail(String.format("%s does not exist", testcases));
return;
}
- String[] listBinaries = testcases.list(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
+ Set<File> listBinaries = FileUtil.findFilesObject(testcases, ".*");
+ listBinaries.removeIf(f -> {
+ String name = f.getName();
if (name.contains(".")) {
- return false;
+ return true;
}
if (BINARY_EXCEPTIONS.contains(name)) {
- return false;
+ return true;
}
for (String suffixException : BINARY_SUFFIX_EXCEPTIONS) {
if (name.endsWith(suffixException)) {
- return false;
+ return true;
}
}
- File file = new File(dir, name);
- if (file.isDirectory()) {
- return false;
+ if (f.isDirectory()) {
+ return true;
}
- if (!file.canExecute()) {
- return false;
+ if (!f.canExecute()) {
+ return true;
}
try {
// Ignore python binaries
- if (FileUtil.readStringFromFile(file).startsWith("#!/usr/bin/env python")) {
- return false;
+ if (FileUtil.readStringFromFile(f).startsWith("#!/usr/bin/env python")) {
+ return true;
}
} catch (IOException e) {
throw new RuntimeException(e);
@@ -244,14 +246,13 @@
for(String pattern: BINARY_EXCEPTIONS_REGEX) {
Matcher matcher = Pattern.compile(pattern).matcher(name);
if (matcher.matches()) {
- return false;
+ return true;
}
}
- return true;
- }
+ return false;
});
- assertTrue(listBinaries.length > 0);
- List<String> orderedList = Arrays.asList(listBinaries);
+ assertTrue(listBinaries.size() > 0);
+ List<String> orderedList = listBinaries.stream().map(f->f.getName()).collect(Collectors.toList());
// we sort to have binary starting with same name, next to each other. The last two
// characters of their name with be the bitness (32 or 64).
Collections.sort(orderedList);